using System;
using UnityEditor;
using UnityEngine;

public class EditorGUILayoutEx
{
    internal const float kSingleLineHeight = 16f;

    internal const float kLabelW = 80f;

    internal const float kSpacing = 5f;

    internal const float kSpacingSubLabel = 2f;

    internal const float kSliderMinW = 60f;

    internal const float kSliderMaxW = 100f;

    internal static string kFloatFieldFormatString = "g7";

    private static readonly int s_SliderKnobHash = "EditorSliderKnob".GetHashCode();

    private static readonly GUIContent s_Text = new GUIContent();

    private static readonly GUIContent s_Image = new GUIContent();

    private static readonly GUIContent s_TextImage = new GUIContent();

    private const int kMaxDecimals = 15;

    private static float kLabelFloatMaxW => EditorGUIUtility.labelWidth + EditorGUIUtility.fieldWidth + 5f;

    internal static Rect DragZoneRect(Rect position)
    {
        return new Rect(position.x, position.y, EditorGUIUtility.labelWidth, position.height);
    }

    internal static bool LabelHasContent(GUIContent label)
    {
        if (label == null)
        {
            return true;
        }
        return label.text != string.Empty || label.image != null;
    }

    internal static GUIContent TempContent(string t)
    {
        s_Text.image = null;
        s_Text.text = t;
        s_Text.tooltip = null;
        return s_Text;
    }

    public static float PowerSlider(GUIContent content, float value, float leftValue, float rightValue, float defaultValue, float power, params GUILayoutOption[] options)
    {
        Rect position = GUILayoutUtility.GetRect(EditorGUIUtility.fieldWidth, kLabelFloatMaxW + 5f + 100f, 16f, 16f, EditorStyles.numberField, options);
        int id = GUIUtility.GetControlID(FocusType.Passive, position);
        Rect sliderRect = EditorGUI.PrefixLabel(position, id, content);
        Rect btnRect = new Rect(sliderRect.x - 29f, sliderRect.y, 19f, sliderRect.height);
        Rect dragZone = LabelHasContent(content) ? DragZoneRect(position) : default(Rect);
        if (defaultValue != value && GUI.Button(btnRect, "R", EditorStyles.miniButton))
        {
            value = defaultValue;
        }
        return DoSlider(sliderRect, dragZone, id, value, leftValue, rightValue, kFloatFieldFormatString, leftValue, rightValue, power, GUI.skin.horizontalSlider, GUI.skin.horizontalSliderThumb);
    }

    public static float Slider(GUIContent content, float value, float leftValue, float rightValue, float defaultValue, params GUILayoutOption[] options)
    {
        //EditorGUILayout.BeginHorizontal();
        //EditorGUILayout.LabelField(content);
        //if (defaultValue == value)
        //{
        //    GUI.enabled = false;
        //}
        //else
        //{
        //    GUI.enabled = true;
        //}
        //if (GUILayout.Button("R1", EditorStyles.miniButton, GUILayout.Width(30)))
        //{
        //    value = defaultValue;
        //}
        //GUI.enabled = true;
        //value = EditorGUILayout.Slider( value, leftValue, rightValue);
        //EditorGUILayout.EndHorizontal();
        Rect position = GUILayoutUtility.GetRect(EditorGUIUtility.fieldWidth, kLabelFloatMaxW + 5f + 100f, 16f, 16f, EditorStyles.numberField, options);
        int id = GUIUtility.GetControlID(FocusType.Passive, position);
        Rect sliderRect = EditorGUI.PrefixLabel(position, id, content);
        Rect btnRect = new Rect(sliderRect.x - 29f, sliderRect.y, 19f, sliderRect.height);
        Rect dragZone = LabelHasContent(content) ? DragZoneRect(position) : default(Rect);
        bool guienable = GUI.enabled;
        if (defaultValue != value  )
        {
            GUI.enabled = true;
        }
        else
        {
            GUI.enabled = false;
        }
        if (GUI.Button(btnRect, "R", EditorStyles.miniButton))
        {
            value = defaultValue;
        }
        GUI.enabled = guienable;
        return EditorGUI.Slider(sliderRect, value, leftValue, rightValue);
    }

    public static float Slider(string label, float value, float leftValue, float rightValue, float defaltValue, params GUILayoutOption[] options)
    {
        return Slider(TempContent(label), value, leftValue, rightValue, defaltValue, options);
    }

    public static float PowerSlider(string label, float value, float leftValue, float rightValue, float defaltValue, float power, params GUILayoutOption[] options)
    {
        return PowerSlider(TempContent(label), value, leftValue, rightValue, defaltValue, power, options);
    }

    private static float PowPreserveSign(float f, float p)
    {
        float result = Mathf.Pow(Mathf.Abs(f), p);
        return (f < 0f) ? (0f - result) : result;
    }

    internal static float RoundToMultipleOf(float value, float roundingValue)
    {
        if (roundingValue == 0f)
        {
            return value;
        }
        return Mathf.Round(value / roundingValue) * roundingValue;
    }

    internal static float GetClosestPowerOfTen(float positiveNumber)
    {
        if (positiveNumber <= 0f)
        {
            return 1f;
        }
        return Mathf.Pow(10f, (float)Mathf.RoundToInt(Mathf.Log10(positiveNumber)));
    }

    internal static int GetNumberOfDecimalsForMinimumDifference(double minDifference)
    {
        return (int)Math.Max(0.0, 0.0 - Math.Floor(Math.Log10(Math.Abs(minDifference))));
    }

    internal static float RoundBasedOnMinimumDifference(float valueToRound, float minDifference)
    {
        if (minDifference == 0f)
        {
            return DiscardLeastSignificantDecimal(valueToRound);
        }
        return (float)Math.Round(valueToRound, GetNumberOfDecimalsForMinimumDifference(minDifference), MidpointRounding.AwayFromZero);
    }

    internal static float DiscardLeastSignificantDecimal(float v)
    {
        int decimals = Mathf.Clamp((int)(5f - Mathf.Log10(Mathf.Abs(v))), 0, 15);
        return (float)Math.Round(v, decimals, MidpointRounding.AwayFromZero);
    }

    private static float DoSlider(Rect position, Rect dragZonePosition, int id, float value, float sliderMin, float sliderMax, string formatString, float textFieldMin, float textFieldMax, float power, GUIStyle sliderStyle, GUIStyle thumbStyle)
    {
        int sliderId = GUIUtility.GetControlID(s_SliderKnobHash, FocusType.Passive, position);
        sliderMin = Mathf.Clamp(sliderMin, float.MinValue, float.MaxValue);
        sliderMax = Mathf.Clamp(sliderMax, float.MinValue, float.MaxValue);
        value = Mathf.Clamp(value, Mathf.Min(sliderMin, sliderMax), Mathf.Max(sliderMin, sliderMax));
        float w2 = position.width;
        if (w2 >= 65f + EditorGUIUtility.fieldWidth)
        {
            float sWidth = w2 - 5f - EditorGUIUtility.fieldWidth;
            EditorGUI.BeginChangeCheck();
            float remapLeft = sliderMin;
            float remapRight = sliderMax;
            float newSliderValue3 = value;
            if (power != 1f)
            {
                remapLeft = 0f;
                remapRight = 1f;
                newSliderValue3 = PowPreserveSign((value - sliderMin) / (sliderMax - sliderMin), 1f / power);
            }
            Rect sliderRect = new Rect(position.x, position.y, sWidth, position.height);
            newSliderValue3 = GUI.Slider(sliderRect, newSliderValue3, 0f, remapLeft, remapRight, sliderStyle, (!EditorGUI.showMixedValue) ? GUI.skin.horizontalSliderThumb : "SliderMixed", true, sliderId);
            if (power != 1f)
            {
                newSliderValue3 = PowPreserveSign(newSliderValue3, power);
                newSliderValue3 = Mathf.Lerp(Mathf.Min(sliderMin, sliderMax), Mathf.Max(sliderMin, sliderMax), newSliderValue3);
            }
            if (EditorGUI.EndChangeCheck())
            {
                value = Mathf.Clamp(newSliderValue3, Mathf.Min(sliderMin, sliderMax), Mathf.Max(sliderMin, sliderMax));
            }
            value = EditorGUI.FloatField(new Rect(position.x + sWidth + 5f, position.y, EditorGUIUtility.fieldWidth, position.height), value);
            value = Mathf.Clamp(value, Mathf.Min(textFieldMin, textFieldMax), Mathf.Max(textFieldMin, textFieldMax));
        }
        else
        {
            w2 = Mathf.Min(EditorGUIUtility.fieldWidth, w2);
            position.x = position.x - w2;
            position.width = w2;
            value = EditorGUI.FloatField(position, value);
            value = Mathf.Clamp(value, Mathf.Min(textFieldMin, textFieldMax), Mathf.Max(textFieldMin, textFieldMax));
        }
        return value;
    }

    public static Color ColorField(GUIContent label, Color value, Color defaultValue, params GUILayoutOption[] options)
    {
        Rect position = GUILayoutUtility.GetRect(EditorGUIUtility.fieldWidth, kLabelFloatMaxW + 5f + 100f, 16f, 16f, EditorStyles.numberField, options);
        int id = GUIUtility.GetControlID(FocusType.Passive, position);
        Rect controlRect = EditorGUI.PrefixLabel(position, id, label);
        Rect btnRect = new Rect(controlRect.x - 29f, controlRect.y, 19f, controlRect.height);
        Rect dragZone = LabelHasContent(label) ? DragZoneRect(position) : default(Rect);
        if (defaultValue != value && GUI.Button(btnRect, "R", EditorStyles.miniButton))
        {
            value = defaultValue;
        }
        return EditorGUI.ColorField(controlRect, value);
    }

    public static Color ColorField(string label, Color value, Color defaultValue, params GUILayoutOption[] options)
    {
        return ColorField(TempContent(label), value, defaultValue, options);
    }

    public static Vector3 Vector3Field(GUIContent label, Vector3 value, Vector3 defaultValue, params GUILayoutOption[] options)
    {
        Rect position = GUILayoutUtility.GetRect(EditorGUIUtility.fieldWidth, kLabelFloatMaxW + 5f + 100f, 16f, 16f, EditorStyles.numberField, options);
        int id = GUIUtility.GetControlID(FocusType.Passive, position);
        Rect controlRect = EditorGUI.PrefixLabel(position, id, label);
        Rect btnRect = new Rect(controlRect.x - 29f, controlRect.y, 19f, controlRect.height);
        Rect dragZone = LabelHasContent(label) ? DragZoneRect(position) : default(Rect);
        if (defaultValue != value && GUI.Button(btnRect, "R", EditorStyles.miniButton))
        {
            value = defaultValue;
        }
        return EditorGUI.Vector3Field(controlRect, "", value);
    }

    public static Vector3 Vector3Field(string label, Vector3 value, Vector3 defaultValue, params GUILayoutOption[] options)
    {
        return Vector3Field(TempContent(label), value, defaultValue, options);
    }
}
