// Alloy Physical Shader Framework
// Copyright 2013-2017 RUST LLC.
// http://www.alloy.rustltd.com/

using UnityEngine;
using UnityEditor;

#if H3VR_IMPORTED
[CustomEditor(typeof(AlloyAreaLight))]
[CanEditMultipleObjects]
public class AlloyAreaLightEditor : Editor {
    public override void OnInspectorGUI() {
        serializedObject.Update();

        var hasSpecularHightlight = serializedObject.FindProperty("m_hasSpecularHightlight");
        var maxRange = float.MaxValue;
        var isSpecularAreaLight = false;
        var isPointLight = false;

        // Light Type.
        foreach (AlloyAreaLight area in targets) {
            var light = area.GetComponent<Light>();

	        if (light.type == LightType.Directional) {
		        maxRange = 1.0f;
	        }
	        else {
		        maxRange = Mathf.Min(light.range, maxRange);
	        }

	        isPointLight = light.type == LightType.Point;

            if (isPointLight 
                || light.type == LightType.Spot  
                || light.type == LightType.Directional) {
                isSpecularAreaLight = true;
            }
        }

        // Specular Highlight.
        if (isSpecularAreaLight) {
            hasSpecularHightlight.boolValue = EditorGUILayout.Toggle("Specular Highlight", hasSpecularHightlight.boolValue);
            isSpecularAreaLight = isSpecularAreaLight && hasSpecularHightlight.boolValue;
        }

        // Radius.
        if (isSpecularAreaLight) {
            EditorGUILayout.Slider(serializedObject.FindProperty("m_radius"), 0.0f, maxRange);
        } else {
            var radius = serializedObject.FindProperty("m_radius");

            if (radius.floatValue != 0.0f) {
                GUI.changed = true;
                radius.floatValue = 0.0f;
            }
        }

        // Length.
        if (isSpecularAreaLight && isPointLight) {
            EditorGUILayout.Slider(serializedObject.FindProperty("m_length"), 0.0f, maxRange * 2.0f);
        } else { 
            var length = serializedObject.FindProperty("m_length");

            if (length.floatValue != 0.0f) {
                GUI.changed = true;
                length.floatValue = 0.0f;
            }
        }
        
        serializedObject.ApplyModifiedProperties();

        if (GUI.changed) {
            foreach (AlloyAreaLight area in targets) {
                area.UpdateBinding();
            }
        }
    }

    internal static void DrawTwoShadedWireDisc(Vector3 position, Vector3 axis, float radius) {
        Color color1 = Handles.color;
        Color color2 = color1;

        color1.a *= 0.2f;
        Handles.color = color1;
        Handles.DrawWireDisc(position, axis, radius);
        Handles.color = color2;
    }

    internal static void DrawTwoShadedWireDisc(Vector3 position, Vector3 axis, Vector3 from, float degrees, float radius) {
        Handles.DrawWireArc(position, axis, from, degrees, radius);

        Color cur = Handles.color;
        Color set = cur;

        set.a *= 0.2f;
        Handles.color = set;
        Handles.DrawWireArc(position, axis, from, degrees - 360f, radius);
        Handles.color = cur;
    }

    static Vector3[] s_directionArray = {
        Vector3.right,
        Vector3.up,
        Vector3.forward,
        -Vector3.right,
        -Vector3.up,
        -Vector3.forward
    };

    static void DoRadiusHandle(Vector3 position, float radius, float length) {
        Vector3 dif = position - Camera.current.transform.position;
        float sqrMagnitude = dif.sqrMagnitude;
        float radiusSqr = radius * radius;
        float radiusDiv = radiusSqr * radiusSqr / sqrMagnitude;
        //float ratio = radiusDiv / radiusSqr;
        float total = Mathf.Sqrt(radiusSqr - radiusDiv);

        Handles.DrawWireDisc(position - radiusSqr * dif / sqrMagnitude, dif, total);

        for (int j = 0; j < 3; j++) {
            float angle = Vector3.Angle(dif, s_directionArray[j]);

            angle = 90f - Mathf.Min(angle, 180f - angle);

            float tanAngle = Mathf.Tan(angle * Mathf.Deg2Rad);
            float viewSize = Mathf.Sqrt(radiusDiv + tanAngle * tanAngle * radiusDiv) / radius;

            if (viewSize < 1f) {
                float finalArcAngle = Mathf.Asin(viewSize) * Mathf.Rad2Deg;
                Vector3 vector2 = Vector3.Cross(s_directionArray[j], dif).normalized;
                vector2 = Quaternion.AngleAxis(finalArcAngle, s_directionArray[j]) * vector2;
                DrawTwoShadedWireDisc(position, s_directionArray[j], vector2, (90f - finalArcAngle) * 2f, radius);
            }
            else {
                DrawTwoShadedWireDisc(position, s_directionArray[j], radius);
            }
        }
    }

    float DrawCapsuleGizmo(Transform transform, float radius, float length) {
        var fwd = Vector3.forward * radius;
        var side = Vector3.up * radius;
        var halfLength = 0.5f * length;

        // Exclude light transform scale, and pre-rotate capsule to follow the Y-axis.
        Handles.matrix = Matrix4x4.TRS(transform.position, transform.rotation, Vector3.one)
                    * Matrix4x4.TRS(Vector3.zero, Quaternion.Euler(0.0f, 0.0f, 90.0f), Vector3.one);

        Handles.DrawWireArc(-halfLength * Vector3.right, Vector3.forward, Vector3.up, 180.0f, radius);
        Handles.DrawWireArc(-halfLength * Vector3.right, Vector3.up, -Vector3.forward, 180.0f, radius);

        Handles.DrawWireArc(halfLength * Vector3.right, Vector3.forward, -Vector3.up, 180.0f, radius);
        Handles.DrawWireArc(halfLength * Vector3.right, Vector3.up, Vector3.forward, 180.0f, radius);

        Handles.DrawWireDisc(-halfLength * Vector3.right, Vector3.right, radius);
        Handles.DrawWireDisc(halfLength * Vector3.right, Vector3.right, radius);

        Handles.DrawLine(-halfLength * Vector3.right + fwd, halfLength * Vector3.right + fwd);
        Handles.DrawLine(-halfLength * Vector3.right - fwd, halfLength * Vector3.right - fwd);

        Handles.DrawLine(-halfLength * Vector3.right + side, halfLength * Vector3.right + side);
        Handles.DrawLine(-halfLength * Vector3.right - side, halfLength * Vector3.right - side);

        if (!Event.current.alt && !Event.current.shift) {
            radius = Handles.RadiusHandle(Quaternion.identity, -halfLength * Vector3.right, radius, true);
            radius = Handles.RadiusHandle(Quaternion.identity, halfLength * Vector3.right, radius, true);
        }

        Handles.matrix = Matrix4x4.identity;

        return radius;
    }

    void OnSceneGUI() {
        var area = target as AlloyAreaLight;
        var light = area.GetComponent<Light>();

        if (light.type == LightType.Point
            || light.type == LightType.Spot) {
            area.Radius = DrawCapsuleGizmo(area.transform, area.Radius, area.Length);
        }

        //DoRadiusHandle(area.transform.position, area.Size, 1.0f);

        if (GUI.changed) {
            Undo.RecordObject(area, "Adjust area light");
        }
    }
}
#endif