using System;
using UnityEngine.Assertions;

namespace UnityEngine.Rendering
{
    /// <summary>
    /// Debug UI Class
    /// </summary>
    public partial class DebugUI
    {
        /// <summary>
        /// Flags for Debug UI widgets.
        /// </summary>
        [Flags]
        public enum Flags
        {
            /// <summary>
            /// None.
            /// </summary>
            None        = 0,
            /// <summary>
            /// This widget is Editor only.
            /// </summary>
            EditorOnly  = 1 << 1,
            /// <summary>
            /// This widget is Runtime only.
            /// </summary>
            RuntimeOnly = 1 << 2,
            /// <summary>
            /// This widget will force the Debug Editor Window refresh.
            /// </summary>
            EditorForceUpdate = 1 << 3
        }

        /// <summary>
        /// Base class for all debug UI widgets.
        /// </summary>
        public abstract class Widget
        {
            // Set to null until it's added to a panel, be careful
            /// <summary>
            /// Panels containing the widget.
            /// </summary>
            protected Panel m_Panel;
            /// <summary>
            /// Panels containing the widget.
            /// </summary>
            public virtual Panel panel
            {
                get { return m_Panel; }
                internal set { m_Panel = value; }
            }

            /// <summary>
            /// Parent container.
            /// </summary>
            protected IContainer m_Parent;
            /// <summary>
            /// Parent container.
            /// </summary>
            public virtual IContainer parent
            {
                get { return m_Parent; }
                internal set { m_Parent = value; }
            }

            /// <summary>
            /// Flags for the widget.
            /// </summary>
            public Flags flags { get; set; }
            /// <summary>
            /// Display name.
            /// </summary>
            public string displayName { get; set; }
            /// <summary>
            /// Path of the widget.
            /// </summary>
            public string queryPath { get; private set; }

            /// <summary>
            /// True if the widget is Editor only.
            /// </summary>
            public bool isEditorOnly { get { return (flags & Flags.EditorOnly) != 0; } }
            /// <summary>
            /// True if the widget is Runtime only.
            /// </summary>
            public bool isRuntimeOnly { get { return (flags & Flags.RuntimeOnly) != 0; } }
            /// <summary>
            /// True if the widget is inactive in the editor (ie: widget is runtime only and the application is not 'Playing')
            /// </summary>
            public bool isInactiveInEditor { get { return (isRuntimeOnly && !Application.isPlaying); } }

            internal virtual void GenerateQueryPath()
            {
                queryPath = displayName.Trim();

                if (m_Parent != null)
                    queryPath = m_Parent.queryPath + " -> " + queryPath;
            }

            /// <summary>
            /// Returns the hash code of the widget.
            /// </summary>
            /// <returns>The hash code of the widget.</returns>
            public override int GetHashCode()
            {
                return queryPath.GetHashCode();
            }
        }

        /// <summary>
        /// Interface for widgets that can contain other widgets.
        /// </summary>
        public interface IContainer
        {
            /// <summary>
            /// List of children of the container.
            /// </summary>
            ObservableList<Widget> children { get; }
            /// <summary>
            /// Display name of the container.
            /// </summary>
            string displayName { get; set; }
            /// <summary>
            /// Path of the container.
            /// </summary>
            string queryPath { get; }
        }


        /// <summary>
        /// Any widget that implements this will be considered for serialization (only if the setter is set and thus is not read-only)
        /// </summary>
        public interface IValueField
        {
            /// <summary>
            /// Return the value of the field.
            /// </summary>
            /// <returns>Value of the field.</returns>
            object GetValue();
            /// <summary>
            /// Set the value of the field.
            /// </summary>
            /// <param name="value">Input value.</param>
            void SetValue(object value);
            /// <summary>
            /// Function used to validate the value when setting it.
            /// </summary>
            /// <param name="value"></param>
            /// <returns></returns>
            object ValidateValue(object value);
        }

        // Miscellaneous
        /// <summary>
        /// Button widget.
        /// </summary>
        public class Button : Widget
        {
            /// <summary>
            /// Action performed by the button.
            /// </summary>
            public Action action { get; set; }
        }

        /// <summary>
        /// Read only Value widget.
        /// </summary>
        public class Value : Widget
        {
            /// <summary>
            /// Getter for the Value.
            /// </summary>
            public Func<object> getter { get; set; }

            /// <summary>
            /// Refresh rate for the read-only value (runtime only)
            /// </summary>
            public float refreshRate = 0.1f;

            /// <summary>
            /// Constructor.
            /// </summary>
            public Value() { displayName = ""; }

            /// <summary>
            /// Returns the value of the widget.
            /// </summary>
            /// <returns>The value of the widget.</returns>
            public object GetValue()
            {
                Assert.IsNotNull(getter);
                return getter();
            }
        }
    }
}
