using System;
using HandyControl.Controls;
using HandyControl.Tools;

namespace HandyControl.Data;

public class GifImageInfo
{
    private const int PropertyTagFrameDelay = 0x5100;

    private int _frame;

    private readonly int[] _frameDelay;

    public int FrameCount { get; }

    internal GifImage Image { get; }

    public bool Animated { get; }

    public EventHandler FrameChangedHandler { get; set; }

    internal int FrameTimer { get; set; }

    public bool FrameDirty { get; private set; }

    public int Frame
    {
        get => _frame;
        set
        {
            if (_frame != value)
            {
                if (value < 0 || value >= FrameCount)
                {
                    throw new ArgumentException("InvalidFrame");
                }

                if (Animated)
                {
                    _frame = value;
                    FrameDirty = true;

                    OnFrameChanged(EventArgs.Empty);
                }
            }
        }
    }

    public GifImageInfo(GifImage image)
    {
        Image = image;
        Animated = ImageAnimator.CanAnimate(image);

        if (Animated)
        {
            FrameCount = image.GetFrameCount(GifFrameDimension.Time);

            var frameDelayItem = image.GetPropertyItem(PropertyTagFrameDelay);

            // If the image does not have a frame delay, we just return 0.                                     
            //
            if (frameDelayItem != null)
            {
                // Convert the frame delay from byte[] to int
                //
                var values = frameDelayItem.Value;
                _frameDelay = new int[FrameCount];
                for (var i = 0; i < FrameCount; ++i)
                {
                    _frameDelay[i] = values[i * 4] + 256 * values[i * 4 + 1] + 256 * 256 * values[i * 4 + 2] + 256 * 256 * 256 * values[i * 4 + 3];
                }
            }
        }
        else
        {
            FrameCount = 1;
        }

        _frameDelay ??= new int[FrameCount];
    }

    public int FrameDelay(int frame) => _frameDelay[frame];

    internal void UpdateFrame()
    {
        if (FrameDirty)
        {
            Image.SelectActiveFrame(GifFrameDimension.Time, Frame);
            FrameDirty = false;
        }
    }

    protected void OnFrameChanged(EventArgs e) => FrameChangedHandler?.Invoke(Image, e);
}
