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

namespace TweenAnimation
{

    public class TweenModuleUI
    {
        static TweenModuleUI m_instance;
        public static TweenModuleUI Get()
        {
            if (m_instance == null)
                m_instance = new TweenModuleUI();
            return m_instance;
        }

        private TweenModuleGUIStyles styles
        {
            get
            {
                return TweenModuleGUIStyles.Get();
            }
        }

        private readonly GUIStyle s_ControlRectStyle = new GUIStyle
        {
            margin = new RectOffset(0, 0, 2, 2)
        };

        private float labelWidth
        {
            get
            {
                return EditorGUIUtility.labelWidth;
            }
        }

        #region Editor internals
        MethodInfo EditorGUI_DoFloatField; // EditorGUI.DoFloatField 		internal float DoFloatField(EditorGUI.RecycledTextEditor editor, Rect position, Rect dragHotZone, int id, float value, string formatString, GUIStyle style, bool draggable)
        FieldInfo EditorGUI_RecycledEditor;  // EditorGUI.s_RecycleEditor   

        int EditorGUI_FloatFieldHash = "EditorTextField".GetHashCode();

        #endregion

        TweenModuleUI()
        {
            Type editorGUIType = typeof(EditorGUI);
            Type recycledTextEditorType = Assembly.GetAssembly(editorGUIType).GetType("UnityEditor.EditorGUI+RecycledTextEditor");

            // DoFloatField
            {
                Type[] argumentTypes = new Type[] { recycledTextEditorType, typeof(Rect), typeof(Rect), typeof(int), typeof(float), typeof(string), typeof(GUIStyle), typeof(bool) };
                EditorGUI_DoFloatField = editorGUIType.GetMethod("DoFloatField", BindingFlags.NonPublic | BindingFlags.Static, null, argumentTypes, null);
                EditorGUI_RecycledEditor = editorGUIType.GetField("s_RecycledEditor", BindingFlags.NonPublic | BindingFlags.Static);
            }
        }

        private object Invoke(MethodInfo method, object caller, params object[] param)
        {
            return method.Invoke(caller, param);
        }

        public Rect GetControlRect(int height)
        {
            return GetControlRect(height, null);
        }

        public float GUIFloat(string guiContent, float floatValue, string formatString = null, params GUILayoutOption[] layoutOptions)
        {
            return GUIFloat(new GUIContent(guiContent), floatValue, formatString, layoutOptions);
        }

        public float GUIFloat(GUIContent guiContent, float floatValue, string formatString, params GUILayoutOption[] layoutOptions)
        {
            Rect controlRect = GetControlRect(13, layoutOptions);
            PrefixLabel(controlRect, guiContent);
            return FloatDraggable(controlRect, floatValue, 1f, EditorGUIUtility.labelWidth, formatString);
        }

        public float FloatDraggable(Rect rect, float floatValue, float remap, float dragWidth, string formatString)
        {
            int controlID = GUIUtility.GetControlID(EditorGUI_FloatFieldHash, FocusType.Keyboard, rect);
            Rect dragHotZone = rect;
            dragHotZone.width = dragWidth;
            Rect position = rect;
            position.xMin += dragWidth;
            float v =  (float)Invoke(EditorGUI_DoFloatField, null, EditorGUI_RecycledEditor.GetValue(null), position, dragHotZone, controlID, floatValue * remap, formatString, styles.floatfiled, true);
            return v / remap;
        }

        public string GUIText(string label, string content, params GUILayoutOption[] layoutOptions)
        {
            return GUIText(new GUIContent(label), content, layoutOptions);
        }

        public string GUIText(GUIContent guiContent, string content, params GUILayoutOption[] layoutOptions)
        {
            Rect controlRect = GetControlRect(13, layoutOptions);
            PrefixLabel(controlRect, guiContent);
            Rect position = controlRect;
            position.xMin += EditorGUIUtility.labelWidth;
            content = GUI.TextField(position, content);
            return content;
        }

        public Enum GUIEnumMask(string label, Enum enumValue, params GUILayoutOption[] layoutOptions)
        {
            return GUIEnumMask(new GUIContent(label), enumValue, layoutOptions);
        }

        public Enum GUIEnumMask(GUIContent label, Enum enumValue, params GUILayoutOption[] layoutOptions)
        {
            Rect rect = GetControlRect(13, layoutOptions);
            rect = PrefixLabel(rect, label);
            return EditorGUI.EnumFlagsField(rect, enumValue, styles.popup);
        }

        public Enum GUIEnum(string label, Enum enumValue, params GUILayoutOption[] layoutOptions)
        {
            return GUIEnum(new GUIContent(label), enumValue, layoutOptions);
        }

        public Enum GUIEnum(GUIContent label, Enum enumValue, params GUILayoutOption[] layoutOptions)
        {
            Rect rect = GetControlRect(13, layoutOptions);
            rect = PrefixLabel(rect, label);
            return EditorGUI.EnumPopup(rect, enumValue, styles.popup);
        }

        private Rect PrefixLabel(Rect totalPosition, GUIContent label)
        {
            bool flag = !EditorGUI_LabelHasContent(label);
            Rect result;
            if (flag)
            {
                result = EditorGUI.IndentedRect(totalPosition);
            }
            else
            {
                Rect labelPosition;
                Rect rect = FieldPosition(totalPosition, out labelPosition);
                EditorGUI.HandlePrefixLabel(totalPosition, labelPosition, label, 0, styles.label);
                result = rect;
            }
            return result;
        }

        private Rect FieldPosition(Rect totalPosition, out Rect labelPosition)
        {
            labelPosition = new Rect(totalPosition.x + EditorGUI_indent, totalPosition.y, EditorGUIUtility.labelWidth - EditorGUI_indent, 13f);
            return new Rect(totalPosition.x + EditorGUIUtility.labelWidth, totalPosition.y, totalPosition.width - EditorGUIUtility.labelWidth, totalPosition.height);
        }

        private Rect GetControlRect(int height, params GUILayoutOption[] layoutOptions)
        {
            return GUILayoutUtility.GetRect(0f, (float)height, s_ControlRectStyle, layoutOptions);
        }

        private bool EditorGUI_LabelHasContent(GUIContent label)
        {
            bool flag = label == null;
            return flag || label.text != string.Empty || label.image != null;
        }

        // EditorGUI.indent
        private float EditorGUI_indent
        {
            get
            {
                return (float)EditorGUI.indentLevel * 15f;
            }
        }

        public Rect GetLastControlRect()
        {
            return GUILayoutUtility.GetLastRect();
        }

    }

}