using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEngine;
using UnityEditor;

namespace TweenAnimation
{
    [CustomEditor(typeof(TweenAnimation), false)]
    public partial class TweenAnimationInspector : Editor
    {
        TweenModuleGUIStyles styles
        {
            get
            {
                return TweenModuleGUIStyles.Get();
            }
        }

        TweenModuleUI ui
        {
            get
            {
                return TweenModuleUI.Get();
            }
        }

        float value = 20;

        TweenAnimation animation;
        bool m_ShowAnimationTab = true;

        static Dictionary<string, Type> s_TweenModuleClasses;
        static string[] s_TweenModuleClassNames;
        static Dictionary<string, MethodInfo> s_TweenModuleGUI;

        public void OnEnable()
        {
            m_ShowAnimationTab = true;
            s_TweenModuleGUI = new Dictionary<string, MethodInfo>();
        }
        
        public override void OnInspectorGUI()
        {
            animation = target as TweenAnimation;
            if (animation == null)
                return;

            EditorGUILayout.Space();

            AnimationTab();
            AddNewModule();
            AnimationModules();

            EditorGUILayout.Space();
        }

        void AnimationTab()
        {
            Rect rect = ui.GetControlRect(40);

            Rect headerRect = rect;
            headerRect.x -= 2;
            headerRect.width += 8;
            if (GUI.Button(headerRect, "", styles.headerBg))
            {
                m_ShowAnimationTab = !m_ShowAnimationTab;
            }

            GUI.Label(new Rect(rect.x + 10, rect.y + 3, 100, 20), "Tween Animation", styles.headerTitle);
            Vector2 size = styles.text.CalcSize(new GUIContent(animation.description));
            GUI.Label(new Rect(rect.x + rect.width - size.x - 10, rect.y + 3, 100, 20), animation.description, styles.text);

            if (m_ShowAnimationTab)
            {
                animation.description = ui.GUIText("Description", animation.description);
                // 播放风格
                animation.playbackStyle = (TweenAnimation.PlaybackStyle) ui.GUIEnum("Playback Style", animation.playbackStyle);

                if(animation.playbackStyle != TweenAnimation.PlaybackStyle.Once)
                {
                    // 播放次数限制
                    string fmt = animation.playbackLimit <= 0 ? "Unlimited" : "";
                    float limit = ui.GUIFloat("Playback Limit", animation.playbackLimit, fmt);
                    limit = Mathf.Clamp(limit, 0, Int32.MaxValue);
                    animation.playbackLimit = animation.playbackLimit > limit ? (int)Mathf.Floor(limit) : (int)Mathf.Ceil(limit);
                }

                // 时间间隔
                float duration = ui.GUIFloat("Duration", animation.duration, "f2");
                animation.duration = Mathf.Clamp(duration, 0, float.MaxValue);

                // 事件触发方向
                animation.eventTriggeredDirection = (TweenAnimation.EventTriggeredDirection)ui.GUIEnumMask("Event Direction", animation.eventTriggeredDirection);
            }
            DrawBgWire(rect, (m_ShowAnimationTab ? 4 : -2));
            if(!m_ShowAnimationTab)
                GUILayout.Space(-4);
            else
                GUILayout.Space(2);
        }

        void AddNewModule()
        {
            Rect rect = ui.GetControlRect(20);

            Rect labelRect = rect;
            labelRect.y += 2;
            GUI.Label(labelRect, "Modules ", styles.text);

            rect.x = rect.x + rect.width - 15;
            rect.width = 20;
            rect.height = 20;
            //if (GUI.Button(rect, "", styles.plus))
            {
                if(s_TweenModuleClasses == null)
                {
                    s_TweenModuleClasses = new Dictionary<string, Type>();
                    // 获得TweenModule的派生类
                    var classes = Assembly
                       .GetAssembly(typeof(TweenModule))
                       .GetTypes()
                       .Where(t => t.IsSubclassOf(typeof(TweenModule)));
                    foreach(var itor in classes)
                    {
                        string name = itor.Name;
                        Type type = itor;
                        s_TweenModuleClasses.Add(name, type);
                    }
                    s_TweenModuleClassNames = null;
                }
                if(s_TweenModuleClassNames == null)
                {
                    s_TweenModuleClassNames = new string[s_TweenModuleClasses.Count];
                    int i = 0;
                    var itor = s_TweenModuleClasses.GetEnumerator();
                    while(itor.MoveNext())
                    {
                        s_TweenModuleClassNames[i++] = itor.Current.Key;
                    }
                }
                int selected = EditorGUI.Popup(rect, -1, s_TweenModuleClassNames, styles.plus);
                if(selected >= 0 && selected < s_TweenModuleClassNames.Length)
                {
                    string name = s_TweenModuleClassNames[selected];
                    Type type = s_TweenModuleClasses[name];
                    var module = Activator.CreateInstance(type);
                    animation.AddModule(module as TweenModule);
                }
            }
            GUILayout.Space(-4);
        }

        void AnimationModules()
        {
            if (animation.modules == null)
                return;
            for(int i = 0; i < animation.modules.Count; ++i)
            {
                TweenModule module = animation.modules[i];
                AnimaitonModule(module, i == animation.modules.Count - 1);
            }
        }

        void AnimaitonModule(TweenModule module, bool isLast)
        {
            if (module == null)
                return;
            string name = module.name;
            string description = module.description;
            bool enabled = module.enabled;
            // header
            Rect rect = ui.GetControlRect(20);

            if (Event.current.type == EventType.MouseDown || Event.current.type == EventType.MouseUp)
            {
                Rect checkRect = rect;
                checkRect.x += 1;
                checkRect.y += 1;
                checkRect.width = 20; 
                checkRect.height = 20;
                module.enabled = GUI.Toggle(checkRect, enabled, "", styles.checkmark);
                Rect headerRect = rect;
                headerRect.x -= 2;
                headerRect.width += 8;
                if (GUI.Button(headerRect, "", styles.headerBg))
                    module.unfold = !module.unfold;
            }
            else if(Event.current.type == EventType.Repaint || Event.current.type == EventType.Layout)
            {
                Rect headerRect = rect;
                headerRect.x -= 2;
                headerRect.width += 8;
                GUI.Button(headerRect, "", styles.headerBg);
                Rect checkRect = rect;
                checkRect.x += 1;
                checkRect.y += 1;
                checkRect.width = 20;
                checkRect.height = 20;
                GUI.Toggle(checkRect, enabled, "", styles.checkmark);
            }

            Vector2 size = styles.text.CalcSize(new GUIContent(name));
            GUI.Label(new Rect(rect.x + 15, rect.y + 2, size.x, 20), name, styles.text);

            // content 
            if (module.unfold)
            {
                MethodInfo method;
                string classname = module.GetType().Name;
                if (!s_TweenModuleGUI.TryGetValue(classname, out method))
                {
                    Type type = this.GetType();
                    method = type.GetMethod("OnInspector_" + classname);
                    s_TweenModuleGUI.Add(classname, method);
                }
                if (method != null)
                {
                    object[] parameter = new object[]{ module};
                    method.Invoke(this, parameter);
                }
                else
                {
                    Debug.LogError("没有对应的绘制函数" + "OnInspector_" + classname);
                }
            }

            // wire 
            DrawBgWire(rect, module.unfold ? 4 : -2);

            if (!module.unfold)
                GUILayout.Space(-4);
            else
                GUILayout.Space(2);

            if (!isLast)
                GUILayout.Space(-1);
        }

        void DrawBgWire(Rect firstRect, int hOff)
        {
            Rect bgRect = ui.GetLastControlRect();
            bgRect.height = bgRect.y + bgRect.height - firstRect.y + hOff/*(m_ShowAnimationTab ? 4 : -2)*/;
            bgRect.x = firstRect.x - 3;
            bgRect.y = firstRect.y - 1;
            bgRect.width = firstRect.width + 5;
            GUI.Label(bgRect, "", styles.bgSmall);
        }

        // 绘制时间轴 
        void DrawRuler()
        {

        }

    }
}