﻿using JLGames.RocketDriver.CSharp.Mathx;
using UnityEngine;

namespace JLGames.RocketDriver.Actions.Graphicsx
{
    public sealed class TextureProxy<T>
    {
        /// <summary>
        /// Custom dataset
        /// 自定义数据集
        /// </summary>
        private readonly Array2D<T> m_DataMap = new Array2D<T>();

        /// <summary>
        /// Bound
        /// 范围
        /// </summary>
        public Bounds2Int Bound => m_DataMap.Bound;

        /// <summary>
        /// Size width
        /// 宽度
        /// </summary>
        public int Width => Bound.Size.X;

        /// <summary>
        /// Size height
        /// 高度
        /// </summary>
        public int Height => Bound.Size.Y;

        /// <summary>
        /// Initialize the dataset
        /// 初始化数据集
        /// </summary>
        /// <param name="texture"></param>
        /// <param name="cs"></param>
        /// <param name="rule"></param>
        public void SetTexture(Texture2D texture, Texture2DUtil.CoordinateSystem cs,
            GraphicsDelegate.ColorTo<T> rule)
        {
            var width = texture.width;
            var data = Texture2DUtil.PixelsToTs(texture, cs, rule);
            m_DataMap.SetData(data, width);
        }

        /// <summary>
        /// Initialize the dataset
        /// 初始化数据集
        /// </summary>
        /// <param name="texture"></param>
        /// <param name="cs"></param>
        /// <param name="rule"></param>
        public void SetTexture(Texture2D texture, Texture2DUtil.CoordinateSystem cs,
            GraphicsDelegate.Color32To<T> rule)
        {
            var width = texture.width;
            var data = Texture2DUtil.Pixels32ToTs(texture, cs, rule);
            m_DataMap.SetData(data, width);
        }

        public T[][] GetDataAtBound(Bounds2Int bound)
        {
            return m_DataMap.GetDataAtBound(bound);
        }

        public T GetValue(int x, int y)
        {
            return m_DataMap.GetValue(x, y);
        }

        public bool CheckValue(int x, int y, T value)
        {
            return m_DataMap.CheckValue(x, y, value);
        }

        public T GetValueInCycle(int cycleX, int cycleY)
        {
            return m_DataMap.GetValue(ToCycleX(cycleX), ToCycleY(cycleY));
        }

        public bool CheckValueInCycle(int cycleX, int cycleY, T value)
        {
            return m_DataMap.CheckValue(ToCycleX(cycleX), ToCycleY(cycleY), value);
        }

        public int ToCycleX(int cycleX)
        {
            if (Bound.ContainsX(cycleX))
            {
                return cycleX;
            }

            var index = Point1Int.ToAreaPoint1(cycleX, (uint) Width);
            return index.Remainder;
        }

        public int ToCycleY(int cycleY)
        {
            if (Bound.ContainsY(cycleY))
            {
                return cycleY;
            }

            var index = Point1Int.ToAreaPoint1(cycleY, (uint) Height);
            return index.Remainder;
        }

        public override string ToString()
        {
            return m_DataMap.ToPrintString(false);
        }
    }
}