// --------------------------------------------------------------------------------------------------------------------
// <copyright file="CullAreaEditor.cs" company="Exit Games GmbH">
//   Part of: Photon Unity Utilities,
// </copyright>
// <summary>
//  Custom inspector for CullArea
// </summary>
// <author>developer@exitgames.com</author>
// --------------------------------------------------------------------------------------------------------------------

using UnityEditor;
using UnityEngine;

namespace Photon.Pun.UtilityScripts
{
    [CanEditMultipleObjects]
    [CustomEditor(typeof(CullArea))]
    public class CullAreaEditor : Editor
    {
        private bool alignEditorCamera, showHelpEntries;

        private CullArea cullArea;

        private enum UP_AXIS_OPTIONS
        {
            SideScrollerMode = 0,
            TopDownOr3DMode = 1
        }

        private UP_AXIS_OPTIONS upAxisOptions;

        public void OnEnable()
        {
            cullArea = (CullArea)target;

            // Destroying the newly created cull area if there is already one existing
            if (FindObjectsOfType<CullArea>().Length > 1)
            {
                Debug.LogWarning("Destroying newly created cull area because there is already one existing in the scene.");

                DestroyImmediate(cullArea);

                return;
            }

            // Prevents the dropdown from resetting
            if (cullArea != null)
            {
                upAxisOptions = cullArea.YIsUpAxis ? UP_AXIS_OPTIONS.SideScrollerMode : UP_AXIS_OPTIONS.TopDownOr3DMode;
            }
        }

        public override void OnInspectorGUI()
        {
            EditorGUILayout.BeginVertical();

            if (Application.isEditor && !Application.isPlaying)
            {
                OnInspectorGUIEditMode();
            }
            else
            {
                OnInspectorGUIPlayMode();
            }

            EditorGUILayout.EndVertical();
        }

        /// <summary>
        ///     Represents the inspector GUI when edit mode is active.
        /// </summary>
        private void OnInspectorGUIEditMode()
        {
            EditorGUI.BeginChangeCheck();

            #region DEFINE_UP_AXIS

            {
                EditorGUILayout.BeginVertical();
                EditorGUILayout.LabelField("Select game type", EditorStyles.boldLabel);
                upAxisOptions = (UP_AXIS_OPTIONS)EditorGUILayout.EnumPopup("Game type", upAxisOptions);
                cullArea.YIsUpAxis = (upAxisOptions == UP_AXIS_OPTIONS.SideScrollerMode);
                EditorGUILayout.EndVertical();
            }

            #endregion

            EditorGUILayout.Space();

            #region SUBDIVISION

            {
                EditorGUILayout.BeginVertical();
                EditorGUILayout.LabelField("Set the number of subdivisions", EditorStyles.boldLabel);
                cullArea.NumberOfSubdivisions = EditorGUILayout.IntSlider("Number of subdivisions", cullArea.NumberOfSubdivisions, 0, CullArea.MAX_NUMBER_OF_SUBDIVISIONS);
                EditorGUILayout.EndVertical();

                EditorGUILayout.Space();

                if (cullArea.NumberOfSubdivisions != 0)
                {
                    for (int index = 0; index < cullArea.Subdivisions.Length; ++index)
                    {
                        if ((index + 1) <= cullArea.NumberOfSubdivisions)
                        {
                            string countMessage = (index + 1) + ". Subdivision: row / column count";

                            EditorGUILayout.BeginVertical();
                            cullArea.Subdivisions[index] = EditorGUILayout.Vector2Field(countMessage, cullArea.Subdivisions[index]);
                            EditorGUILayout.EndVertical();

                            EditorGUILayout.Space();
                        }
                        else
                        {
                            cullArea.Subdivisions[index] = new UnityEngine.Vector2(1, 1);
                        }
                    }
                }
            }

            #endregion

            EditorGUILayout.Space();

            #region UPDATING_MAIN_CAMERA

            {
                EditorGUILayout.BeginVertical();

                EditorGUILayout.LabelField("View and camera options", EditorStyles.boldLabel);
                alignEditorCamera = EditorGUILayout.Toggle("Automatically align editor view with grid", alignEditorCamera);

                if (Camera.main != null)
                {
                    if (GUILayout.Button("Align main camera with grid"))
                    {
                        Undo.RecordObject(Camera.main.transform, "Align main camera with grid.");

                        float yCoord = cullArea.YIsUpAxis ? cullArea.Center.y : Mathf.Max(cullArea.Size.x, cullArea.Size.y);
                        float zCoord = cullArea.YIsUpAxis ? -Mathf.Max(cullArea.Size.x, cullArea.Size.y) : cullArea.Center.y;

                        Camera.main.transform.position = new Vector3(cullArea.Center.x, yCoord, zCoord);
                        Camera.main.transform.LookAt(cullArea.transform.position);
                    }

                    EditorGUILayout.LabelField("Current main camera position is " + Camera.main.transform.position.ToString());
                }

                EditorGUILayout.EndVertical();
            }

            #endregion

            if (EditorGUI.EndChangeCheck())
            {
                cullArea.RecreateCellHierarchy = true;

                AlignEditorView();
            }

            EditorGUILayout.Space();
            EditorGUILayout.Space();
            EditorGUILayout.Space();

            showHelpEntries = EditorGUILayout.Foldout(showHelpEntries, "Need help with this component?");
            if (showHelpEntries)
            {
                EditorGUILayout.HelpBox("To find help you can either follow the tutorial or have a look at the forums by clicking on the buttons below.", MessageType.Info);
                EditorGUILayout.BeginHorizontal();
                if (GUILayout.Button("Open the tutorial"))
                {
                    Application.OpenURL("https://doc.photonengine.com/en-us/pun/v2/demos-and-tutorials/package-demos/culling-demo");
                }
                if (GUILayout.Button("Take me to the forums"))
                {
                    Application.OpenURL("https://forum.photonengine.com/categories/unity-networking-plugin-pun");
                }
                EditorGUILayout.EndHorizontal();
            }
        }

        /// <summary>
        ///     Represents the inspector GUI when play mode is active.
        /// </summary>
        private void OnInspectorGUIPlayMode()
        {
            EditorGUILayout.LabelField("No changes allowed when game is running. Please exit play mode first.", EditorStyles.boldLabel);
        }

        public void OnSceneGUI()
        {
            Handles.BeginGUI();
            GUILayout.BeginArea(new Rect(Screen.width - 110, Screen.height - 90, 100, 60));

            if (GUILayout.Button("Reset position"))
            {
                cullArea.transform.position = Vector3.zero;
            }

            if (GUILayout.Button("Reset scaling"))
            {
                cullArea.transform.localScale = new Vector3(25.0f, 25.0f, 25.0f);
            }

            GUILayout.EndArea();
            Handles.EndGUI();

            // Checking for changes of the transform
            if (cullArea.transform.hasChanged)
            {
                // Resetting position
                float posX = cullArea.transform.position.x;
                float posY = cullArea.YIsUpAxis ? cullArea.transform.position.y : 0.0f;
                float posZ = !cullArea.YIsUpAxis ? cullArea.transform.position.z : 0.0f;

                cullArea.transform.position = new Vector3(posX, posY, posZ);

                // Resetting scaling
                if (cullArea.Size.x < 1.0f || cullArea.Size.y < 1.0f)
                {
                    float scaleX = (cullArea.transform.localScale.x < 1.0f) ? 1.0f : cullArea.transform.localScale.x;
                    float scaleY = (cullArea.transform.localScale.y < 1.0f) ? 1.0f : cullArea.transform.localScale.y;
                    float scaleZ = (cullArea.transform.localScale.z < 1.0f) ? 1.0f : cullArea.transform.localScale.z;

                    cullArea.transform.localScale = new Vector3(scaleX, scaleY, scaleZ);

                    Debug.LogWarning("Scaling on a single axis can not be lower than 1. Resetting...");
                }

                cullArea.RecreateCellHierarchy = true;

                AlignEditorView();
            }
        }

        /// <summary>
        ///     Aligns the editor view with the created grid.
        /// </summary>
        private void AlignEditorView()
        {
            if (!alignEditorCamera)
            {
                return;
            }

            // This creates a temporary game object in order to align the editor view.
            // The created game object is destroyed afterwards.
            GameObject tmpGo = new GameObject();

            float yCoord = cullArea.YIsUpAxis ? cullArea.Center.y : Mathf.Max(cullArea.Size.x, cullArea.Size.y);
            float zCoord = cullArea.YIsUpAxis ? -Mathf.Max(cullArea.Size.x, cullArea.Size.y) : cullArea.Center.y;

            tmpGo.transform.position = new Vector3(cullArea.Center.x, yCoord, zCoord);
            tmpGo.transform.LookAt(cullArea.transform.position);

            if (SceneView.lastActiveSceneView != null)
            {
                SceneView.lastActiveSceneView.AlignViewToObject(tmpGo.transform);
            }

            DestroyImmediate(tmpGo);
        }
    }
}