// KlakSpout - Spout video frame sharing plugin for Unity
// https://github.com/keijiro/KlakSpout

using UnityEngine;
using UnityEditor;

namespace Klak.Spout
{
    [CanEditMultipleObjects]
    [CustomEditor(typeof(SpoutReceiver))]
    sealed class SpoutReceiverEditor : Editor
    {
        SerializedProperty _sourceName;
        SerializedProperty _targetTexture;
        SerializedProperty _targetRenderer;
        SerializedProperty _targetMaterialProperty;

        static double _prevRepaintTime;

        static class Labels
        {
            public static readonly GUIContent Property = new GUIContent("Property");
            public static readonly GUIContent Select = new GUIContent("Select");
        }

        // Request receiver reconnection.
        void RequestReconnect()
        {
            foreach (SpoutReceiver receiver in targets) receiver.RequestReconnect();
        }

        // Check and request repaint with 0.1s interval.
        void CheckRepaint()
        {
            var time = EditorApplication.timeSinceStartup;
            if (time - _prevRepaintTime < 0.1) return;
            UnityEditorInternal.InternalEditorUtility.RepaintAllViews();
            _prevRepaintTime = time;
        }

        // Create and show the source name dropdown.
        void ShowSourceNameDropdown(Rect rect)
        {
            var menu = new GenericMenu();
            var count = PluginEntry.ScanSharedObjects();
            for (var i = 0; i < count; i++)
            {
                var name = PluginEntry.GetSharedObjectNameString(i);
                menu.AddItem(new GUIContent(name), false, OnSelectSource, name);
            }
            menu.DropDown(rect);
        }

        // Source name selection callback
        void OnSelectSource(object name)
        {
            serializedObject.Update();
            _sourceName.stringValue = (string)name;
            serializedObject.ApplyModifiedProperties();
            RequestReconnect();
        }

        void OnEnable()
        {
            _sourceName = serializedObject.FindProperty("_sourceName");
            _targetTexture = serializedObject.FindProperty("_targetTexture");
            _targetRenderer = serializedObject.FindProperty("_targetRenderer");
            _targetMaterialProperty = serializedObject.FindProperty("_targetMaterialProperty");

            EditorApplication.update += CheckRepaint;
        }

        void OnDisable()
        {
            EditorApplication.update -= CheckRepaint;
        }

        public override void OnInspectorGUI()
        {
            serializedObject.Update();

            EditorGUILayout.BeginHorizontal();

            // Source name text field
            EditorGUI.BeginChangeCheck();
            EditorGUILayout.DelayedTextField(_sourceName);
            if (EditorGUI.EndChangeCheck()) RequestReconnect();

            // Source name dropdown
            var rect = EditorGUILayout.GetControlRect(false, GUILayout.Width(60));
            if (EditorGUI.DropdownButton(rect, Labels.Select, FocusType.Keyboard))
                ShowSourceNameDropdown(rect);

            EditorGUILayout.EndHorizontal();

            // Target texture/renderer
            EditorGUILayout.PropertyField(_targetTexture);
            EditorGUILayout.PropertyField(_targetRenderer);

            EditorGUI.indentLevel++;

            if (_targetRenderer.hasMultipleDifferentValues)
            {
                // Multiple renderers selected: Show a simple text field.
                EditorGUILayout.PropertyField(_targetMaterialProperty, Labels.Property);
            }
            else if (_targetRenderer.objectReferenceValue != null)
            {
                // Single renderer: Show the material property selection dropdown.
                MaterialPropertySelector.DropdownList(_targetRenderer, _targetMaterialProperty);
            }

            EditorGUI.indentLevel--;

            serializedObject.ApplyModifiedProperties();
        }
    }
}
