using System;

namespace Quik.Media.Color
{
    public unsafe struct LockIO
    {
        public QImageLock Lock { get; }
        public int Width => Lock.Width;
        public int Height => Lock.Height;
        public int Depth => Depth;
        public QImageFormat Format => Lock.Format;

        public LockIO(QImageLock imageLock)
        {
            if (!imageLock.Format.IsU8())
                throw new Exception("Can only read/write U8 format images");

            Lock = imageLock;
        }

        public QColor this[int index]
        {
            get
            {
                int chan = Format.Channels();
                byte *ptr = (byte*)Lock.ImagePtr + chan * index;

                switch (Format)
                {
                default:
                case QImageFormat.RedU8:    return new QColor(ptr[0], 0, 0, 255);
                case QImageFormat.AlphaU8:  return new QColor(0, 0, 0, ptr[0]);
                case QImageFormat.RaU8:     return new QColor(ptr[0], 0, 0, ptr[1]);
                case QImageFormat.RgbU8:    return new QColor(ptr[0], ptr[1], ptr[2], 255);
                case QImageFormat.RgbaU8:   return new QColor(ptr[0], ptr[1], ptr[2], ptr[3]);
                }
            }

            set
            {
                int chan = Format.Channels();
                byte *ptr = (byte*)Lock.ImagePtr + chan * index;

                switch (Format)
                {
                default:
                case QImageFormat.RedU8:
                    ptr[0] = value.R;
                    break;
                case QImageFormat.AlphaU8:
                    ptr[0] = value.A;
                    break;
                case QImageFormat.RaU8:
                    ptr[0] = value.R;
                    ptr[1] = value.A;
                    break;
                case QImageFormat.RgbU8:
                    ptr[0] = value.R;
                    ptr[1] = value.G;
                    ptr[2] = value.B;
                    break;
                case QImageFormat.RgbaU8:
                    ptr[0] = value.R;
                    ptr[1] = value.G;
                    ptr[2] = value.B;
                    ptr[3] = value.A;
                    break;
                }
            }
        }
        public QColor this[int x, int y, int z = 0]
        {
            get => this[x + y * Width + z * Width * Height];
            set => this[x + y * Width + z * Width * Height] = value;
        }
    }

    public unsafe struct LockIOF
    {
        public QImageLock Lock { get; }
        public int Width => Lock.Width;
        public int Height => Lock.Height;
        public int Depth => Depth;
        public QImageFormat Format => Lock.Format;

        public LockIOF(QImageLock imageLock)
        {
            if (!imageLock.Format.IsFloat())
                throw new Exception("Can only read/write U8 format images");

            Lock = imageLock;
        }

        public QColorF this[int index]
        {
            get
            {
                int chan = Format.Channels();
                float *ptr = (float*)Lock.ImagePtr + chan * index;

                switch (Format)
                {
                default:
                case QImageFormat.RedU8:    return new QColorF(ptr[0], 0, 0, 255);
                case QImageFormat.AlphaU8:  return new QColorF(0, 0, 0, ptr[0]);
                case QImageFormat.RaU8:     return new QColorF(ptr[0], 0, 0, ptr[1]);
                case QImageFormat.RgbU8:    return new QColorF(ptr[0], ptr[1], ptr[2], 255);
                case QImageFormat.RgbaU8:   return new QColorF(ptr[0], ptr[1], ptr[2], ptr[3]);
                }
            }

            set
            {
                int chan = Format.Channels();
                float *ptr = (float*)Lock.ImagePtr + chan * index;

                switch (Format)
                {
                default:
                case QImageFormat.RedU8:
                    ptr[0] = value.R;
                    break;
                case QImageFormat.AlphaU8:
                    ptr[0] = value.A;
                    break;
                case QImageFormat.RaU8:
                    ptr[0] = value.R;
                    ptr[1] = value.A;
                    break;
                case QImageFormat.RgbU8:
                    ptr[0] = value.R;
                    ptr[1] = value.G;
                    ptr[2] = value.B;
                    break;
                case QImageFormat.RgbaU8:
                    ptr[0] = value.R;
                    ptr[1] = value.G;
                    ptr[2] = value.B;
                    ptr[3] = value.A;
                    break;
                }
            }
        }
        public QColorF this[int x, int y, int z = 0]
        {
            get => this[x + y * Width + z * Width * Height];
            set => this[x + y * Width + z * Width * Height] = value;
        }
    }
}