﻿using UnityEngine;

namespace JLGames.RocketDriver.Actions.Graphicsx
{
    public static class Texture2DUtil
    {
        /// <summary>
        /// Resize with scale
        /// 按比例缩放
        /// </summary>
        /// <param name="source"></param>
        /// <param name="scale"></param>
        /// <returns></returns>
        public static Texture2D Resize(Texture2D source, float scale)
        {
            var newWidth = (int) (source.width * scale);
            var newHeight = (int) (source.height * scale);
            return Resize1(source, newWidth, newHeight);
        }

        /// <summary>
        /// Resize to fixed size
        /// 缩放到固定尺寸
        /// </summary>
        /// <param name="source">源始图像</param>
        /// <param name="width"></param>
        /// <param name="height"></param>
        /// <returns></returns>
        public static Texture2D Resize(Texture2D source, int width, int height)
        {
            return Resize1(source, width, height);
        }

        private static Texture2D Resize1(Texture2D source, int width, int height)
        {
            var oldFilterMode = source.filterMode;

            source.filterMode = FilterMode.Point;
            var renderTemp = RenderTexture.GetTemporary(width, height);
            RenderTexture.active = renderTemp;
            Graphics.Blit(source, renderTemp);

            var rs = new Texture2D(width, height);
            rs.ReadPixels(new Rect(0, 0, width, height), 0, 0);
            rs.Apply();
            RenderTexture.active = null;

            source.filterMode = oldFilterMode;
            return rs;
        }

        private static Texture2D Resize2(Texture2D source, int width, int height)
        {
            var filterMode = source.filterMode;
            var factorWidth = (float) source.width / width;
            var factorHeight = (float) source.height / height;
            var rs = new Texture2D(width, height, source.format, false) {filterMode = filterMode};
            for (var h = 0; h < rs.height; h++)
            {
                for (var w = 0; w < rs.width; w++)
                {
                    var color = source.GetPixel((int) (w * factorWidth), (int) (h * factorHeight));
                    rs.SetPixel(w, h, color);
                }
            }

            rs.Apply();
            return rs;
        }

        /// <summary>
        /// Generate solid-color Texture2D
        /// 生成纯色的Texture2D
        /// </summary>
        /// <param name="width"></param>
        /// <param name="height"></param>
        /// <param name="col"></param>
        /// <param name="keep"></param>
        /// <returns></returns>
        public static Texture2D GenColorTexture(int width, int height, Color col, bool keep = false)
        {
            //remove color variation for versions under 2017
            var pix = new Color[width * height];
            for (var i = 0; i < pix.Length; i++)
            {
#if UNITY_2018_1_OR_NEWER
                pix[i] = QualitySettings.activeColorSpace == ColorSpace.Linear ? col.linear : col;
#else
                pix[i] = col;
#endif
            }

            var result = new Texture2D(width, height, TextureFormat.RGBA32, false, true);
            result.SetPixels(pix);
            result.Apply();

            if (keep)
                result.hideFlags = HideFlags.HideAndDontSave;
            return result;
        }

        /// <summary>
        /// Texture2D that generates gradients
        /// 生成渐变的Texture2D
        /// Horizontal direction
        /// 水平方向
        /// </summary>
        /// <param name="width"></param>
        /// <param name="startColor"></param>
        /// <param name="endColor"></param>
        /// <param name="endGradientPixel"></param>
        /// <param name="keep"></param>
        /// <returns></returns>
        public static Texture2D GenGradientColorTextureHorizontal(int width, Color startColor, Color endColor,
            int endGradientPixel, bool keep)
        {
            var pix = new Color[width];
#if UNITY_2018_1_OR_NEWER
            startColor = QualitySettings.activeColorSpace == ColorSpace.Linear ? startColor.linear : startColor;
            endColor = QualitySettings.activeColorSpace == ColorSpace.Linear ? endColor.linear : endColor;
#endif
            for (var i = 0; i < pix.Length; i++)
            {
                if (i < endGradientPixel)
                {
                    pix[i] = Color.Lerp(startColor, endColor, (float) i / endGradientPixel);
                }
                else
                {
                    pix[i] = endColor;
                }
            }

            var result = new Texture2D(width, 1, TextureFormat.RGBA32, false, true);
            result.SetPixels(pix);
            result.Apply();
            result.hideFlags = HideFlags.HideAndDontSave;
            return result;
        }

        /// <summary>
        /// Texture2D that generates gradients
        /// 生成渐变的Texture2D
        /// Vertical direction
        /// 垂直方向
        /// </summary>
        /// <param name="height"></param>
        /// <param name="startColor"></param>
        /// <param name="endColor"></param>
        /// <param name="endGradientPixel"></param>
        /// <param name="keep"></param>
        /// <returns></returns>
        public static Texture2D GenGradientColorTextureVertical(int height, Color startColor, Color endColor,
            int endGradientPixel, bool keep)
        {
            var pix = new Color[height];
#if UNITY_2018_1_OR_NEWER
            startColor = QualitySettings.activeColorSpace == ColorSpace.Linear ? startColor.linear : startColor;
            endColor = QualitySettings.activeColorSpace == ColorSpace.Linear ? endColor.linear : endColor;
#endif
            for (var i = 0; i < pix.Length; i++)
            {
                if (i < endGradientPixel)
                {
                    pix[i] = Color.Lerp(startColor, endColor, (float) i / endGradientPixel);
                }
                else
                {
                    pix[i] = endColor;
                }
            }

            var result = new Texture2D(1, height, TextureFormat.RGBA32, false, true);
            result.SetPixels(pix);
            result.Apply();
            result.hideFlags = HideFlags.HideAndDontSave;
            return result;
        }

        //--------------------------------------------------

        public enum CoordinateSystem
        {
            LeftUp,
            LeftDown,
            RightUp,
            RightDown
        }

        /// <summary>
        /// The custom conversion image pixel value to Generics
        /// 自定义换算图像像素值为T
        /// </summary>
        /// <param name="texture2D">左下角坐标系</param>
        /// <param name="cs"></param>
        /// <param name="rule"></param>
        /// <returns></returns>
        public static T[] PixelsToTs<T>(Texture2D texture2D, CoordinateSystem cs, GraphicsDelegate.ColorTo<T> rule)
        {
            if (null == texture2D)
            {
                return null;
            }

            var colors = texture2D.GetPixels();
            if (null == colors)
            {
                return null;
            }

            var ln = colors.Length;
            var width = texture2D.width;
            var rs = new T[ln];

            for (var index = 0; index < ln; index++)
            {
                var index2 = LeftDownToOther(ln, width, index, cs);
                rs[index2] = rule.Invoke(colors[index]);
            }

            return rs;
        }

        /// <summary>
        /// Custom conversion image pixel value to int value
        /// 自定义换算图像像素值为int
        /// </summary>
        /// <param name="texture2D">左下角坐标系</param>
        /// <param name="cs"></param>
        /// <param name="rule"></param>
        /// <returns></returns>
        public static int[] PixelsToInts(Texture2D texture2D, CoordinateSystem cs, GraphicsDelegate.ColorToInt rule)
        {
            if (null == texture2D)
            {
                return null;
            }

            var colors = texture2D.GetPixels();
            if (null == colors)
            {
                return null;
            }

            var ln = colors.Length;
            var width = texture2D.width;
            var rs = new int[ln];

            for (var index = 0; index < ln; index++)
            {
                var index2 = LeftDownToOther(ln, width, index, cs);
                rs[index2] = rule.Invoke(colors[index]);
            }

            return rs;
        }

        /// <summary>
        /// The custom conversion image pixel value to Generics
        /// 自定义换算图像像素值为T
        /// </summary>
        /// <param name="texture2D">左下角坐标系</param>
        /// <param name="cs">坐标系</param>
        /// <param name="rule">转换规则</param>
        /// <returns></returns>
        public static T[] Pixels32ToTs<T>(Texture2D texture2D, CoordinateSystem cs,
            GraphicsDelegate.Color32To<T> rule)
        {
            if (null == texture2D)
            {
                return null;
            }

            var colors = texture2D.GetPixels32();
            if (null == colors)
            {
                return null;
            }

            var ln = colors.Length;
            var width = texture2D.width;
            var rs = new T[ln];

            for (var index = 0; index < ln; index++)
            {
                var index2 = LeftDownToOther(ln, width, index, cs);
                rs[index2] = rule.Invoke(colors[index]);
            }

            return rs;
        }

        /// <summary>
        /// Custom conversion image pixel value to int value
        /// 自定义换算图像像素值为int
        /// </summary>
        /// <param name="texture2D">左下角坐标系</param>
        /// <param name="cs">坐标系</param>
        /// <param name="rule">转换规则</param>
        /// <returns></returns>
        public static int[] Pixels32ToInts(Texture2D texture2D, CoordinateSystem cs, GraphicsDelegate.Color32ToInt rule)
        {
            if (null == texture2D)
            {
                return null;
            }

            var colors = texture2D.GetPixels32();
            if (null == colors)
            {
                return null;
            }

            var ln = colors.Length;
            var width = texture2D.width;
            var rs = new int[ln];

            for (var index = 0; index < ln; index++)
            {
                var index2 = LeftDownToOther(ln, width, index, cs);
                rs[index2] = rule.Invoke(colors[index]);
            }

            return rs;
        }

        private static int LeftDownToOther(int total, int width, int current, CoordinateSystem cs)
        {
            switch (cs)
            {
                case CoordinateSystem.RightUp:
                    return total - current;
                case CoordinateSystem.LeftDown:
                    return current;
            }

            var allArea = total / width;
            var local = current % width;
            var area = current / width;
            var leftUp = (allArea - area - 1) * width + local;
            switch (cs)
            {
                case CoordinateSystem.LeftUp:
                    return leftUp;
                case CoordinateSystem.RightDown:
                    return total - leftUp;
            }

            return current;
        }
    }
}