using System;
using System.Collections.Generic;
using UnityEditor.AddressableAssets.Settings;
using UnityEditor.IMGUI.Controls;
using UnityEngine;
using UnityEngine.AddressableAssets;
#if (ENABLE_CCD && UNITY_2019_4_OR_NEWER)
using Unity.Services.Ccd.Management.Models;
#endif

namespace UnityEditor.AddressableAssets.GUI
{
    internal class ProfileWindow : EditorWindow
    {
        //Min and Max proportion of the window that ProfilePane can take up
        const float k_MinProfilePaneWidth = 0.10f;
        const float k_MaxProfilePaneWidth = 0.6f;

        private const float k_MinLabelWidth = 155f;
        private const float k_ApproxCharWidth = 8.5f;

        const float k_DefaultHorizontalSplitterRatio = 0.33f;
        const int k_SplitterThickness = 2;
        const int k_ToolbarHeight = 20;
        const int k_ItemRectPadding = 15;

        //amount of padding between variable items
        const float k_VariableItemPadding = 5f;

        //Default length of the Label within the Variables Pane
        private float m_LabelWidth = 155f;
        private float m_FieldBufferWidth = 0f;

        GUIStyle m_ItemRectPadding;

        float m_HorizontalSplitterRatio = k_DefaultHorizontalSplitterRatio;

        private ProfileDataSourceSettings m_ProfileDataSource;

        internal AddressableAssetSettings settings
        {
            get { return AddressableAssetSettingsDefaultObject.Settings; }
        }

        internal ProfileDataSourceSettings dataSourceSettings
        {
            get
            {
                if (m_ProfileDataSource == null)
                    m_ProfileDataSource = ProfileDataSourceSettings.GetSettings();
                return m_ProfileDataSource;
            }
        }

        private ProfileTreeView m_ProfileTreeView;

        private bool m_IsResizingHorizontalSplitter;
        internal static bool m_Reload = false;

        private Vector2 m_ProfilesPaneScrollPosition;
        private Vector2 m_VariablesPaneScrollPosition;

        private int m_ProfileIndex = -1;

        public int ProfileIndex
        {
            get { return m_ProfileIndex; }
            set { m_ProfileIndex = value; }
        }


        private GUIStyle m_ButtonStyle;

        private GUIContent m_CreateNewProfileOrVariablesGUIContent = new GUIContent("Create", "Create a new profile or profile variable(s)");


        private Dictionary<string, bool?> m_foldouts = new Dictionary<string, bool?>();
        private Dictionary<string, bool> m_CustomGroupTypes = new Dictionary<string, bool>();

        [MenuItem("Window/Asset Management/Addressables/Profiles", priority = 2051)]
        internal static void ShowWindow()
        {
            AddressableAnalytics.ReportUsageEvent(AddressableAnalytics.UsageEventType.OpenProfilesWindow);

            var settings = AddressableAssetSettingsDefaultObject.Settings;
            if (settings == null)
            {
                EditorUtility.DisplayDialog("Error",
                    "Attempting to open Addressables Profiles window, but no Addressables Settings file exists.  \n\nOpen 'Window/Asset Management/Addressables/Groups' for more info.", "Ok");
                return;
            }

            GetWindow<ProfileWindow>().Show();
        }

        internal static void DrawOutline(Rect rect, float size)
        {
            Color color = new Color(0.6f, 0.6f, 0.6f, 1.333f);
            if (EditorGUIUtility.isProSkin)
            {
                color.r = 0.12f;
                color.g = 0.12f;
                color.b = 0.12f;
            }

            if (Event.current.type != EventType.Repaint)
                return;

            Color orgColor = UnityEngine.GUI.color;
            UnityEngine.GUI.color = UnityEngine.GUI.color * color;
            UnityEngine.GUI.DrawTexture(new Rect(rect.x, rect.y, rect.width, size), EditorGUIUtility.whiteTexture);
            UnityEngine.GUI.DrawTexture(new Rect(rect.x, rect.yMax - size, rect.width, size), EditorGUIUtility.whiteTexture);
            UnityEngine.GUI.DrawTexture(new Rect(rect.x, rect.y + 1, size, rect.height - 2 * size), EditorGUIUtility.whiteTexture);
            UnityEngine.GUI.DrawTexture(new Rect(rect.xMax - size, rect.y + 1, size, rect.height - 2 * size), EditorGUIUtility.whiteTexture);

            UnityEngine.GUI.color = orgColor;
        }

#if (ENABLE_CCD && UNITY_2019_4_OR_NEWER)
        private async void Awake()
        {
            if (CloudProjectSettings.projectId != String.Empty) await ProfileDataSourceSettings.UpdateCCDDataSourcesAsync(CloudProjectSettings.projectId, false);
        }

#endif

        private void OnEnable()
        {
            AddressableAnalytics.ReportUsageEvent(AddressableAnalytics.UsageEventType.OpenProfilesWindow, true);
            Undo.undoRedoPerformed += MarkForReload;
            titleContent = new GUIContent("Addressables Profiles");
            m_ItemRectPadding = new GUIStyle();
            m_ItemRectPadding.padding = new RectOffset(k_ItemRectPadding, k_ItemRectPadding, k_ItemRectPadding, k_ItemRectPadding);
        }

        private void OnDisable()
        {
            Undo.undoRedoPerformed -= MarkForReload;
        }

        internal static void MarkForReload()
        {
            m_Reload = true;
        }

        GUIStyle GetStyle(string styleName)
        {
            GUIStyle s = UnityEngine.GUI.skin.FindStyle(styleName);
            if (s == null)
                s = EditorGUIUtility.GetBuiltinSkin(EditorSkin.Inspector).FindStyle(styleName);
            if (s == null)
            {
                Addressables.LogError("Missing built-in guistyle " + styleName);
                s = new GUIStyle();
            }

            return s;
        }

        void TopToolbar(Rect toolbarPos)
        {
            if (m_ButtonStyle == null)
                m_ButtonStyle = GetStyle("ToolbarButton");

            m_ButtonStyle.alignment = TextAnchor.MiddleLeft;

            GUILayout.BeginArea(new Rect(0, 0, toolbarPos.width, k_ToolbarHeight));
            GUILayout.BeginHorizontal(EditorStyles.toolbar);
            {
                Rect rMode = GUILayoutUtility.GetRect(m_CreateNewProfileOrVariablesGUIContent, EditorStyles.toolbarDropDown);
                if (EditorGUI.DropdownButton(rMode, m_CreateNewProfileOrVariablesGUIContent, FocusType.Passive, EditorStyles.toolbarDropDown))
                {
                    var menu = new GenericMenu();
                    menu.AddItem(new GUIContent("Profile"), false, NewProfile);
                    menu.AddItem(new GUIContent("Variable (All Profiles)"), false, () => NewVariable(rMode));
                    menu.AddItem(new GUIContent("Build and Load Path Variables (All Profiles)"), false, () => NewPathPair(rMode));
                    menu.DropDown(rMode);
                }

                GUILayout.FlexibleSpace();
            }
            GUILayout.EndHorizontal();
            GUILayout.EndArea();
        }

        void NewVariable(Rect displayRect)
        {
            try
            {
                displayRect.y += 22f;
                PopupWindow.Show(displayRect,
                    new ProfileNewVariablePopup(position.width, position.height, 0, m_ProfileTreeView, settings));
            }
            catch (ExitGUIException)
            {
                // Exception not being caught through OnGUI call
            }
        }

        void NewPathPair(Rect displayRect)
        {
            try
            {
                displayRect.y += 22f;
                PopupWindow.Show(displayRect,
                    new ProfileNewPathPairPopup(position.width, position.height, 0, m_ProfileTreeView, settings));
            }
            catch (ExitGUIException)
            {
                // Exception not being caught through OnGUI call
            }
        }

        //Contains all of the profile names, primarily implemented in ProfileTreeView
        void ProfilesPane(Rect profilesPaneRect)
        {
            DrawOutline(profilesPaneRect, 1);
            GUILayout.BeginArea(profilesPaneRect);
            {
                m_ProfilesPaneScrollPosition = GUILayout.BeginScrollView(m_ProfilesPaneScrollPosition);
                Rect r = new Rect(profilesPaneRect);
                r.y = 0;

                var profiles = settings.profileSettings.profiles;

                if (m_ProfileTreeView == null || m_ProfileTreeView.Names.Count != profiles.Count || m_Reload)
                {
                    m_Reload = false;
                    m_ProfileTreeView = new ProfileTreeView(new TreeViewState(), profiles, this, ProfileTreeView.CreateHeader());
                }

                m_ProfileTreeView.OnGUI(r);
                GUILayout.EndScrollView();
            }
            GUILayout.EndArea();
        }

        //Displays all variables for the currently selected profile and initializes each variable's context menu
        void VariablesPane(Rect variablesPaneRect)
        {
            DrawOutline(variablesPaneRect, 1);
            Event evt = Event.current;
            AddressableAssetProfileSettings.BuildProfile selectedProfile = GetSelectedProfile();

            if (selectedProfile == null) return;
            if (evt.isMouse || evt.isKey)
            {
                m_ProfileTreeView.lastClickedProfile = ProfileIndex;
            }

            //ensures amount of visible text is not affected by label width
            float fieldWidth = variablesPaneRect.width - (2 * k_ItemRectPadding) + m_FieldBufferWidth;

            if (!EditorGUIUtility.labelWidth.Equals(m_LabelWidth))
                EditorGUIUtility.labelWidth = m_LabelWidth;

            int maxLabelLen = 0;
            int maxFieldLen = 0;

            GUILayout.BeginArea(variablesPaneRect);
            EditorGUI.indentLevel++;
            List<ProfileGroupType> groupTypes = ProfileGroupType.CreateGroupTypes(selectedProfile, settings);
            HashSet<string> drawnGroupTypes = new HashSet<string>();

            //Displaying Path Groups
            foreach (ProfileGroupType groupType in groupTypes)
            {
                bool? foldout;
                m_foldouts.TryGetValue(groupType.GroupTypePrefix, out foldout);
                GUILayout.Space(5);
                Rect pathPairRect = EditorGUILayout.BeginHorizontal(new GUILayoutOption[]
                    {GUILayout.Width(fieldWidth + k_VariableItemPadding - k_SplitterThickness), GUILayout.MinWidth(fieldWidth + k_VariableItemPadding - k_SplitterThickness)});
                m_foldouts[groupType.GroupTypePrefix] = EditorGUILayout.Foldout(foldout != null ? foldout.Value : true,
                    new GUIContent(groupType.GroupTypePrefix, "A pair of profile variables used for AssetBundles Build and Load Paths"), true);
                Rect dsDropdownRect = EditorGUILayout.BeginHorizontal(new GUILayoutOption[] {GUILayout.Width(fieldWidth - m_LabelWidth), GUILayout.MinWidth(fieldWidth - m_LabelWidth)});
                string dropdownText = DetermineOptionString(groupType);
                bool dsDropdown = EditorGUILayout.DropdownButton(new GUIContent(dropdownText, "Location type"), FocusType.Keyboard, new GUILayoutOption[] {GUILayout.Width(fieldWidth - m_LabelWidth)});
                if (evt.type == EventType.ContextClick)
                    CreatePairPrefixContextMenu(variablesPaneRect, pathPairRect, groupType, evt);

                EditorGUILayout.EndHorizontal();
                EditorGUILayout.EndHorizontal();
                DrawDataSourceDropDowns(dsDropdownRect, groupType, dsDropdown);

                //Specific Grouped variables
                List<ProfileGroupType.GroupTypeVariable> pathVariables = new List<ProfileGroupType.GroupTypeVariable>();
                pathVariables.Add(groupType.GetVariableBySuffix(AddressableAssetSettings.kBuildPath));
                drawnGroupTypes.Add(groupType.GetName(groupType.GetVariableBySuffix(AddressableAssetSettings.kBuildPath)));
                pathVariables.Add(groupType.GetVariableBySuffix(AddressableAssetSettings.kLoadPath));
                drawnGroupTypes.Add(groupType.GetName(groupType.GetVariableBySuffix(AddressableAssetSettings.kLoadPath)));


                if (m_foldouts[groupType.GroupTypePrefix].Value)
                {
                    bool custom;
                    m_CustomGroupTypes.TryGetValue(groupType.GroupTypePrefix, out custom);
                    EditorGUI.BeginDisabledGroup(!custom);

                    EditorGUI.indentLevel++;

                    //Displaying Path Groups
                    foreach (var variable in pathVariables)
                    {
                        Rect newPathRect = EditorGUILayout.BeginVertical();
                        string newPath = EditorGUILayout.TextField(new GUIContent(groupType.GetName(variable), "Profile variable representing a file path or url"), variable.Value,
                            new GUILayoutOption[] {GUILayout.Width(fieldWidth)});
                        EditorGUILayout.EndVertical();
                        if (newPath != variable.Value && ProfileIndex == m_ProfileTreeView.lastClickedProfile)
                        {
                            Undo.RecordObject(settings, "Variable value changed");
                            settings.profileSettings.SetValue(selectedProfile.id, groupType.GetName(variable), newPath);
                            AddressableAssetUtility.OpenAssetIfUsingVCIntegration(settings);
                        }
                    }

                    EditorGUI.indentLevel--;

                    EditorGUI.EndDisabledGroup();
                }
            }

            //Display all other variables
            for (var i = 0; i < settings.profileSettings.profileEntryNames.Count; i++)
            {
                AddressableAssetProfileSettings.ProfileIdData curVariable = settings.profileSettings.profileEntryNames[i];
                if (!drawnGroupTypes.Contains(curVariable.ProfileName))
                {
                    GUILayout.Space(5);
                    Rect newValueRect = EditorGUILayout.BeginVertical();
                    string newValue = EditorGUILayout.TextField(new GUIContent(curVariable.ProfileName, "Profile variable"), selectedProfile.values[i].value,
                        new GUILayoutOption[] {GUILayout.Width(fieldWidth)});
                    EditorGUILayout.EndVertical();
                    if (newValue != selectedProfile.values[i].value && ProfileIndex == m_ProfileTreeView.lastClickedProfile)
                    {
                        Undo.RecordObject(settings, "Variable value changed");
                        settings.profileSettings.SetValue(selectedProfile.id, settings.profileSettings.profileEntryNames[i].ProfileName, newValue);
                        AddressableAssetUtility.OpenAssetIfUsingVCIntegration(settings);
                    }

                    if (evt.type == EventType.ContextClick)
                    {
                        CreateVariableContextMenu(variablesPaneRect, newValueRect, curVariable, evt);
                    }
                }

                maxLabelLen = Math.Max(maxLabelLen, curVariable.ProfileName.Length);
            }

            EditorGUI.indentLevel--;
            GUILayout.EndArea();

            //Update the label width to the maximum of the minimum acceptable label width and the amount of
            //space required to contain the longest variable name
            m_LabelWidth = Mathf.Max(maxLabelLen * k_ApproxCharWidth, k_MinLabelWidth);
            m_FieldBufferWidth = Mathf.Clamp((maxFieldLen * k_ApproxCharWidth) - fieldWidth, 0f, float.MaxValue);
        }

        void DrawDataSourceDropDowns(Rect dsDropdownRect, ProfileGroupType groupType, bool showDropdown)
        {
            Rect fixedDropdownRect = new Rect(
                //Determine correct position for dropdown window
                new Vector2(
                    dsDropdownRect.x,
                    dsDropdownRect.y
                ),
                new Vector2(dsDropdownRect.width, 120)
            );

            if (showDropdown)
            {
                ProfileDataSourceDropdownWindow dataSourceDropdownWindow = new ProfileDataSourceDropdownWindow(fixedDropdownRect, groupType);
                //TODO: Add Event Handler Here
                dataSourceDropdownWindow.ValueChanged += DataSourceDropdownValueChanged;
                PopupWindow.Show(dsDropdownRect, dataSourceDropdownWindow);
            }
        }

        internal void DataSourceDropdownValueChanged(object sender, ProfileDataSourceDropdownWindow.DropdownWindowEventArgs e)
        {
            m_CustomGroupTypes[e.GroupType.GroupTypePrefix] = e.IsCustom;
            if (!e.IsCustom)
            {
                var selectedProfile = GetSelectedProfile();
                Undo.RecordObject(settings, "Variable value changed");
                settings.profileSettings.SetValue(selectedProfile.id, e.GroupType.GetName(e.GroupType.GetVariableBySuffix(AddressableAssetSettings.kBuildPath)), e.Option.BuildPath);
                settings.profileSettings.SetValue(selectedProfile.id, e.GroupType.GetName(e.GroupType.GetVariableBySuffix(AddressableAssetSettings.kLoadPath)), e.Option.LoadPath);
                AddressableAssetUtility.OpenAssetIfUsingVCIntegration(settings);
            }
        }

        private string DetermineOptionString(ProfileGroupType groupType)
        {
            ProfileGroupType selectedGroupType = dataSourceSettings.FindGroupType(groupType);
            if (selectedGroupType != null)
            {
                bool custom;
                m_CustomGroupTypes.TryGetValue(groupType.GroupTypePrefix, out custom);
                if (custom && ProfileIndex == m_ProfileTreeView.lastClickedProfile)
                    return "Custom";
                m_CustomGroupTypes[groupType.GroupTypePrefix] = false;

#if (ENABLE_CCD && UNITY_2019_4_OR_NEWER)
                //Could ERR if user has group type prefix that starts with CCD
                if (selectedGroupType.GroupTypePrefix.StartsWith("CCD", StringComparison.Ordinal))
                {
                    var parts = selectedGroupType.GroupTypePrefix.Split(ProfileGroupType.k_PrefixSeparator);
                    var badgeName = String.Join(ProfileGroupType.k_PrefixSeparator.ToString(), parts, 4, parts.Length - 4);
                    var bucketName = selectedGroupType.GetVariableBySuffix($"{nameof(CcdBucket)}{nameof(CcdBucket.Name)}").Value;
                    var environmentName = selectedGroupType.GetVariableBySuffix($"{nameof(ProfileDataSourceSettings.Environment)}{nameof(ProfileDataSourceSettings.Environment.name)}").Value;
                    return String.Join(ProfileGroupType.k_PrefixSeparator.ToString(), new string[]
                    {
                        "CCD",
                        environmentName,
                        bucketName,
                        badgeName
                    });
                }


                if (selectedGroupType.GroupTypePrefix == AddressableAssetSettings.CcdManagerGroupTypePrefix)
                {
                    return $"{selectedGroupType.GroupTypePrefix} ({m_ProfileDataSource.currentEnvironment.name})";
                }
#endif
                return selectedGroupType.GroupTypePrefix;
            }
            else
            {
                m_CustomGroupTypes[groupType.GroupTypePrefix] = true;
                return "Custom";
            }
        }

        void CreatePairPrefixContextMenu(Rect parentWindow, Rect menuRect, ProfileGroupType groupType, Event evt)
        {
            if (menuRect.Contains(evt.mousePosition))
            {
                GenericMenu menu = new GenericMenu();
                menu.AddDisabledItem(new GUIContent(groupType.GroupTypePrefix));
                menu.AddSeparator("");
                menu.AddItem(new GUIContent("Rename Path Prefix (All Profiles)"), false, () => { RenamePathPair(groupType, parentWindow, menuRect); });
                menu.AddItem(new GUIContent("Delete Path Pair (All Profiles)"), false, () => { DeletePathPair(groupType); });
                menu.ShowAsContext();
                evt.Use();
            }
        }

        //Creates the context menu for the selected variable
        void CreateVariableContextMenu(Rect parentWindow, Rect menuRect, AddressableAssetProfileSettings.ProfileIdData variable, Event evt)
        {
            if (menuRect.Contains(evt.mousePosition))
            {
                GenericMenu menu = new GenericMenu();
                //Displays name of selected variable so user can be confident they're deleting/renaming the right one
                menu.AddDisabledItem(new GUIContent(variable.ProfileName));
                menu.AddSeparator("");
                menu.AddItem(new GUIContent("Rename Variable (All Profiles)"), false, () => { RenameVariable(variable, parentWindow, menuRect); });
                menu.AddItem(new GUIContent("Delete Variable (All Profiles)"), false, () => { DeleteVariable(variable); });
                menu.ShowAsContext();
                evt.Use();
            }
        }

        void RenamePathPair(ProfileGroupType groupType, Rect parentWindow, Rect displayRect)
        {
            try
            {
                //Determines the current variable rect location
                Rect variableRect = new Rect(parentWindow.x + 2.5f, displayRect.y + 1.5f, m_LabelWidth, k_ToolbarHeight * 2);
                PopupWindow.Show(variableRect, new PathPairRenamePopup(m_LabelWidth, groupType, settings));
            }
            catch (ExitGUIException)
            {
                // Exception not being caught through OnGUI call
            }
        }

        //Opens ProfileRenameVariablePopup
        void RenameVariable(AddressableAssetProfileSettings.ProfileIdData profileVariable, Rect parentWindow, Rect displayRect)
        {
            try
            {
                //Determines the current variable rect location
                Rect variableRect = new Rect(parentWindow.x + 2.5f, displayRect.y + 1.5f, m_LabelWidth, k_ToolbarHeight * 2);
                PopupWindow.Show(variableRect, new ProfileRenameVariablePopup(m_LabelWidth, profileVariable, settings));
            }
            catch (ExitGUIException)
            {
                // Exception not being caught through OnGUI call
            }
        }

        void DeletePathPair(ProfileGroupType groupType)
        {
            var buildPathData = settings.profileSettings.GetProfileDataByName(groupType.GroupTypePrefix + ProfileGroupType.k_PrefixSeparator + AddressableAssetSettings.kBuildPath);
            var loadPathData = settings.profileSettings.GetProfileDataByName(groupType.GroupTypePrefix + ProfileGroupType.k_PrefixSeparator + AddressableAssetSettings.kLoadPath);
            if (loadPathData == default(AddressableAssetProfileSettings.ProfileIdData) || buildPathData == default(AddressableAssetProfileSettings.ProfileIdData))
            {
                Debug.LogError("An error occured while getting one of the path pair variables.");
                return;
            }

            Undo.RecordObject(settings, "Profile Variable Deleted");
            settings.profileSettings.RemoveValue(buildPathData.Id);
            settings.profileSettings.RemoveValue(loadPathData.Id);
            AddressableAssetUtility.OpenAssetIfUsingVCIntegration(settings);
        }

        void DeleteVariable(AddressableAssetProfileSettings.ProfileIdData toBeDeleted)
        {
            Undo.RecordObject(settings, "Profile Variable Deleted");
            settings.profileSettings.RemoveValue(toBeDeleted.Id);
            AddressableAssetUtility.OpenAssetIfUsingVCIntegration(settings);
        }

        //Returns the BuildProfile currently selected in the ProfilesPane
        AddressableAssetProfileSettings.BuildProfile GetSelectedProfile()
        {
            return m_ProfileTreeView.GetSelectedProfile();
        }

        //Creates a new BuildProfile and reloads the ProfilesPane
        void NewProfile()
        {
            var uniqueProfileName = settings.profileSettings.GetUniqueProfileName("New Profile");
            if (!string.IsNullOrEmpty(uniqueProfileName))
            {
                Undo.RecordObject(settings, "New Profile Created");
                //Either copy values from the selected profile, or if there is no selected profile, copy from the default
                string idToCopyFrom = GetSelectedProfile() != null
                    ? GetSelectedProfile().id
                    : settings.profileSettings.profiles[0].id;
                settings.profileSettings.AddProfile(uniqueProfileName, idToCopyFrom);
                AddressableAssetUtility.OpenAssetIfUsingVCIntegration(settings);
                m_ProfileTreeView.Reload();
            }
        }

        private void OnGUI()
        {
            if (settings == null) return;

            if (m_IsResizingHorizontalSplitter)
                m_HorizontalSplitterRatio = Mathf.Clamp(Event.current.mousePosition.x / position.width,
                    k_MinProfilePaneWidth, k_MaxProfilePaneWidth);

            var toolbarRect = new Rect(0, 0, position.width, position.height);
            var profilesPaneRect = new Rect(0, k_ToolbarHeight, (position.width * m_HorizontalSplitterRatio), position.height);
            var variablesPaneRect = new Rect(profilesPaneRect.width + k_SplitterThickness, k_ToolbarHeight,
                position.width - profilesPaneRect.width - k_SplitterThickness, position.height - k_ToolbarHeight);
            var horizontalSplitterRect = new Rect(profilesPaneRect.width, k_ToolbarHeight, k_SplitterThickness, position.height - k_ToolbarHeight);

            EditorGUIUtility.AddCursorRect(horizontalSplitterRect, MouseCursor.ResizeHorizontal);
            if (Event.current.type == EventType.MouseDown && horizontalSplitterRect.Contains(Event.current.mousePosition))
                m_IsResizingHorizontalSplitter = true;
            else if (Event.current.type == EventType.MouseUp)
                m_IsResizingHorizontalSplitter = false;

            TopToolbar(toolbarRect);

            ProfilesPane(profilesPaneRect);

            VariablesPane(variablesPaneRect);

            if (m_IsResizingHorizontalSplitter)
                Repaint();
        }

        class PathPairRenamePopup : PopupWindowContent
        {
            internal Rect m_WindowRect;
            internal ProfileGroupType m_ProfileGroupType;
            internal List<ProfileGroupType> m_AllProfileGroupTypes;
            internal AddressableAssetSettings m_Settings;
            internal string m_NewName;
            internal float m_LabelWidth;

            public PathPairRenamePopup(float labelWidth, ProfileGroupType profileGroupType, AddressableAssetSettings settings)
            {
                m_LabelWidth = labelWidth;
                m_ProfileGroupType = profileGroupType;
                m_Settings = settings;
                m_NewName = profileGroupType.GroupTypePrefix;
                UnityEngine.GUI.enabled = true;
            }

            public override Vector2 GetWindowSize()
            {
                return new Vector2(m_LabelWidth, 40);
            }

            public override void OnGUI(Rect windowRect)
            {
                GUILayout.BeginArea(windowRect);

                Event evt = Event.current;
                bool hitEnter = evt.type == EventType.KeyDown && (evt.keyCode == KeyCode.Return || evt.keyCode == KeyCode.KeypadEnter);

                m_NewName = GUILayout.TextField(m_NewName);
                if (GUILayout.Button("Save") || hitEnter)
                {
                    if (string.IsNullOrEmpty(m_NewName))
                        Debug.LogError("Path pair prefix cannot be empty.");
                    else if (m_NewName == m_ProfileGroupType.GroupTypePrefix)
                        editorWindow.Close();
                    else if (VariableWithNewPrefixAlreadyExists())
                        Debug.LogError("One or more build or load path variables with prefix '" + m_NewName + "' already exist. Please rename them or pick a different prefix.");
                    else if (m_NewName.Trim().Length == 0) // new name cannot only contain spaces
                        Debug.LogError("Path pair prefix cannot be only spaces");
                    else
                    {
                        var loadPathVariableData =
                            m_Settings.profileSettings.GetProfileDataByName(m_ProfileGroupType.GroupTypePrefix + ProfileGroupType.k_PrefixSeparator + AddressableAssetSettings.kLoadPath);
                        var buildPathVariableData =
                            m_Settings.profileSettings.GetProfileDataByName(m_ProfileGroupType.GroupTypePrefix + ProfileGroupType.k_PrefixSeparator + AddressableAssetSettings.kBuildPath);
                        if (loadPathVariableData == default(AddressableAssetProfileSettings.ProfileIdData) || buildPathVariableData == default(AddressableAssetProfileSettings.ProfileIdData))
                            Debug.LogError("Valid path pair to rename not found.");
                        else
                        {
                            Undo.RecordObject(m_Settings, "Path pair prefix Renamed");
                            m_ProfileGroupType.GroupTypePrefix = m_NewName;
                            loadPathVariableData.SetName(m_ProfileGroupType.GroupTypePrefix + ProfileGroupType.k_PrefixSeparator + AddressableAssetSettings.kLoadPath, m_Settings.profileSettings);
                            buildPathVariableData.SetName(m_ProfileGroupType.GroupTypePrefix + ProfileGroupType.k_PrefixSeparator + AddressableAssetSettings.kBuildPath, m_Settings.profileSettings);
                            AddressableAssetUtility.OpenAssetIfUsingVCIntegration(m_Settings, true);
                            editorWindow.Close();
                        }
                    }
                }

                GUILayout.EndArea();
            }

            bool VariableWithNewPrefixAlreadyExists()
            {
                bool loadPathAlreadyExists = m_Settings.profileSettings.GetProfileDataByName(m_NewName + ProfileGroupType.k_PrefixSeparator + AddressableAssetSettings.kLoadPath)
                                             != default(AddressableAssetProfileSettings.ProfileIdData);
                bool buildPathAlreadyExists = m_Settings.profileSettings.GetProfileDataByName(m_NewName + ProfileGroupType.k_PrefixSeparator + AddressableAssetSettings.kBuildPath)
                                              != default(AddressableAssetProfileSettings.ProfileIdData);
                return loadPathAlreadyExists || buildPathAlreadyExists;
            }
        }

        class ProfileRenameVariablePopup : PopupWindowContent
        {
            internal float m_LabelWidth;
            internal AddressableAssetProfileSettings.ProfileIdData m_ProfileVariable;
            internal AddressableAssetSettings m_Settings;
            internal string m_NewName;

            public ProfileRenameVariablePopup(float labelWidth, AddressableAssetProfileSettings.ProfileIdData profileVariable, AddressableAssetSettings settings)
            {
                m_LabelWidth = labelWidth;
                m_ProfileVariable = profileVariable;
                m_Settings = settings;
                m_NewName = m_ProfileVariable.ProfileName;
                UnityEngine.GUI.enabled = true;
            }

            public override Vector2 GetWindowSize()
            {
                return new Vector2(m_LabelWidth, 40);
            }

            public override void OnGUI(Rect windowRect)
            {
                GUILayout.BeginArea(windowRect);

                Event evt = Event.current;
                bool hitEnter = evt.type == EventType.KeyDown && (evt.keyCode == KeyCode.Return || evt.keyCode == KeyCode.KeypadEnter);

                m_NewName = GUILayout.TextField(m_NewName);
                if (GUILayout.Button("Save") || hitEnter)
                {
                    if (string.IsNullOrEmpty(m_NewName))
                        Debug.LogError("Variable name cannot be empty.");
                    else if (m_NewName == m_ProfileVariable.ProfileName)
                        editorWindow.Close();
                    else if (m_NewName != m_Settings.profileSettings.GetUniqueProfileEntryName(m_NewName))
                        Debug.LogError("Profile variable '" + m_NewName + "' already exists.");
                    else if (m_NewName.Trim().Length == 0) // new name cannot only contain spaces
                        Debug.LogError("Name cannot be only spaces");
                    else
                    {
                        Undo.RecordObject(m_Settings, "Profile Variable Renamed");
                        m_ProfileVariable.SetName(m_NewName, m_Settings.profileSettings);
                        AddressableAssetUtility.OpenAssetIfUsingVCIntegration(m_Settings, true);
                        editorWindow.Close();
                    }
                }

                GUILayout.EndArea();
            }
        }


        class ProfileNewVariablePopup : PopupWindowContent
        {
            internal float m_WindowWidth;
            internal float m_WindowHeight;
            internal float m_xOffset;
            internal string m_Name;
            internal string m_Value;
            internal bool m_NeedsFocus = true;
            internal AddressableAssetSettings m_Settings;

            ProfileTreeView m_ProfileTreeView;

            public ProfileNewVariablePopup(float width, float height, float xOffset, ProfileTreeView profileTreeView, AddressableAssetSettings settings)
            {
                m_WindowWidth = width;
                m_WindowHeight = height;
                m_xOffset = xOffset;
                m_Settings = settings;
                m_Name = m_Settings.profileSettings.GetUniqueProfileEntryName("New Entry");
                m_Value = Application.dataPath;

                m_ProfileTreeView = profileTreeView;
            }

            public override Vector2 GetWindowSize()
            {
                float width = Mathf.Clamp(m_WindowWidth * 0.375f, Mathf.Min(600, m_WindowWidth - m_xOffset), m_WindowWidth);
                float height = Mathf.Clamp(65, Mathf.Min(65, m_WindowHeight), m_WindowHeight);
                return new Vector2(width, height);
            }

            public override void OnGUI(Rect windowRect)
            {
                GUILayout.Space(5);
                Event evt = Event.current;
                bool hitEnter = evt.type == EventType.KeyDown && (evt.keyCode == KeyCode.Return || evt.keyCode == KeyCode.KeypadEnter);
                EditorGUIUtility.labelWidth = 90;
                m_Name = EditorGUILayout.TextField("Variable Name", m_Name);
                m_Value = EditorGUILayout.TextField("Default Value", m_Value);

                UnityEngine.GUI.enabled = m_Name.Length != 0;
                if (GUILayout.Button("Save") || hitEnter)
                {
                    if (string.IsNullOrEmpty(m_Name))
                        Debug.LogError("Variable name cannot be empty.");
                    else if (m_Name != m_Settings.profileSettings.GetUniqueProfileEntryName(m_Name))
                        Debug.LogError("Profile variable '" + m_Name + "' already exists.");
                    else
                    {
                        Undo.RecordObject(m_Settings, "Profile Variable " + m_Name + " Created");
                        m_Settings.profileSettings.CreateValue(m_Name, m_Value);
                        AddressableAssetUtility.OpenAssetIfUsingVCIntegration(m_Settings);
                        m_ProfileTreeView.Reload();
                        editorWindow.Close();
                    }
                }
            }
        }

        class ProfileNewPathPairPopup : PopupWindowContent
        {
            internal float m_WindowWidth;
            internal float m_WindowHeight;
            internal float m_xOffset;
            internal string m_Name;
            internal string m_BuildPath;
            internal string m_LoadPath;
            internal bool m_NeedsFocus = true;
            internal AddressableAssetSettings m_Settings;

            ProfileTreeView m_ProfileTreeView;

            public ProfileNewPathPairPopup(float width, float height, float xOffset, ProfileTreeView profileTreeView, AddressableAssetSettings settings)
            {
                m_WindowWidth = width;
                m_WindowHeight = height;
                m_xOffset = xOffset;
                m_Settings = settings;
                m_Name = m_Settings.profileSettings.GetUniqueProfileEntryName("New Entry");
                m_BuildPath = Application.dataPath;
                m_LoadPath = Application.dataPath;

                m_ProfileTreeView = profileTreeView;
            }

            public override Vector2 GetWindowSize()
            {
                float width = Mathf.Clamp(m_WindowWidth * 0.375f, Mathf.Min(600, m_WindowWidth - m_xOffset), m_WindowWidth);
                float height = Mathf.Clamp(85, Mathf.Min(85, m_WindowHeight), m_WindowHeight);
                return new Vector2(width, height);
            }

            public override void OnGUI(Rect windowRect)
            {
                GUILayout.Space(5);
                Event evt = Event.current;
                bool hitEnter = evt.type == EventType.KeyDown && (evt.keyCode == KeyCode.Return || evt.keyCode == KeyCode.KeypadEnter);
                EditorGUIUtility.labelWidth = 120;
                m_Name = EditorGUILayout.TextField("Prefix Name", m_Name);
                m_BuildPath = EditorGUILayout.TextField("Build Path Value", m_BuildPath);
                m_LoadPath = EditorGUILayout.TextField("Load Path Value", m_LoadPath);

                UnityEngine.GUI.enabled = m_Name.Length != 0;
                if (GUILayout.Button("Save") || hitEnter)
                {
                    string buildPathName = m_Name + ProfileGroupType.k_PrefixSeparator + AddressableAssetSettings.kBuildPath;
                    string loadPathName = m_Name + ProfileGroupType.k_PrefixSeparator + AddressableAssetSettings.kLoadPath;
                    if (string.IsNullOrEmpty(m_Name))
                        Debug.LogError("Variable name cannot be empty.");
                    else if (buildPathName != m_Settings.profileSettings.GetUniqueProfileEntryName(buildPathName))
                        Debug.LogError("Profile variable '" + buildPathName + "' already exists.");
                    else if (loadPathName != m_Settings.profileSettings.GetUniqueProfileEntryName(loadPathName))
                        Debug.LogError("Profile variable '" + loadPathName + "' already exists.");
                    else
                    {
                        Undo.RecordObject(m_Settings, "Profile Path Pair Created");
                        m_Settings.profileSettings.CreateValue(buildPathName, m_BuildPath);
                        m_Settings.profileSettings.CreateValue(loadPathName, m_LoadPath);
                        AddressableAssetUtility.OpenAssetIfUsingVCIntegration(m_Settings);
                        m_ProfileTreeView.Reload();
                        editorWindow.Close();
                    }
                }
            }
        }
    }
}