//Created by Neodrop
//neodrop@unity3d.ru
//Created by PAX
//pax62rus@yandex.ru
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
#pragma warning disable

public class AntaresBasket : EditorWindow
{
    static int currentButton = 0, bcount = 8;
    static AntaresBasket window;
    static GUIContent[] buttonsContent;
    static GUIStyle buttonsStyle;

    static Dictionary<GameObject, Texture> listGo = new Dictionary<GameObject,Texture>(), listPrefabs = new Dictionary<GameObject,Texture>();
    static Dictionary<Material, Texture> listMat = new Dictionary<Material,Texture>();
    static Dictionary<MonoScript, Texture> listScript = new Dictionary<MonoScript, Texture>();
    static Dictionary<Texture2D, Texture> listTextere = new Dictionary<Texture2D, Texture>();
    static List<Color> listColor = new List<Color>();
    static Dictionary<AudioClip, Texture> listAudio = new Dictionary<AudioClip, Texture>();

    static Dictionary<Object, Texture> listToExport = new Dictionary<Object, Texture>();
    static Dictionary<Object, bool> listToExportMainAsset = new Dictionary<Object, bool>();

    [MenuItem("Antares/BASKET &b")]
    static void CreateWindow()
    {
        window = (AntaresBasket)EditorWindow.GetWindow(typeof(AntaresBasket));

        window.wantsMouseMove = true;
        window.title = "Antares BASKET";
        window.autoRepaintOnSceneChange = true;
        window.minSize = new Vector2(550, 300);
        window.Show();
        window.ShowUtility();
        
        buttonsContent = new GUIContent[bcount];
        buttonsContent[0] = new GUIContent("GameObject", "");
        buttonsContent[1] = new GUIContent("Script", "");
        buttonsContent[2] = new GUIContent("Prefab", "");
        buttonsContent[3] = new GUIContent("Texture", "");
        buttonsContent[4] = new GUIContent("Material", "");
        buttonsContent[5] = new GUIContent("Color", "");
        buttonsContent[6] = new GUIContent("Sound", "");
        buttonsContent[7] = new GUIContent("Export", "Export to Asset Bundle");
        buttonsStyle = EditorStyles.miniButton;

        buttonsStyle.active.textColor = Color.white;
        buttonsStyle.onActive.textColor = AntaresEdMainWindow.colorSelected;
        buttonsStyle.onHover.textColor = AntaresEdMainWindow.colorSelected;
    }

    void OnGUI()
    {
        if (EditorApplication.isCompiling) return;
        try
        {
            if (AntaresGameObjectCustom.Routines.imageBackground != null)
            {
                float backWith = AntaresGameObjectCustom.Routines.imageBackground.width,
                      backHeight = AntaresGameObjectCustom.Routines.imageBackground.height;

                GUI.enabled = false;
                GUIStyle.none.Draw(new Rect(window.position.width - 512, window.position.height - 512, 512, 512),
                                   AntaresGameObjectCustom.Routines.imageBackground, false, false, false, false);
                GUI.enabled = true;

                AntaresGameObjectCustom.Routines.ShowCredits(new Rect(window.position.width - 115,
                                                                      window.position.height - 60,
                                                                      100, 32));
            }

            if (buttonsContent == null) CreateWindow();
            toDragCandidate = null;
            EditorGUILayout.Separator();
            currentButton = GUILayout.SelectionGrid(currentButton, buttonsContent, bcount, buttonsStyle);

            toRemove = null;
            EditorGUILayout.Separator();
            switch (currentButton)
            {
                case 0:
                    ShowGameObjects();
                    break;
                case 1:
                    ShowScripts();
                    break;
                case 2:
                    ShowPrefabs();
                    break;
                case 3:
                    ShowTextures();
                    break;
                case 4:
                    ShowMaterials();
                    break;
                case 5:
                    ShowColors();
                    break;
                case 6:
                    ShowAudio();
                    break;
                case 7:
                    ShowExport();
                    break;
            }

            #region Drag and Drop

            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();

                window.Focus();
                //Event.current.Use();
            }

            if (Event.current.button != 0) toDrag = null;

            if (Event.current.type == EventType.DragExited) // && window.position.Contains(Event.current.mousePosition))
            {
                if (toDrag)
                {
                    toDrag = null;
                    return;
                }
                int addedCount = 0;

                System.Type dragObjType = DragAndDrop.objectReferences[0].GetType();
                if (currentButton != 7) // if no export
                {
                    if (dragObjType == typeof (GameObject) && currentButton != 2) currentButton = 0;
                    else if (dragObjType == typeof (MonoScript)) currentButton = 1;
                    else if (dragObjType == typeof (Texture2D)) currentButton = 3;
                    else if (dragObjType == typeof (Material)) currentButton = 4;
                    else if (dragObjType == typeof (AudioClip)) currentButton = 6;
                }

                int count = 0;

                switch (currentButton)
                {
                    case 1: //Scripts
                        System.Type typeGo1 = typeof (MonoScript);
                        count = DragAndDrop.objectReferences.Length;
                        for (int i = 0; i < count; i++)
                        {
                            if (DragAndDrop.objectReferences[i].GetType() == typeGo1 &&
                                !listScript.ContainsKey((MonoScript) DragAndDrop.objectReferences[i]))
                            {
                                listScript.Add((MonoScript) DragAndDrop.objectReferences[i],
                                               AssetDatabase.GetCachedIcon(
                                                   AssetDatabase.GetAssetPath(DragAndDrop.objectReferences[i])));
                                addedCount++;
                            }
                        }
                        break;
                    case 3: //Textures
                        System.Type typeTex = typeof (Texture2D);
                        count = DragAndDrop.objectReferences.Length;
                        for (int i = 0; i < count; i++)
                        {
                            if (DragAndDrop.objectReferences[i].GetType() == typeTex &&
                                !listTextere.ContainsKey((Texture2D) DragAndDrop.objectReferences[i]))
                            {
                                listTextere.Add((Texture2D) DragAndDrop.objectReferences[i],
                                                EditorUtility.GetMiniThumbnail(DragAndDrop.objectReferences[i]));
                                addedCount++;
                            }
                        }
                        break;
                    case 4: // Materials
                        System.Type typeGo = typeof (Material);
                        count = DragAndDrop.objectReferences.Length;
                        for (int i = 0; i < count; i++)
                        {
                            if (DragAndDrop.objectReferences[i].GetType() == typeGo &&
                                !listMat.ContainsKey((Material) DragAndDrop.objectReferences[i]))
                            {
                                listMat.Add((Material) DragAndDrop.objectReferences[i],
                                            AssetDatabase.GetCachedIcon(
                                                AssetDatabase.GetAssetPath(DragAndDrop.objectReferences[i])));
                                addedCount++;
                            }
                        }
                        break;
                    case 6:
                        System.Type typeA = typeof (AudioClip);
                        count = DragAndDrop.objectReferences.Length;
                        for (int i = 0; i < count; i++)
                        {
                            if (DragAndDrop.objectReferences[i].GetType() == typeA &&
                                !listAudio.ContainsKey((AudioClip) DragAndDrop.objectReferences[i]))
                            {
                                listAudio.Add((AudioClip) DragAndDrop.objectReferences[i],
                                              AssetDatabase.GetCachedIcon(
                                                  AssetDatabase.GetAssetPath(DragAndDrop.objectReferences[i])));
                                addedCount++;
                            }
                        }
                        break;
                    case 7:
                        count = DragAndDrop.objectReferences.Length;
                        for (int i = 0; i < count; i++)
                        {
                            if (!listToExport.ContainsKey(DragAndDrop.objectReferences[i]))
                            {
                                if (DragAndDrop.objectReferences[i].GetType() == typeof (Object)) continue;
                                Texture icon = null;
                                try
                                {
                                    icon =
                                        AssetDatabase.GetCachedIcon(
                                            AssetDatabase.GetAssetPath(DragAndDrop.objectReferences[i]));
                                }
                                catch (System.Exception ex)
                                {
                                    Debug.Log(ex);
                                    Debug.Log("Object : " + DragAndDrop.objectReferences[i] + " have no source");
                                    continue;
                                }
                                if (icon)
                                {
                                    listToExport.Add(DragAndDrop.objectReferences[i], icon);
                                    listToExportMainAsset.Add(DragAndDrop.objectReferences[i], false);
                                    addedCount++;
                                }
                            }

                        }
                        break;
                }
                if (currentButton == 0 || currentButton == 2) // Game Objects & Prefabs
                {
                    System.Type typeGo = typeof (GameObject);
                    count = DragAndDrop.objectReferences.Length;
                    for (int i = 0; i < count; i++)
                    {
                        if (DragAndDrop.objectReferences[i].GetType() == typeGo &&
                            !listGo.ContainsKey((GameObject) DragAndDrop.objectReferences[i]))
                        {
                            listGo.Add((GameObject) DragAndDrop.objectReferences[i],
                                       AssetDatabase.GetCachedIcon(
                                           AssetDatabase.GetAssetPath(DragAndDrop.objectReferences[i])));
                            addedCount++;
                            if (EditorUtility.GetPrefabType(DragAndDrop.objectReferences[i]) != PrefabType.None &&
                                DragAndDrop.paths.Length != 0 && DragAndDrop.paths[i].Contains("prefab"))
                            {
                                listPrefabs.Add((GameObject) DragAndDrop.objectReferences[i],
                                                AssetDatabase.GetCachedIcon(
                                                    AssetDatabase.GetAssetPath(DragAndDrop.objectReferences[i])));
                            }
                        }
                    }
                }

                ShowNotification(new GUIContent("Received : " + addedCount + " objects"
                                     , AntaresGameObjectCustom.Routines.imageIconSmall));
            }

            if (Event.current.type == EventType.MouseDrag && toDrag != null)
            {
                // Clear out drag data
                DragAndDrop.PrepareStartDrag();

                // Set up what we want to drag
                DragAndDrop.objectReferences = new Object[] {toDrag}; //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;
                toDrag = null;
            }
        }catch
        {
        }

        #endregion
    }

    string bundleName = "Enter AssetBundle name";
    bool collectDependencies = true, completeAssets = false, deterministicAssetBundle = false;
    Object mainAsset = null;
    private void ShowExport()
    {
        int count = listToExport.Count;
        GUI.enabled = count > 0;
        EditorGUILayout.BeginHorizontal();
        if (GUI.enabled) GUI.color = AntaresEdMainWindow.colorSelected;
        if (GUILayout.Button("Export selected", EditorStyles.miniButton, GUILayout.Width(128)))
        {
            if (mainAsset == null || !listToExport.ContainsKey(mainAsset))
            {
                ShowNotification(new GUIContent("You must select Main Object", AntaresGameObjectCustom.Routines.imageIconSmall));
                return;
            }
            Export();
        }
        GUI.enabled = true;
        GUI.color = Color.white;
        collectDependencies = GUILayout.Toggle(collectDependencies, new GUIContent("Collect Dependencies", "This follows all references to any assets, game objects or components and includes them in the build."));
        completeAssets = GUILayout.Toggle(completeAssets, new GUIContent("Complete Assets", "For example if you pass a Mesh into the BuildPipeline.BuildAssetBundle function and use CompleteAssets it would also include the game object and any animation clips in the same asset. "));
        deterministicAssetBundle = GUILayout.Toggle(deterministicAssetBundle, new GUIContent("Deterministic AssetBundle", "This allows you to rebuild an asset bundle and reference assets in it directly. When rebuilding the asset bundle the objects in it are guaranteed to have the same id after rebuilding the asset bundle. Due to it being a 32 bit hash space, if you have a lot of objects in the asset bundle it will increase the potential for hash conflicts. Unity will give an error and not build the asset bundle in that case. The hash is based on the GUID of the asset and the local id of the object in the asset. DeterministicAssetBundle are also slower to load from than normal asset bundles, this is because the threaded background loading API usually expects objects to be ordered in a way that makes reading reduce seeking. With DeterministicAssetBundles that is not possible."));
        EditorGUILayout.EndHorizontal();
        EditorGUILayout.Separator();

        
        Object[] mats = new Object[count];
        listToExport.Keys.CopyTo(mats, 0);

        for (int i = 0; i < count; i++)
        {
            GUILayout.BeginHorizontal();
            GUILayout.Label(new GUIContent(listToExport[mats[i]]), GUILayout.Width(24), GUILayout.Height(24));
            EditorGUILayout.ObjectField(mats[i], typeof(Object), GUILayout.Width(256));
            if (GUILayout.Button("Remove", EditorStyles.miniButton, GUILayout.Width(60))) toRemove = mats[i];
            bool before = listToExportMainAsset[mats[i]];
            listToExportMainAsset[mats[i]] = GUILayout.Toggle(listToExportMainAsset[mats[i]], "Main Asset");
            if (before != listToExportMainAsset[mats[i]])
            {
                if (!before)mainAsset = mats[i];
                else mainAsset = null;
                int selected = 0;
                for (int t = 0; t < count; t++) if (listToExportMainAsset[mats[t]]) selected++;
                if (selected > 1) ShowNotification(new GUIContent("Only one asset must be marked as Main", AntaresGameObjectCustom.Routines.imageIconSmall));
            }
            GUILayout.EndHorizontal();
        }
        if (toRemove)
        {
            listToExport.Remove(toRemove);
            if (toRemove == mainAsset) mainAsset = null;
            listToExportMainAsset.Remove(toRemove);
        }
    }

    string lastSavedFolder = "";
    private void Export()
    {
        string srcFolder = lastSavedFolder;
        if (lastSavedFolder == "") srcFolder = Application.dataPath;
        string label = "";
        switch (Application.systemLanguage)
        {
            case SystemLanguage.English:
                label = "Enter file name";
                break;
            case SystemLanguage.Russian:
                label = "Укажите имя файла для сохранения ресурсов";
                break;
        }

        string dstFolder = dstFolder = lastSavedFolder;
        if (dstFolder == "") dstFolder = Application.dataPath;
        bundleName = EditorUtility.SaveFilePanel(label, dstFolder, "Export", "unity3d");
        if (dstFolder == "" || bundleName == "") return;
        lastSavedFolder = bundleName;
        //Debug.Log("Last Path : " + lastSavedFolder);

        Object[] objects = new Object[listToExport.Count], objectsToSave = new Object[listToExport.Count-1];
        listToExport.Keys.CopyTo(objects, 0);
        int index = 0;
        foreach(Object o in objects) if (!listToExportMainAsset[o]) objectsToSave[index++] = o;
        else mainAsset = o;

        BuildAssetBundleOptions options = BuildAssetBundleOptions.CollectDependencies;
        if (completeAssets) options |= BuildAssetBundleOptions.CompleteAssets;
        if (deterministicAssetBundle) options |= BuildAssetBundleOptions.DeterministicAssetBundle;
        if (!collectDependencies) options -= BuildAssetBundleOptions.CollectDependencies;

        if (!BuildPipeline.BuildAssetBundle(mainAsset, objectsToSave, bundleName, options))
        {
            Debug.Log("Error during Exporting : " + bundleName);
            ShowNotification(new GUIContent("Error during Exporting : " + bundleName, AntaresGameObjectCustom.Routines.imageIconSmall));
        }
        else
        {
            ShowNotification(new GUIContent("Done", AntaresGameObjectCustom.Routines.imageIconSmall));
            AssetDatabase.Refresh();
            Selection.activeObject = EditorUtility.FindAsset(bundleName, typeof(Object));
        }
    }

    private void ShowAudio()
    {
        int count = listAudio.Count;
        AudioClip[] mats = new AudioClip[count];
        listAudio.Keys.CopyTo(mats, 0);
        for (int i = 0; i < count; i++)
        {
            GUILayout.BeginHorizontal();
            GUILayout.Label(new GUIContent(listAudio[mats[i]]), GUILayout.Width(24), GUILayout.Height(24));
            EditorGUILayout.ObjectField(mats[i], typeof(AudioClip), GUILayout.Width(256));
            if (GUILayout.Button("Remove", EditorStyles.miniButton, GUILayout.Width(60))) toRemove = mats[i];
            toDragCandidate = mats[i];
            PushButton();
            GUILayout.EndHorizontal();
        }
        if (toRemove != null) listAudio.Remove((AudioClip)toDragCandidate);
    }

    private void ShowColors()
    {
        if (GUILayout.Button("Add Color", EditorStyles.miniButton, GUILayout.Width(60))) listColor.Add(new Color(1f, 1f, 1f, 1f));
        EditorGUILayout.Separator();
        int count = listColor.Count, toRemoveIndex = -1;
        for (int i = 0; i < count; i++ )
        {
            GUILayout.BeginHorizontal();
            listColor[i] = EditorGUILayout.ColorField(listColor[i], GUILayout.Width(256));
            if (GUILayout.Button("Remove", EditorStyles.miniButton, GUILayout.Width(60))) toRemoveIndex = i;
            GUILayout.EndHorizontal();
        }
        if (toRemoveIndex > -1) listColor.RemoveAt(toRemoveIndex);
    }

    Vector2 scrollTextures = Vector2.zero;
    private void ShowTextures()
    {
        int count = listTextere.Count;
        Texture2D[] mats = new Texture2D[count];
        listTextere.Keys.CopyTo(mats, 0);
        scrollTextures = GUILayout.BeginScrollView(scrollTextures, false, false);
        for (int i = 0; i < count; i++)
        {
            GUILayout.BeginHorizontal();
            EditorGUILayout.ObjectField(mats[i], typeof(Texture2D), GUILayout.Width(75), GUILayout.Height(75));
            if (GUILayout.Button("Remove", EditorStyles.miniButton, GUILayout.Width(60))) toRemove = mats[i];
            toDragCandidate = mats[i];
            PushButton();
            GUILayout.EndHorizontal();
        }
        GUILayout.EndScrollView();
        if (toRemove != null) listTextere.Remove((Texture2D)toDragCandidate);
    }

    private void ShowScripts()
    {
        int count = listScript.Count;
        MonoScript[] mats = new MonoScript[count];
        listScript.Keys.CopyTo(mats, 0);
        for (int i = 0; i < count; i++)
        {
            GUILayout.BeginHorizontal();
            GUILayout.Label(new GUIContent(listScript[mats[i]]), GUILayout.Width(24), GUILayout.Height(24));
            EditorGUILayout.ObjectField(mats[i], typeof(MonoScript), GUILayout.Width(256));
            if (GUILayout.Button("Remove", EditorStyles.miniButton, GUILayout.Width(60))) toRemove = mats[i];
            toDragCandidate = mats[i];
            PushButton();
            GUILayout.EndHorizontal();
        }

        if (toRemove != null) listScript.Remove((MonoScript)toDragCandidate);
    }

    private void ShowMaterials()
    {
        int count = listMat.Count;
        Material[] mats = new Material[count];
        listMat.Keys.CopyTo(mats,0);
        for (int i = 0; i < count; i++)
        {
            GUILayout.BeginHorizontal();  
            GUILayout.Label(new GUIContent(listMat[mats[i]]), GUILayout.Width(24), GUILayout.Height(24));
            EditorGUILayout.ObjectField(mats[i], typeof(Material), GUILayout.Width(256));
            if (GUILayout.Button("Remove", EditorStyles.miniButton, GUILayout.Width(60))) toRemove = mats[i];
            toDragCandidate = mats[i];
            PushButton();
            GUILayout.EndHorizontal();
        }

        if (toRemove != null)listMat.Remove((Material)toDragCandidate);
    }

    UnityEngine.Object toRemove, toDrag, toDragCandidate;
    private void ShowGameObjects()
    {
        int count = listGo.Count;
        GameObject[] mats = new GameObject[count];
        listGo.Keys.CopyTo(mats, 0);
        for (int i = 0; i < count; i++)
        {
            GUILayout.BeginHorizontal();
            GUILayout.Label(new GUIContent(listGo[mats[i]]), GUILayout.Width(24), GUILayout.Height(24));
            EditorGUILayout.ObjectField(mats[i], typeof(GameObject), GUILayout.Width (256));
            if (GUILayout.Button("Remove", EditorStyles.miniButton, GUILayout.Width(60))) toRemove = mats[i];
  
            toDragCandidate = mats[i];
            PushButton();
            GUILayout.EndHorizontal();
        }
        if (toRemove != null)
        {
            listGo.Remove((GameObject)toRemove);
            if (AssetDatabase.GetAssetPath(toRemove).Contains("prefab")) listPrefabs.Remove((GameObject)toRemove);
        }
    }

    private void PushButton()
    {
        if (GUILayout.RepeatButton(new GUIContent("Push & Drag", "Press and start dragging object to the target slots"), EditorStyles.miniButton, GUILayout.Width(80)) && Event.current.type != EventType.MouseDrag)
        {
            toDrag = toDragCandidate;
        }
    }

    private void ShowPrefabs()
    {
        int count = listPrefabs.Count;
        GameObject[] mats = new GameObject[count];
        listPrefabs.Keys.CopyTo(mats, 0);
        for (int i = 0; i < count; i++)
        {
            GUILayout.BeginHorizontal();
            GUILayout.Label(new GUIContent(listPrefabs[mats[i]]), GUILayout.Width(24), GUILayout.Height(24));
            EditorGUILayout.ObjectField(mats[i], typeof(GameObject), GUILayout.Width(256));

            if (GUILayout.Button("Remove", EditorStyles.miniButton, GUILayout.Width(60))) toRemove = mats[i];
            toDragCandidate = mats[i];
            PushButton();
            GUILayout.EndHorizontal();
        }
        if (toRemove != null)
        {
            if(listGo.ContainsKey((GameObject)toRemove))listGo.Remove((GameObject)toRemove);
            listPrefabs.Remove((GameObject)toRemove);
        }
    }
}
