#if UNITY_EDITOR
namespace Sirenix.OdinInspector.Demos
{
    using System;
    using UnityEngine;

#if UNITY_EDITOR

    using Sirenix.OdinInspector.Editor;
    using System.Reflection;
    using Sirenix.Utilities;
    using Sirenix.Utilities.Editor;

#endif

    // Example demonstrating how reflection can be used to enhance custom drawers.
    [TypeInfoBox(
            "This example demonstrates how reflection can be used to extend drawers from what otherwise would be possible.\n\n" +
            "In this case, a user can specify one of their own methods to receive a callback from the drawer chain.\n\n" +
            "Note that this is a manual approach; it is recommended to use ValueResolver<T> and ActionResolver instead.")]
    public class ReflectionExample : MonoBehaviour
    {
        [OnClickMethod("OnClick")]
        public int InstanceMethod;

        [OnClickMethod("StaticOnClick")]
        public int StaticMethod;

        [OnClickMethod("InvalidOnClick")]
        public int InvalidMethod;

        private void OnClick()
        {
            Debug.Log("Hello?");
        }

        private static void StaticOnClick()
        {
            Debug.Log("Static Hello?");
        }
    }

    // Attribute with name of call back method.
    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
    public class OnClickMethodAttribute : Attribute
    {
        public string MethodName { get; private set; }

        public OnClickMethodAttribute(string methodName)
        {
            this.MethodName = methodName;
        }
    }

#if UNITY_EDITOR

    // Place the drawer script file in an Editor folder.
    // Remember to add the OdinDrawer to your custom drawer classes, or they will not be found by Odin.
    public class OnClickMethodAttributeDrawer : OdinAttributeDrawer<OnClickMethodAttribute>
    {
        // This field is used to display errors messages to the user, if something goes wrong.
        private string ErrorMessage;

        // Reference to the method specified by the user in the attribute.
        private MethodInfo Method;

        protected override void Initialize()
        {
            // Use reflection to find the specified method, and store the method info in the context object.
            this.Method = this.Property.ParentType.GetMethod(this.Attribute.MethodName, Flags.StaticInstanceAnyVisibility, null, Type.EmptyTypes, null);

            if (this.Method == null)
            {
                this.ErrorMessage = "Could not find a parameterless method named '" + this.Attribute.MethodName + "' in the type '" + this.Property.ParentType + "'.";
            }
        }

        protected override void DrawPropertyLayout(GUIContent label)
        {
            // Display any error that might have occured.
            if (this.ErrorMessage != null)
            {
                SirenixEditorGUI.ErrorMessageBox(this.ErrorMessage);

                // Continue drawing the rest of the property as normal.
                this.CallNextDrawer(label);
            }
            else
            {
                // Get the mouse down event.
                bool clicked = Event.current.rawType == EventType.MouseDown && Event.current.button == 0 && this.Property.LastDrawnValueRect.Contains(Event.current.mousePosition);

                if (clicked)
                {
                    // Invoke the method stored in the context object.
                    if (this.Method.IsStatic)
                    {
                        this.Method.Invoke(null, null);
                    }
                    else
                    {
                        this.Method.Invoke(this.Property.ParentValues[0], null);
                    }
                }

                // Draw the property.
                this.CallNextDrawer(label);

                if (clicked)
                {
                    // If the event havn't been used yet, then use it here.
                    Event.current.Use();
                }
            }
        }
    }

#endif
}
#endif
