using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SkiaSharp;
using System.IO;
using CPF.Drawing;

namespace CPF.Skia
{
    public class SkiaImage : IImageImpl
    {
        int frameCount;
        Stream stream;
        //SKBitmap[] bitmaps;
        SKCodec codec;
        SKBitmap bitmap;

        public SkiaImage(string path)
        {
            stream = File.OpenRead(path);
            //#if Net4
            using (SKData data = SKData.Create(path))
            {
                codec = SKCodec.Create(data);
            }
            //#else
            //            codec = SKCodec.Create(stream);
            //#endif
            frameCount = Math.Max(1, codec.FrameCount);
            bitmap = SKBitmap.Decode(codec);
            Codec();
        }

        public SkiaImage(Stream stream)
        {
            this.stream = new MemoryStream();
            stream.CopyTo(this.stream);
            this.stream.Position = 0;
            //#if Net4
            using (SKData data = SKData.Create(this.stream))
            {
                codec = SKCodec.Create(data);
            }
            //#else
            //            codec = SKCodec.Create(this.stream);
            //#endif
            if (codec == null)
            {
                this.stream.Position = 0;
                codec = SKCodec.Create(this.stream, out var result);
                if (codec == null)
                {
                    throw new Exception("图片解码失败" + result);
                }
            }
            frameCount = Math.Max(1, codec.FrameCount);
            bitmap = SKBitmap.Decode(codec);
            Codec();
        }

        int[] durations;

        public int[] FrameDelay { get { return durations; } }

        void Codec()
        {
            if (frameCount > 1)
            {
                durations = new int[frameCount];
                for (int frame = 0; frame < frameCount; frame++)
                {
                    // From the FrameInfo collection, get the duration of each frame
                    durations[frame] = codec.FrameInfo[frame].Duration;
                }
                Duration = 0;
                // Sum up the total duration
                for (int frame = 0; frame < durations.Length; frame++)
                {
                    Duration += durations[frame];
                }
            }
            if (bitmap == null)
            {
                throw new Exception("图片解析失败");
            }
        }

        //void Codec(SKCodec codec)
        //{
        //    // Get frame count and allocate bitmaps
        //    frameCount = codec.FrameCount;
        //    if (frameCount == 0)
        //    {
        //        frameCount = 1;
        //        bitmaps = new SKBitmap[frameCount];
        //        bitmaps[0] = SKBitmap.Decode(codec);
        //    }
        //    else
        //    {
        //        bitmaps = new SKBitmap[frameCount];
        //        var durations = new int[frameCount];
        //        //var accumulatedDurations = new int[frameCount];

        //        // Note: There's also a RepetitionCount property of SKCodec not used here

        //        // Loop through the frames
        //        for (int frame = 0; frame < frameCount; frame++)
        //        {
        //            // From the FrameInfo collection, get the duration of each frame
        //            durations[frame] = codec.FrameInfo[frame].Duration;

        //            // Create a full-color bitmap for each frame
        //            SKImageInfo imageInfo = new SKImageInfo(codec.Info.Width, codec.Info.Height);
        //            bitmaps[frame] = new SKBitmap(imageInfo);

        //            // Get the address of the pixels in that bitmap
        //            IntPtr pointer = bitmaps[frame].GetPixels();

        //            // Create an SKCodecOptions value to specify the frame
        //            SKCodecOptions codecOptions = new SKCodecOptions(frame);

        //            // Copy pixels from the frame into the bitmap
        //            codec.GetPixels(imageInfo, pointer, codecOptions);
        //        }
        //        Duration = 0;
        //        // Sum up the total duration
        //        for (int frame = 0; frame < durations.Length; frame++)
        //        {
        //            Duration += durations[frame];
        //        }

        //        // Calculate the accumulated durations
        //        //for (int frame = 0; frame < durations.Length; frame++)
        //        //{
        //        //    accumulatedDurations[frame] = durations[frame] +
        //        //        (frame == 0 ? 0 : accumulatedDurations[frame - 1]);
        //        //}
        //    }
        //}

        public SKBitmap Image
        {
            get
            {
                if (needUpdate)
                {
                    needUpdate = false;

                    IntPtr pointer = bitmap.GetPixels();

                    // Create an SKCodecOptions value to specify the frame
#if Net4
                    SKCodecOptions codecOptions = new SKCodecOptions((int)index, true);
#else
                    SKCodecOptions codecOptions = new SKCodecOptions((int)index, (int)index - 1);
#endif
                    SKImageInfo imageInfo = new SKImageInfo(codec.Info.Width, codec.Info.Height);
                    // Copy pixels from the frame into the bitmap
                    codec.GetPixels(imageInfo, pointer, codecOptions);
                    bitmap.NotifyPixelsChanged();
                }
                return bitmap;
            }
        }

        public int Width
        {
            get
            {
                return Image.Width;
            }
        }

        public int Height
        {
            get
            {
                return Image.Height;
            }
        }

        public uint FrameCount
        {
            get
            {
                return (uint)frameCount;
            }
        }

        bool needUpdate;
        uint index;
        public uint Index
        {
            get { return index; }
            set
            {
                if (index != value)
                {
                    index = value;
                    needUpdate = true;
                }
            }
        }
        ~SkiaImage()
        {
            Dispose();
        }
        public int Duration { get; set; }

        public void Dispose()
        {
            if (bitmap != null)
            {
                bitmap.Dispose();
                bitmap = null;
            }
            if (codec != null)
            {
                codec.Dispose();
                codec = null;
            }
            if (stream != null)
            {
                stream.Dispose();
                stream = null;
            }
            GC.SuppressFinalize(this);
        }

        public Stream SaveToStream(ImageFormat format)
        {
            var f = SKEncodedImageFormat.Jpeg;
            switch (format)
            {
                case ImageFormat.Bmp:
                    f = SKEncodedImageFormat.Bmp;
                    break;
                case ImageFormat.Gif:
                    f = SKEncodedImageFormat.Gif;
                    break;
                case ImageFormat.Jpeg:
                    f = SKEncodedImageFormat.Jpeg;
                    break;
                case ImageFormat.Png:
                    f = SKEncodedImageFormat.Png;
                    break;
                default:
                    break;
            }
            using (var image = SKImage.FromBitmap(Image))
            {
                var data = image.Encode(f, 100);
                var d = data.AsStream();
                return d;
            }
        }
        public void SaveToStream(ImageFormat format, Stream m)
        {
            var f = SKEncodedImageFormat.Jpeg;
            switch (format)
            {
                case ImageFormat.Bmp:
                    f = SKEncodedImageFormat.Bmp;
                    break;
                case ImageFormat.Gif:
                    f = SKEncodedImageFormat.Gif;
                    break;
                case ImageFormat.Jpeg:
                    f = SKEncodedImageFormat.Jpeg;
                    break;
                case ImageFormat.Png:
                    f = SKEncodedImageFormat.Png;
                    break;
                default:
                    break;
            }
            using (var image = SKImage.FromBitmap(Image))
            {
                var data = image.Encode(f, 100);
                //var d = data.AsStream();
                //return d;
                data.SaveTo(m);
                data.Dispose();
            }
        }

        public object Clone()
        {
            stream.Position = 0;
            return new SkiaImage(stream);
        }
    }
}