//////////////////////////////////////////////////////////////////////////
//Created by Neodrop. neodrop@unity3d.ru
//////////////////////////////////////////////////////////////////////////
using UnityEngine;
using System.Collections;
using UnityEditor;
using System.IO;
using System.Collections.Generic;
using System.Text.RegularExpressions;

public class AntaresEdMainWindow : AntaresEdWindow {
    public static AntaresEdMainWindow window;

    [MenuItem("Antares/Open Antares Browser")]
    static void CreateWindow()
    {
        AntInit();        
        window = (AntaresEdMainWindow)EditorWindow.GetWindow(typeof(AntaresEdMainWindow));

        window.wantsMouseMove = true;
        window.title = Lang("Antares Project Browser");
        window.autoRepaintOnSceneChange = true;
        window.minSize = new Vector2(800, 600);
        window.Show();
        window.ShowUtility();
    }

    void OnEnable()
    {
        thisScript = this;
        AntInit();
    }

    void OnGUI()
    {
        if (EditorApplication.isCompiling) return;
        try
        {
            switch (DrawUpSideBar())
            {
                case 0:
                    GetObjectWithScriptTab();
                    break;
                case 1:
                    AssetsTab();
                    break;
                case 6:
                    break;
            }
            if (window != null)
            {
                AntaresGameObjectCustom.Routines.DrawBackground(new Rect(window.position.width - 512, window.position.height - 512, 512,
                                                                512));
                AntaresGameObjectCustom.Routines.ShowCredits(new Rect(window.position.width - 120, 1, 100, 32));
            }
        }
        catch { }
    }

    private static GUIContent[] iconHolder = null;
    private static bool monoScriptLastUpdateTime = false;
    private static MonoScript[] monoScriptHolder;
    private static MonoScript monoScriptLastSelected = null;
    private static GUIContent monoScriptLastSelectedContent;
    private static GameObject[] monoScriptParents;
    private static bool monoScriptCS = true, monoScriptJS = true, monoScriptIgnoreAntares = true;
    private static int monoScriptCurrentLineCount = 0;
    static readonly int thumbsAndFilds = 25;
    void GetObjectWithScriptTab()
    {
        int leftFieldWidth = 400, refreshButtonWidth = 64;

        int count;
        System.Type type = typeof(MonoScript);

#region // Кнопки контроля. Refresh, Current Object, etc.
        GUILayout.Space(15);
        GUILayout.BeginHorizontal();
        if (GUILayout.Button(Lang("Refresh"), GUILayout.Width(refreshButtonWidth))) monoScriptLastUpdateTime = false;

        GUILayout.BeginHorizontal(GUILayout.Width(128));
        GUILayout.Space(5);
        monoScriptCS = GUILayout.Toggle(monoScriptCS,"*.cs");
        if (GUI.changed) monoScriptLastUpdateTime = false;
        monoScriptJS = GUILayout.Toggle(monoScriptJS, "*.js");
        if (GUI.changed) monoScriptLastUpdateTime = false;
        GUILayout.Space(15);
        monoScriptIgnoreAntares = GUILayout.Toggle(monoScriptIgnoreAntares, Lang("Ignore Antares Scripts"));
        if (GUI.changed) monoScriptLastUpdateTime = false;
        GUILayout.EndHorizontal();

        GUILayout.Space(25);
        bool forceUpdateList = false;
        if (monoScriptLastSelected != null)
        {
            GUILayout.Space(-70);
            monoScriptLastSelected = EditorGUILayout.ObjectField(monoScriptLastSelectedContent, monoScriptLastSelected, type, GUILayout.Width(256), GUILayout.Height(20)) as MonoScript;
            if (GUI.changed)
            {
                monoScriptLastUpdateTime = false;
                forceUpdateList = true;

                monoScriptCurrentLineCount = ProcessFile(AssetDatabase.GetAssetPath(monoScriptLastSelected.GetInstanceID()));
            }
            GUILayout.Label(Lang("Lines Count : ") + monoScriptCurrentLineCount);
        }
        
        GUILayout.EndHorizontal();
        GUILayout.Space(5);
#endregion
#region // Перерасчёт

        if (!monoScriptLastUpdateTime)
        {
            if (monoScriptCS && monoScriptJS)
            {
                monoScriptHolder = Search(true, monoScriptIgnoreAntares).ToArray(typeof(MonoScript)) as MonoScript[];
            }
            else if (monoScriptCS)
            {
                totalLinesCount = totalSharpLinesCount;// totalJSlinesCount;
                monoScriptHolder = Search("*.cs", monoScriptIgnoreAntares).ToArray(typeof(MonoScript)) as MonoScript[];
            }
            else if (monoScriptJS)
            {
                totalLinesCount = totalJSlinesCount;// totalSharpLinesCount;
                monoScriptHolder = Search("*.js", monoScriptIgnoreAntares).ToArray(typeof(MonoScript)) as MonoScript[];
            }
            else
            {
                monoScriptHolder = null;
                return;
            }
            
            if (forceUpdateList)
            {
                if (monoScriptLastSelected.GetClass().BaseType == typeof(System.Object)) monoScriptParents = null;
                else
                {
                    Object[] arr = new Object[0];
                    if (monoScriptLastSelected.GetType().IsSubclassOf(typeof(MonoBehaviour)))arr = GameObject.FindObjectsOfType(monoScriptLastSelected.GetClass());
                    int c = arr.Length;

                    monoScriptParents = new GameObject[c];
                    for (int o = 0; o < c; o++)
                    {
                        MonoBehaviour go = arr[o] as MonoBehaviour;
                        monoScriptParents[o] = go.gameObject;
                    }
                }
            }
            monoScriptLastUpdateTime = true;
            int holdCount = monoScriptHolder.Length;
            iconHolder = new GUIContent[holdCount];
            for (int i = 0; i < holdCount; i++ ) iconHolder[i] = new GUIContent(AssetDatabase.GetCachedIcon(AssetDatabase.GetAssetPath(monoScriptHolder[i])));
        }
#endregion

        EditorGUILayout.BeginHorizontal();

        scrolls["1-1"] = EditorGUILayout.BeginScrollView((Vector2)scrolls["1-1"], false, false,
            genericEditorSkin.horizontalScrollbar,genericEditorSkin.verticalScrollbar,genericEditorSkin.box, GUILayout.Width(leftFieldWidth));

        count = monoScriptHolder.Length;

#region // Отображение найденных скриптов и кнопок
        Color col = GUI.color;
        for(int i = 0; i < count; i++)
        {
            EditorGUILayout.BeginHorizontal();
            GUILayout.Space(-80);
            MonoScript obj = EditorGUILayout.ObjectField(iconHolder[i], monoScriptHolder[i], type, GUILayout.Height(thumbsAndFilds)) as MonoScript;
            string addStr = Lang("search");
            if (monoScriptLastSelected == obj)
            {
                addStr = Lang("chosen");
                GUI.color = Color.Lerp(Color.cyan, Color.white, .75f);  
            }
            
            if (GUILayout.Button( addStr, GUILayout.Width(64)))
            {
                monoScriptLastSelected = obj;
                monoScriptLastSelectedContent = iconHolder[i];
                if (obj == null)
                {
                    monoScriptLastUpdateTime = false;
                    EditorGUILayout.EndHorizontal();
                    return;
                }
                monoScriptCurrentLineCount = ProcessFile(AssetDatabase.GetAssetPath(monoScriptLastSelected.GetInstanceID()));
                System.Type classType = obj.GetClass();

                Object[] arr = null;

                if (classType.IsSubclassOf(typeof(MonoBehaviour)))
            	arr = GameObject.FindObjectsOfType(obj.GetClass());
                else arr = new Object[0];
                int c = arr.Length;

                monoScriptParents = new GameObject[c];
                for (int o = 0; o < c; o++)
                {
                    MonoBehaviour go = arr[o] as MonoBehaviour;
                    monoScriptParents[o] = go.gameObject;
                }
            }
            GUI.color = col;
            EditorGUILayout.EndHorizontal();
        }
#region // Вывод статистики по скриптам.
        GUILayout.Label(Lang("Total C# lines count : ") + totalSharpLinesCount);
        GUILayout.Label(Lang("Total JavaScript lines count : ") + totalJSlinesCount);
        GUILayout.Label(Lang("Total scripts lines count : ") + totalLinesCount);
        GUILayout.Label(Lang("Total scripts count : ") + monoScriptHolder.Length);
#endregion
#endregion

        EditorGUILayout.EndScrollView();

        scrolls["1-2"] = EditorGUILayout.BeginScrollView((Vector2)scrolls["1-2"], false, false,
            genericEditorSkin.horizontalScrollbar, genericEditorSkin.verticalScrollbar, genericEditorSkin.box);
#region // Отображение списка объектов, использующих выбраный скрипт. 

        if (monoScriptParents != null)
        {
            count = monoScriptParents.Length;
            if (count > 0 && GUILayout.Button(Lang("Select All"), GUILayout.Width(80)))
            {
                Object[] objs = new Object[count];
                for (int i = 0; i < count; i++)
                {
                    objs[i] = monoScriptParents[i];
                    EditorGUIUtility.PingObject(objs[i]);
                }
                Selection.objects = objs;
            }
            
            type = typeof(GameObject);

            for (int i = 0; i < count; i++)
            {
                EditorGUILayout.BeginHorizontal();
                Object obj = EditorGUILayout.ObjectField(monoScriptParents[i], type, GUILayout.Height(thumbsAndFilds), GUILayout.Width(256));

                if(GUILayout.Button(EditorUtility.GetMiniThumbnail(obj), GUILayout.Width(thumbsAndFilds), GUILayout.Height(thumbsAndFilds)))
                {  
                    EditorGUIUtility.PingObject(obj);
                    Selection.activeGameObject = obj as GameObject;
                }

                EditorGUILayout.EndHorizontal();
            }
        }
#endregion
        EditorGUILayout.EndScrollView();

        EditorGUILayout.EndHorizontal();
    }

    public enum AssetTab
    {
        NONE,
        Export,
        FindAssets
    }

    public class ExportedOptions
    {
        public bool allTabConteined = false;
        public Object obj;
        public bool selectDependencies = true;
        public bool markedToSave = false;
        public string path;
        public GUIContent icon = new GUIContent();
        public System.Type type;
        public bool underFouldoutOpen = false;
        public List<ExportedOptions> textureMaterals = null;

        internal void ShowGUI()
        {
            GUILayout.BeginHorizontal();
            GUILayout.Space(-60);
            EditorGUILayout.ObjectField(icon, obj, type, GUILayout.Height(thumbsAndFilds));
            if (markedToSave)
            {
                GUI.color = colorSelected;
                if (GUILayout.Button(">>", GUILayout.Width(32)))
                {
                    markedToSave = false;
                }
                GUI.color = colorGUI;
            }
            else
            {
                if (GUILayout.Button("<<", GUILayout.Width(32))) markedToSave = true;
            }
            GUILayout.EndHorizontal();
        }

        internal void ShowTexturesGUI()
        {
            int matCount = 0;
            if (textureMaterals != null) matCount = textureMaterals.Count;
            EditorGUILayout.BeginVertical();

            EditorGUILayout.ObjectField(icon, obj, type, GUILayout.Height(thumbsAndFilds));
            if(GUILayoutUtility.GetLastRect().Contains( Event.current.mousePosition ))
            {
                if (Event.current.button == 1) Selection.activeObject = obj;
                else if (Event.current.type == EventType.MouseDrag)
                {
                    // Clear out drag data
                    DragAndDrop.PrepareStartDrag ();

                    // Set up what we want to drag
                    DragAndDrop.objectReferences = new Object[] { obj };

                    // Start the actual drag
                    DragAndDrop.StartDrag ("Dragging title");

                    // Make sure no one uses the event after us
                    Event.current.Use();
                    
                    DragAndDrop.visualMode = DragAndDropVisualMode.Link;
                }
            }
            else if (Event.current.type == EventType.DragUpdated || Event.current.type == EventType.DragPerform)
            {
                // Show a copy icon on the drag
                DragAndDrop.visualMode = DragAndDropVisualMode.Link;

                if (Event.current.type == EventType.DragPerform)
                    DragAndDrop.AcceptDrag();

                Event.current.Use();
            }

            EditorGUILayout.BeginHorizontal();
            GUILayout.Space(80);
            if (matCount > 0)
                underFouldoutOpen = EditorGUILayout.Foldout(underFouldoutOpen, Lang("Materials") + " (" + matCount + ")");
            EditorGUILayout.EndHorizontal();
            if (underFouldoutOpen) ShowMaterials(matCount);

            EditorGUILayout.EndVertical();
        }

        internal void ShowMaterials(int matCount)
        {
            if (textureMaterals == null) return;

            for (int i = 0; i < matCount; i++ )
            {
                ExportedOptions mat = textureMaterals[i];
                EditorGUILayout.ObjectField(mat.icon, mat.obj, mat.type, GUILayout.MaxWidth(400));
            }
        }

        internal void ShowGUIRight()
        {
            if (!markedToSave) return;
            GUILayout.BeginHorizontal();
            if (GUILayout.Button("<<", GUILayout.Width(32))) markedToSave = false;
            GUILayout.Space(-50);
            EditorGUILayout.ObjectField(icon, obj, type, GUILayout.Height(thumbsAndFilds));
            GUILayout.EndHorizontal();
            assetsVar.totalAssObjectSelected++;
        }

        internal void ShowGUIRight(int index)
        {
            if (index != 0) ShowGUIRight();
        }
    }

    public class AssetsVar
    {
        public int exportButtonWidth = 64;
        public int totalAssObjectsCount = 0, totalAssObjectSelected = 0, totalTexturesCount = 0, totalMaterialsCount = 0;
        public bool exportedObjectsFound = false;
        public AssetTab choosenTab = AssetTab.Export;
        public Hashtable filesInProject = null, texturesInProject = null, materialsInProject = null;
        public bool exportExtPrefab = true, exportExtFBX = true, collectDependencies = true;
        public enum FindAssetsMode
        {
            Textures,
            Materials
        }
        public FindAssetsMode fMode = FindAssetsMode.Textures;
        public bool findAssetsOpen = true;
        public Rect assetsTextureFieldRect = new Rect();
    }

    public static AssetsVar assetsVar = new AssetsVar();
    private void AssetsTab()
    {
        #region Select Buttons
        GUILayout.Space(5);
        GUILayout.Box("", GUILayout.ExpandWidth(true), GUILayout.Height(32));
        GUILayout.Space(-29);
        GUILayout.BeginHorizontal();
        GUILayout.Space(10);

        if (assetsVar.choosenTab == AssetTab.Export) GUI.color = colorSelected;
        if (GUILayout.Button(Lang("Export To Bundle"), GUILayout.Width(128)))
        {
            assetsVar.choosenTab = AssetTab.Export;
        }
        GUI.color = colorGUI;
        if (assetsVar.choosenTab == AssetTab.FindAssets) GUI.color = colorSelected;
        if (GUILayout.Button(Lang("Find Assets"), GUILayout.Width(128)))
        {
            if (assetsVar.choosenTab == AssetTab.FindAssets) assetsVar.findAssetsOpen = !assetsVar.findAssetsOpen;
            else assetsVar.findAssetsOpen = true;
            assetsVar.choosenTab = AssetTab.FindAssets;
        }
        GUI.color = colorGUI;


        GUILayout.EndHorizontal();
        #endregion

        #region Export
        if (assetsVar.choosenTab == AssetTab.Export)
        {
            GUILayout.Space(15);
            GUILayout.BeginHorizontal();

            if (GUILayout.Button("Export", GUILayout.Width(assetsVar.exportButtonWidth)))
            {
                SaveToBundles(assetsVar.filesInProject, assetsVar.collectDependencies);
            }
            int rightFeldWidth = 400;

            GUILayout.BeginHorizontal(GUILayout.Width(512));
            bool extensionChoosed = false;
            assetsVar.exportExtPrefab = GUILayout.Toggle(assetsVar.exportExtPrefab, ".prefab");
            if (GUI.changed) extensionChoosed = true;
            assetsVar.exportExtFBX = GUILayout.Toggle(assetsVar.exportExtFBX, ".fbx");
            if (GUI.changed) extensionChoosed = true;
            assetsVar.collectDependencies = GUILayout.Toggle(assetsVar.collectDependencies, "Dependencies");
            if (GUI.changed) extensionChoosed = true;

            if (extensionChoosed) FillListForExport();

            GUILayout.Label(Lang("Total Objects Found : ") + assetsVar.totalAssObjectsCount);
            GUILayout.Label("/");
            GUILayout.Label(Lang("Objects Selected : ") + assetsVar.totalAssObjectSelected);

            GUILayout.EndHorizontal();
            GUILayout.EndHorizontal();

            GUILayout.Space(5);
            GUILayout.BeginHorizontal();

            scrolls["AssetTabExportLeft"] = DrawField(new SectorDelegate(AssetExportTabLeftField), genericEditorSkin, (Vector2)scrolls["AssetTabExportLeft"], GUILayout.ExpandWidth(true));
            scrolls["AssetTabExportRight"] = DrawField(new SectorDelegate(AssetExportTabRightField), genericEditorSkin, (Vector2)scrolls["AssetTabExportRight"], GUILayout.Width(rightFeldWidth));

            GUILayout.EndHorizontal();
        }
        #endregion

        #region Find Assets
        else if (assetsVar.choosenTab == AssetTab.FindAssets)
        {
            AssetFindAssets();
        }
        #endregion
    }

    private void FillListForExport()
    {
        List<string> extensions = new List<string>();
        if (assetsVar.choosenTab == AssetTab.Export)
        {
            if (assetsVar.exportExtPrefab) extensions.Add("*.prefab");
            if (assetsVar.exportExtFBX) {
				extensions.Add("*.fbx");
				extensions.Add("*.max");
			}
            assetsVar.filesInProject = FindObjects(extensions, ref assetsVar.totalAssObjectsCount);
            assetsVar.exportedObjectsFound = true;
        }
        else if (assetsVar.choosenTab == AssetTab.FindAssets && assetsVar.fMode == AssetsVar.FindAssetsMode.Textures)
        {
            extensions.Add("*.mat");
            assetsVar.materialsInProject = FindObjects(extensions, ref assetsVar.totalMaterialsCount);
            extensions.Clear();

            extensions.Add("*.jpg");
            extensions.Add("*.jpeg");
            extensions.Add("*.psd");
            extensions.Add("*.gif");
            extensions.Add("*.bmp");
            extensions.Add("*.png");
            extensions.Add("*.tga");
            extensions.Add("*.pict");
            extensions.Add("*.tiff");
            extensions.Add("*.tif");
            extensions.Add("*.iff");
            assetsVar.texturesInProject = FindObjects(extensions, ref assetsVar.totalTexturesCount);
        } 
    }

    private void AssetExportTabRightField(params object[] obj)
    {
        if (assetsVar.filesInProject == null) return;
        assetsVar.totalAssObjectSelected = 0;
        EditorGUILayout.BeginVertical();
        List<DirectoryInfo> infos = (List<DirectoryInfo>)assetsVar.filesInProject["Keys"];
        int index = 0;
        foreach (DirectoryInfo dif in infos)
        {
            List<ExportedOptions> objects = (List<ExportedOptions>)assetsVar.filesInProject[dif];
            int count = objects.Count;
            for (int i = 0; i < count; i++)objects[i].ShowGUIRight(index);
            index++;
        }
        EditorGUILayout.EndVertical();
    }

    private void AssetExportTabLeftField(params object[] obj)
    {
        if (GUILayout.Button(Lang("Refresh"), GUILayout.Width(assetsVar.exportButtonWidth))) FillListForExport();
        if (assetsVar.filesInProject == null) FillListForExport();
        EditorGUILayout.BeginVertical();

        List<DirectoryInfo> infos = (List<DirectoryInfo>)assetsVar.filesInProject["Keys"];
        List<bool> toggles = (List<bool>)assetsVar.filesInProject["Toggles"], selectAll = (List<bool>)assetsVar.filesInProject["Select All"];
        int index = 0;

        foreach (DirectoryInfo dif in infos)
        {
            GUIContent cont = new GUIContent(dif.FullName, folderIcon);
            if (index == 0) cont.text = Lang("All Objects");
            toggles[index] = EditorGUILayout.Foldout(toggles[index], cont);
            if (!toggles[index])
            {
                index++;
                continue;
            }

            List<ExportedOptions> objects = (List<ExportedOptions>)assetsVar.filesInProject[dif];
            bool toggleChanged = selectAll[index];
            selectAll[index] = GUILayout.Toggle(selectAll[index], Lang("Select All") + "  (" + objects.Count + " " + Lang("Objects") + ")");

            int count = objects.Count;
            //DirectoryInfo srcFolder = new DirectoryInfo(Application.dataPath);
            for (int i = 0; i < count; i++)
            {
                ExportedOptions sobj = objects[i];
                if (selectAll[index] != toggleChanged) sobj.markedToSave = selectAll[index];
                sobj.ShowGUI();
            }
            index++;
        }
        EditorGUILayout.EndVertical();
    }

    private void AssetFindAssets(params object[] obj)
    {
        #region Select Buttons
        if (assetsVar.findAssetsOpen)
        {
            GUILayout.Space(5);
            GUILayout.Box("", GUILayout.ExpandWidth(true), GUILayout.Height(32));
            GUILayout.Space(-31);
            EditorGUILayout.BeginHorizontal();
            GUILayout.Space(10);

            if (assetsVar.fMode == AssetsVar.FindAssetsMode.Textures) GUI.color = colorSelected;
            if (GUILayout.Button(Lang("Textures"), GUILayout.Width(128)))
            {
                assetsVar.fMode = AssetsVar.FindAssetsMode.Textures;
            }
            GUI.color = colorGUI;
            GUI.enabled = false;
            if (assetsVar.fMode == AssetsVar.FindAssetsMode.Materials) GUI.color = colorSelected;
            if (GUILayout.Button(Lang("Materials"), GUILayout.Width(128)))
            {
                assetsVar.fMode = AssetsVar.FindAssetsMode.Materials;
            }
            GUI.enabled = true;
            GUI.color = colorGUI;
            if (GUILayout.Button(Lang("Close"), GUILayout.Width(64)))
            {
                assetsVar.findAssetsOpen = false;
            }

            GUILayout.Space(25);
            GUILayout.Label(Lang("Total Textures in Project : ") + assetsVar.totalTexturesCount);

            EditorGUILayout.EndHorizontal();
        }
        #endregion

        switch (assetsVar.fMode)
        {
            case AssetsVar.FindAssetsMode.Textures :
                scrolls["AssetTextures"] = DrawField(new SectorDelegate(AssetFindTextures), genericEditorSkin, (Vector2)scrolls["AssetTextures"], GUILayout.ExpandWidth(true));
                assetsVar.assetsTextureFieldRect = GUILayoutUtility.GetLastRect();
                if (assetsVar.assetsTextureFieldRect.width < 500) assetsVar.assetsTextureFieldRect.width = 500;
                break;
        }
    }

    private void AssetFindTextures(params object[] obj)
    {
        if (GUILayout.Button(Lang("Refresh"), GUILayout.Width(assetsVar.exportButtonWidth))) FillListForExport();
        if (assetsVar.texturesInProject == null) FillListForExport();

        List<DirectoryInfo> infos = (List<DirectoryInfo>)assetsVar.texturesInProject["Keys"];
        List<bool> toggles = (List<bool>)assetsVar.texturesInProject["Toggles"];
        int index = 0;
        
        EditorGUILayout.BeginVertical();
        if (infos == null)
        {
            FillListForExport();
            return;
        }

        foreach (DirectoryInfo dif in infos)
        {
            GUIContent cont = new GUIContent(dif.FullName, folderIcon);
            if (index == 0) cont.text = Lang("All Objects");
            toggles[index] = EditorGUILayout.Foldout(toggles[index], cont);
            if (!toggles[index])
            {
                index++;
                continue;
            }
            List<ExportedOptions> objects = (List<ExportedOptions>)assetsVar.texturesInProject[dif];
            DrawTexturesLine(objects, 0);
            index++;
        }

        EditorGUILayout.EndVertical();

    }

    public void DrawTexturesLine(List<ExportedOptions> objects, int currentIndex)
    {
        int count = objects.Count;
        DrawSeparator();
        EditorGUILayout.BeginVertical();
        while (count > currentIndex)
        {
            EditorGUILayout.BeginHorizontal();
            GUILayout.Space(-50);
            for (int i = 0; i < 5; i++)
            {
                if (count > currentIndex)
                {
                    objects[currentIndex++].ShowTexturesGUI();
                }
            }
            EditorGUILayout.EndHorizontal();
            EditorGUILayout.Separator();
        }
        EditorGUILayout.EndVertical();
        DrawSeparator();
    }
}
