﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.IO;
using UnityGLTF;
using Ionic.Zip;
using System.Net;
using System.Net.Sockets;
using System.Linq;

namespace NextechAR.ARitize.Plugin
{
    public class ARitizer : EditorWindow
    {
        private static ARitizer _instance;
        public ARitizerUI ui;

        public static ARitizer Instance
        {
            get
            {
                if (_instance == null)
                {
                    _instance = new ARitizer();
                }
                return _instance;
            }
        }

        //settings
        public string assetBundleDirectory = "NTARs";
        public string unityPackageDirectory = "ExperienceUnityPackages";
        public string stagingDirectory = "Temp/NTAR_Staging";
        public string gltfDirectory = "GLTFs";

        public string lastAssetBundleDirectory = "NTARs";
        public string lastUnityPackageDirectory = "ExperienceUnityPackages";
        public string lastStagingDirectory = "Temp/NTAR_Staging";
        public string lastGltfDirectory = "GLTFs";

        public static string requiredUnityVersion = "2020.1.17f1";
        public static string pluginVersion = "0.27.4";


        //working variables
        public string newExperienceInput = "";
        public bool creatingNew = false;
        public BuildTarget editorBuildTarget;
        public Menu currentMenu = Menu.home;
        public ExperienceInfoEditor dataEditor;
        public int currentSelectedExperience = 0;
        public Object selectedObjectPrefab;
        public ExperienceMenu currentExperienceMenu;
        public UnityEditor.Editor editorForModuleBeingInspected;
        public string editingModuleName;

        public enum Menu
        {
            home,
            experience,
            bulkexport,
            settings,
            tutorial,
            changelog,
            test
        }

        public enum ExperienceMenu
        {
            home,
            edit,
            editModule,
            module,
            build,
            delete,
            duplicate
        }



        void OnGUI()
        {
            ui.PluginGUI();
        }

        void OnEnable()
        {
            ui = new ARitizerUI();
            if (LayerMask.NameToLayer("UserLayer1") == -1)
            {
                InitializeLayers();
            }

            _instance = this;


            ui.Initialize(this);

            if (EditorPrefs.HasKey("assetBundleDirectory"))
            {
                assetBundleDirectory = lastAssetBundleDirectory = EditorPrefs.GetString("assetBundleDirectory");
            }
            else
            {
                lastAssetBundleDirectory = assetBundleDirectory;
            }

            if (EditorPrefs.HasKey("unityPackageDirectory"))
            {
                unityPackageDirectory = lastUnityPackageDirectory = EditorPrefs.GetString("unityPackageDirectory");
            }
            else
            {
                lastUnityPackageDirectory = unityPackageDirectory;
            }

            if (EditorPrefs.HasKey("stagingDirectory"))
            {
                stagingDirectory = lastStagingDirectory = EditorPrefs.GetString("stagingDirectory");
            }
            else
            {
                lastStagingDirectory = stagingDirectory;
            }

            if (EditorPrefs.HasKey("gltfDirectory"))
            {
                gltfDirectory = lastGltfDirectory = EditorPrefs.GetString("gltfDirectory");
            }
            else
            {
                lastGltfDirectory = gltfDirectory;
            }

            if (previewServer == null)
            {
                previewServer = new Telepathy.Server();
            }
        }

        void OnDisable()
        {
            EditorApplication.update -= NetworkUpdate;
        }

        public void SetDataEditor(string experiencePath)
        {
            string dataPath = experiencePath + "/Data.asset";
            Object dataObj = AssetDatabase.LoadAssetAtPath(dataPath, typeof(Object));
            dataEditor = (ExperienceInfoEditor)Editor.CreateEditor(dataObj, typeof(ExperienceInfoEditor));
        }

        void InitializeLayers()
        {
            int userLayerCount = 5;

            var tagManager = new SerializedObject(AssetDatabase.LoadAllAssetsAtPath("ProjectSettings/TagManager.asset")[0]);
            var layerProps = tagManager.FindProperty("layers");

            for (int i = 0; i < userLayerCount; i++)
            {
                int layerIndex = 10 + i;
                string layerNumber = (i + 1).ToString();
                SerializedProperty layerProperty = layerProps.GetArrayElementAtIndex(layerIndex);
                layerProperty.stringValue = string.Format("UserLayer{0}", layerNumber);
            }

            tagManager.ApplyModifiedProperties();
        }


        public void SelectExperience(int index)
        {
            string[] experienceFolders = GetExperienceFolders();
            currentExperienceMenu = ARitizer.ExperienceMenu.home;
            currentSelectedExperience = index;
            OnExperienceSelected(experienceFolders[index], true);
            currentMenu = Menu.experience;


        }

        public string[] GetExperienceFolders()
        {
            return AssetDatabase.GetSubFolders("Assets/_Experiences");
        }

        public void OnExperienceSelected(string experienceFolder, bool instantiate = false)
        {
            string prefabPath = experienceFolder + "/AnchorForAR.prefab";

            if (!FileManager.FileExists(prefabPath))
            {
                return;
            }

            Object obj = AssetDatabase.LoadAssetAtPath(prefabPath, typeof(Object));

            if (obj != null)
            {

                // open prefab
                // AssetDatabase.OpenAsset(obj);

                // return;

                Selection.activeObject = obj;

                // opening prefab stuff moved to buttons
                return;

                if (instantiate)
                {
                    selectedObjectPrefab = PrefabUtility.InstantiatePrefab(obj);
                    StaticCoroutine.Start(SelectionCoroutine(obj, selectedObjectPrefab, true));
                }
                else
                {
                    StaticCoroutine.Start(SelectionCoroutine(obj, selectedObjectPrefab, false));
                }

                if (SceneView.lastActiveSceneView != null)
                    SceneView.lastActiveSceneView.FrameSelected();
            }
        }



        IEnumerator SelectionCoroutine(Object firstSelection, Object secondSelection, bool alsoInScene = true)
        {
            Selection.activeObject = firstSelection;

            yield return null;

            if (alsoInScene)
            {
                Selection.activeObject = secondSelection;

                if (SceneView.lastActiveSceneView != null)
                    SceneView.lastActiveSceneView.FrameSelected();
            }
        }

        public ValidationResult ValidateExperience(string experiencePath)
        {
            ValidationResult result = new ValidationResult();

            string prefabPath = experiencePath + "/AnchorForAR.prefab";
            string dataPath = experiencePath + "/Data.asset";
            string experienceName = Path.GetFileName(experiencePath);


            if (!File.Exists(prefabPath))
            {
                result.messages.Add(new ValidationResult.ValidationMessage("No AnachorForAR prefab (maybe you renamed it?)", ValidationResult.ValidationMessage.MessageType.error));
            }

            if (!File.Exists(dataPath))
            {
                result.messages.Add(new ValidationResult.ValidationMessage("No Data object (maybe you renamed it?)", ValidationResult.ValidationMessage.MessageType.error));
            }
            else
            {
                ExperienceInfo expInfo = AssetDatabase.LoadMainAssetAtPath(dataPath) as ExperienceInfo;

                if (expInfo == null)
                {
                    result.messages.Add(new ValidationResult.ValidationMessage("Data object corrupted?", ValidationResult.ValidationMessage.MessageType.error));
                }
                else if (expInfo.modules != null)
                {
                    for (int i = 0; i < expInfo.modules.Count; i++)
                    {
                        if (expInfo.modules[i] == null)
                        {
                            result.messages.Add(new ValidationResult.ValidationMessage(string.Format("Missing module in Data (Element {0})", i), ValidationResult.ValidationMessage.MessageType.error));
                        }
                    }
                }
                else
                {
                    expInfo.modules = new List<ExperienceModule>();
                }

            }

            List<string> allDependencies = GetAllDependencies(new List<string> { prefabPath, dataPath });

            for (int i = 0; i < allDependencies.Count; i++)
            {
                if (!allDependencies[i].Contains(experiencePath))
                {
                    result.messages.Add(new ValidationResult.ValidationMessage(string.Format("Asset not in the \"{0}\" folder: {1}", experienceName, allDependencies[i]), ValidationResult.ValidationMessage.MessageType.warning));
                }
            }

            return result;
        }

        [System.Serializable]
        public class ValidationResult
        {
            public List<ValidationMessage> messages;

            public bool IsValid()
            {
                ValidationMessage errorMsg = messages.Find(msg => msg.messageType == ValidationMessage.MessageType.error);
                if (errorMsg == null)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }

            public ValidationResult()
            {
                this.messages = new List<ValidationMessage>();
            }

            [System.Serializable]
            public class ValidationMessage
            {
                public string message;
                public MessageType messageType;
                public enum MessageType
                {
                    none,
                    warning,
                    error
                }

                public ValidationMessage(string msg, MessageType msgType)
                {
                    this.message = msg;
                    this.messageType = msgType;
                }
            }
        }

        int lastExperienceCount = 0;

        public bool ExperienceCountChanged()
        {
            string[] experienceFolders = AssetDatabase.GetSubFolders("Assets/_Experiences");

            if (experienceFolders.Length != lastExperienceCount)
            {
                lastExperienceCount = experienceFolders.Length;
                return true;
            }
            else
            {
                return false;
            }


        }

        public bool IsCorrectUnityVersion()
        {
            if (Application.unityVersion != requiredUnityVersion)
            {
                return false;
            }
            else
            {
                return true;
            }
        }

        public string GetPluginVersion()
        {
            return pluginVersion;
        }

        public string GetRequiredUnityVersion()
        {
            return requiredUnityVersion;
        }

        bool HasExperienceSelectedInScene()
        {
            GameObject targetGO = GameObject.Find("AnchorForAR");
            if (targetGO != null)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        public static string RetrieveTexturePath(UnityEngine.Texture texture)
        {
            return AssetDatabase.GetAssetPath(texture);
        }

        public void BuildForWeb(string parentFolder)
        {
            if (HasExperienceSelectedInScene())
            {
                string bundleName = Path.GetFileName(parentFolder);

                Transform[] transforms = new Transform[1];
                transforms[0] = GameObject.Find("AnchorForAR").transform;

                var exporter = new GLTFSceneExporter(transforms, RetrieveTexturePath);

                string path = gltfDirectory + "/" + bundleName + "/";
                FileManager.DeleteFile(path);
                FileManager.CreateDirectoryIfNeeded(path);

                if (exporter.SaveGLTFandBin(path, "Main"))
                {
                    ZipGLTF(bundleName, gltfDirectory);

                    EditorUtility.RevealInFinder(gltfDirectory + "/" + bundleName + ".zip");
                }
            }
            else
            {
                Debug.LogError("Drag the AnchorForAR prefab for the experience into the scene before exporting eCommerce build");
            }

        }

        void ZipGLTF(string bundleName, string path)
        {
            using (ZipFile zip = new ZipFile())
            {
                string zipPath = path + "/" + bundleName + ".zip";
                string gltfPath = path + "/" + bundleName;
                string[] files = Directory.GetFiles(gltfPath, "*", SearchOption.AllDirectories);

                for (int i = 0; i < files.Length; i++)
                {
                    string fileName = Path.GetFileName(files[i]);
                    string zipFolder = files[i].Replace(gltfPath, "").Replace(fileName, "");
                    zip.AddFile(files[i], zipFolder);
                }


                zip.Save(zipPath);
            }
        }

        public void SetModuleEditor()
        {
            dataEditor = null;
            string path = EditorPrefs.GetString("EditModulePath");
            Object dataObj = AssetDatabase.LoadAssetAtPath(path, typeof(Object));

            editingModuleName = EditorPrefs.GetString("EditModule");
            editorForModuleBeingInspected = Editor.CreateEditor(dataObj);
        }

        public void ClosePreviewServer()
        {
            KillServer();
            previewMenuOpen = false;
        }

        public void SendData(string fileName)
        {
            string testPath = assetBundleDirectory + "/" + fileName;
            byte[] fileBytes = FileManager.LoadFileAsBytes(testPath);
            previewServer.Send(lastConnectionId, fileBytes);
        }

        public string localIp = "";
        public void StartPreviewServer()
        {
            string hostName = System.Net.Dns.GetHostName();
            IPAddress[] IPs = System.Net.Dns.GetHostEntry(hostName).AddressList;
            IPAddress ipToUse = null;
            for (int i = 0; i < IPs.Length; i++)
            {
                Debug.Log("IP: " + IPs[i].ToString());
                if (IPs[i].ToString().Contains(":"))
                {
                    continue;
                }
                else if (IPs[i].ToString().Contains("."))
                {
                    ipToUse = IPs[i];
                    break;
                }
            }
            localIp = ipToUse.ToString();
            StartHost();
            previewMenuOpen = true;
        }

        public bool previewMenuOpen = false;

        public void ExportUnityPackage(string path)
        {
            if (!Directory.Exists(unityPackageDirectory))
            {
                Directory.CreateDirectory(unityPackageDirectory);
            }
            string exportLocation = unityPackageDirectory + "/" + Path.GetFileName(path) + ".unitypackage";

            List<string> assetsToExport = GetAllDependencies(new List<string> { path });
            Debug.Log("Building plugin");

            string assetsListed = "Assets to export: \n";
            for (int i = 0; i < assetsToExport.Count; i++)
            {
                assetsListed += assetsToExport[i] + "\n";
            }

            Debug.Log(assetsListed);

            AssetDatabase.ExportPackage(assetsToExport.ToArray(), exportLocation, ExportPackageOptions.Interactive);

            if (FileManager.FileExists(exportLocation))
            {
                EditorUtility.RevealInFinder(exportLocation);
            }
            else
            {
                EditorUtility.RevealInFinder(FileManager.GetParentFolder(exportLocation));
            }

        }

        public void UninstallSelf()
        {
            string[] pathsToDelete = new string[]{
                "Assets/_ReadMe.txt",
                "Assets/_Experiences/Examples",
                "Assets/_Scenes/Exporter.unity",
                "Assets/_Scripts/",
                "Assets/_Modules",
                "Assets/_Editor",
                "Assets/PostProcessing",
                "Assets/Telepathy"
            };

            for (int i = 0; i < pathsToDelete.Length; i++)
            {
                FileUtil.DeleteFileOrDirectory(pathsToDelete[i]);
            }

            AssetDatabase.Refresh();
            EditorUtility.SetDirty(this);
        }

        public void CreateNewExperience(string newExperienceName)
        {
            string newExperiencePath = "Assets/_Experiences/" + newExperienceName;
            if (!Directory.Exists(newExperiencePath))
            {
                //create directories
                Directory.CreateDirectory(newExperiencePath + "/_Assets");
                //create AnchorForAR
                GameObject tmpObject = new GameObject();
                PrefabUtility.CreatePrefab(newExperiencePath + "/AnchorForAR.prefab", tmpObject);
                DestroyImmediate(tmpObject);
                //create Data
                ScriptableObject newData = ScriptableObject.CreateInstance("ExperienceInfo");
                AssetDatabase.CreateAsset(newData, newExperiencePath + "/Data.asset");
                //this is so inspector updates instantly
                AssetDatabase.Refresh();
            }
            else
            {
                Debug.LogError("Experience already exists: " + newExperienceName);
                return;
            }
            newExperienceInput = "";
        }

        public void DuplicateExperience(int experienceIndex, string newName)
        {
            UnityEditor.SceneManagement.StageUtility.GoToMainStage();

            string[] experienceFolders = AssetDatabase.GetSubFolders("Assets/_Experiences");
            string experiencePath = experienceFolders[experienceIndex];
            string experienceName = Path.GetFileName(experiencePath);


            Debug.Log("Duplicating " + experienceName + " to " + newName);

            string expFolder = experiencePath.Replace(experienceName, "");

            // Debug.Log(expFolder);

            string guid = AssetDatabase.CreateFolder(expFolder.Substring(0, expFolder.Length - 1), newName);

            // AssetDatabase.SaveAssets();

            string oldDir = experiencePath + "/";
            string newDir = AssetDatabase.GUIDToAssetPath(guid) + "/";

            // Debug.Log(newPath);

            string[] files = Directory.GetFiles(oldDir, searchPattern: "*", searchOption: SearchOption.AllDirectories);

            List<string> filesToCopy = new List<string>();

            // filter out meta files
            for (int i = 0; i < files.Length; i++)
            {
                string ending = files[i].Substring(files[i].Length - 5);
                // if(ending != ".meta")
                // {
                //     filesToCopy.Add(files[i]);
                // }

                if (files[i].Contains(".asset"))
                {
                    if (ending != ".meta")
                    {
                        filesToCopy.Add(files[i]);
                    }

                }

                if (files[i].Contains("AnchorForAR.prefab"))
                {
                    if (ending != ".meta")
                    {
                        filesToCopy.Add(files[i]);
                    }
                }
            }

            Debug.Log("File count: " + filesToCopy.Count);

            Dictionary<string, string> pathRecord = new Dictionary<string, string>();

            for (int i = 0; i < filesToCopy.Count; i++)
            {
                string oldPath = filesToCopy[i];
                string newPath = oldPath.Replace(oldDir, newDir);
                pathRecord.Add(oldPath, newPath);
                Debug.Log("Copying: " + oldPath + " -> " + newPath);

                FileManager.CreateDirectoryIfNeeded(newPath);

                bool result = AssetDatabase.CopyAsset(oldPath, newPath);

                if (result == false)
                {
                    Debug.LogError("Error copying: " + oldPath + " -> " + newPath);
                }

            }

            string oldDataPath = oldDir + "Data.asset";
            string newDataPath = newDir + "Data.asset";


            ExperienceInfo oldExpInfo = AssetDatabase.LoadMainAssetAtPath(oldDataPath) as ExperienceInfo;
            ExperienceInfo newExpInfo = AssetDatabase.LoadMainAssetAtPath(newDataPath) as ExperienceInfo;

            InputOutputModule ioModule = null;

            for (int i = 0; i < oldExpInfo.modules.Count; i++)
            {
                int oldInstanceId = oldExpInfo.modules[i].GetInstanceID();
                string oldPath = AssetDatabase.GetAssetPath(oldInstanceId);



                string newPath = pathRecord[oldPath];

                ExperienceModule tmpModule = AssetDatabase.LoadAssetAtPath<ExperienceModule>(newPath);

                newExpInfo.modules[i] = tmpModule;

                Debug.Log("Module: " + oldPath + " -> " + newPath);

                if (tmpModule.GetType() == typeof(InputOutputModule))
                {
                    ioModule = (InputOutputModule)tmpModule;
                }
            }

            EditorUtility.SetDirty(newExpInfo);

            if (ioModule == null)
            {
                Debug.Log("No IO module to copy");
            }
            else
            {
                Debug.Log("Copying IOs");
                Dictionary<string, string> ioPathRecord = new Dictionary<string, string>();

                for (int i = 0; i < ioModule.inputOutputSets.Count; i++)
                {
                    int oldInputInstanceId = ioModule.inputOutputSets[i].input.GetInstanceID();

                    // Debug.Log("oldInputInstanceId: " + oldInputInstanceId);

                    string oldInputPath = AssetDatabase.GetAssetPath(oldInputInstanceId);

                    // Debug.Log("oldInputPathD: " + oldInputPath);

                    string newInputPath = pathRecord[oldInputPath];

                    // Debug.Log("SubModule: " + oldOutputPath + " -> " + newOutputPath);

                    InputSubmodule tmpInputModule = AssetDatabase.LoadAssetAtPath<InputSubmodule>(newInputPath);

                    int oldOutputInstanceId = ioModule.inputOutputSets[i].output.GetInstanceID();
                    string oldOutputPath = AssetDatabase.GetAssetPath(oldOutputInstanceId);

                    string newOutputPath = pathRecord[oldOutputPath];

                    // Debug.Log("SubModule: " + oldOutputPath + " -> " + newOutputPath);

                    OutputSubmodule tmpOutputModule = AssetDatabase.LoadAssetAtPath<OutputSubmodule>(newOutputPath);

                    ioModule.inputOutputSets[i].input = tmpInputModule;
                    ioModule.inputOutputSets[i].output = tmpOutputModule;



                }

                EditorUtility.SetDirty(ioModule);
            }

            AssetDatabase.SaveAssets();


            BackFromHome();
            // currentExperienceMenu = ExperienceMenu.home;

        }

        //clean up garbage so we're building ntars one at a time
        void ClearAssetBundleNames()
        {
            string[] bundleNames = AssetDatabase.GetAllAssetBundleNames();
            for (int i = 0; i < bundleNames.Length; i++)
            {
                AssetDatabase.RemoveAssetBundleName(bundleNames[i], true);
            }
        }

        void PreProcessExperience(ExperienceInfo experienceInfo)
        {
            for (int i = 0; i < experienceInfo.modules.Count; i++)
            {
                // if it's a video module, make sure if we have a local video that it's named .bytes
                if (experienceInfo.modules[i].GetType() == typeof(VideoModule))
                {
                    VideoModule videoModule = experienceInfo.modules[i] as VideoModule;
                    if (videoModule.videoFile != null)
                    {
                        string assetPath = AssetDatabase.GetAssetPath(videoModule.videoFile);

                        if (assetPath.Contains(".bytes"))
                        {
                            Debug.Log(assetPath + " already renamed .bytes");
                        }
                        else
                        {
                            string renamed_path = assetPath + ".bytes";

                            //rename file
                            File.Move(assetPath, renamed_path);
                            AssetDatabase.ImportAsset(renamed_path);
                            AssetDatabase.SaveAssets();

                            //update module reference 
                            Object newRef = AssetDatabase.LoadAssetAtPath<Object>(renamed_path);
                            videoModule.videoFile = newRef;
                            AssetDatabase.SaveAssets();

                            AssetDatabase.Refresh();
                            // string result = AssetDatabase.(assetPath, renamed_path);

                            Debug.Log("Renamed " + assetPath + " to " + renamed_path);

                        }


                        // Debug.Log(assetPath);
                        // if(videoModule.videoFile.name)
                        // {

                        // }
                    }
                }
            }


        }



        public void BuildExperience(string parentFolder, BuildTarget platformToBuild, string destinationFolder = "")
        {
            // if (destinationFolder == "")
            //     destinationFolder = assetBundleDirectory;





            string prefabPath = parentFolder + "/AnchorForAR.prefab";
            string dataPath = parentFolder + "/Data.asset";
            string bundleName = Path.GetFileName(parentFolder);

            //add dependencies
            Debug.Log("Building " + parentFolder);
            List<string> dependencyParents = new List<string>();
            dependencyParents.Add(prefabPath);
            dependencyParents.Add(dataPath);

            // some experiences may need some preprocessing
            ExperienceInfo expInfo = AssetDatabase.LoadMainAssetAtPath(dataPath) as ExperienceInfo;
            PreProcessExperience(expInfo);

            //validate experience
            ValidationResult validation = ValidateExperience(parentFolder);

            if (!validation.IsValid())
            {
                Debug.Log("Validation failed, fix issues");
                return;
            }


            for (int i = 0; i < expInfo.forcedDependencies.Count; i++)
            {
                dependencyParents.Add(expInfo.forcedDependencies[i]);
            }

            List<string> assetsToInclude = GetAllDependencies(dependencyParents);

            //printout list of assets included for debug purposes
            string assetListString = "Building NTAR with assets:\n";
            for (int i = 0; i < assetsToInclude.Count; i++)
            {
                assetListString += assetsToInclude[i] + "\n";
            }
            Debug.Log(assetListString);

            //send it off to build
            BuildForPlatform(bundleName, assetsToInclude, platformToBuild, destinationFolder);
        }

        List<string> GetAllDependencies(List<string> assetPaths)
        {
            List<string> dependenciesToReturn = new List<string>();

            for (int i = 0; i < assetPaths.Count; i++)
            {
                string filename = Path.GetFileName(assetPaths[i]);

                if (filename.Contains("."))
                {
                    //it's a file
                    AddDependenciesToList(dependenciesToReturn, AssetDatabase.GetDependencies(assetPaths[i], true));
                }
                else
                {
                    //it's a folder
                    AddDependenciesToList(dependenciesToReturn, GetAllAssetsInDirectory(assetPaths[i]).ToArray());
                }

            }

            return dependenciesToReturn;
        }

        List<string> GetAllAssetsInDirectory(string directoryToSearch)
        {
            string[] filesInFolder = Directory.GetFiles(directoryToSearch, "*", SearchOption.AllDirectories);
            List<string> pathsToReturn = new List<string>();

            for (int i = 0; i < filesInFolder.Length; i++)
            {
                if (!filesInFolder[i].Contains(".meta") && !filesInFolder[i].Contains(".DS_Store"))
                {
                    // pathsToReturn.Add(filesInFolder[i]);
                    string[] dependenciesOfFile = AssetDatabase.GetDependencies(filesInFolder[i], true);
                    pathsToReturn.AddRange(dependenciesOfFile);
                }
            }

            return pathsToReturn;
        }

        void AddDependenciesToList(List<string> dependencyList, string[] pathsToAdd)
        {
            //only add if not already on list and not a .cs file
            for (int i = 0; i < pathsToAdd.Length; i++)
            {
                if (!pathsToAdd[i].Contains(".cs"))
                {
                    if (!dependencyList.Contains(pathsToAdd[i]))
                    {
                        dependencyList.Add(pathsToAdd[i]);
                    }
                }
            }
        }

        void DelayedBuild(string bundleName, List<string> assetsToInclude, BuildTarget platformToBuild, string destinationFolder = "")
        {
            editorBuildTarget = EditorUserBuildSettings.activeBuildTarget;
            Debug.Log("Target in Delayed: " + editorBuildTarget.ToString());
            BuildForPlatform(bundleName, assetsToInclude, platformToBuild, destinationFolder);
        }

        public string GetName_NTAR(string bundleName, BuildTarget platformToBuild)
        {
            string platformSuffix = "";
            if (platformToBuild == BuildTarget.iOS)
            {
                platformSuffix = "ios";
            }
            else if (platformToBuild == BuildTarget.Android)
            {
                platformSuffix = "android";
            }

            return string.Format("{0}_{1}.ntar", bundleName, platformSuffix);
        }

        void BuildForPlatform(string bundleName, List<string> assetsToInclude, BuildTarget platformToBuild, string destinationFolder = "")
        {
            if (destinationFolder == "")
                destinationFolder = assetBundleDirectory;

            editorBuildTarget = EditorUserBuildSettings.activeBuildTarget;
            Debug.Log("Target in Build: " + editorBuildTarget.ToString());
            if (editorBuildTarget != platformToBuild)
            {
                if (platformToBuild == BuildTarget.iOS)
                {
                    EditorUserBuildSettings.SwitchActiveBuildTarget(BuildTargetGroup.iOS, BuildTarget.iOS);
                }
                else if (platformToBuild == BuildTarget.Android)
                {
                    EditorUserBuildSettings.SwitchActiveBuildTarget(BuildTargetGroup.Android, BuildTarget.Android);
                }
                else
                {
                    Debug.LogError("Platform not implemented: " + platformToBuild.ToString());
                }

                //this is required to prevent reimporting twice
                DelayedBuild(bundleName, assetsToInclude, platformToBuild, destinationFolder);
                return;
            }

            Debug.Log("asset bundle dir: " + assetBundleDirectory);
            //add platform to file name


            //create directory if needed
            if (!Directory.Exists(stagingDirectory))
            {
                Directory.CreateDirectory(stagingDirectory);
            }

            //set asset bundle names for necessary files
            ClearAssetBundleNames();
            string bundleAssetName = GetName_NTAR(bundleName, platformToBuild);
            for (int i = 0; i < assetsToInclude.Count; i++)
            {
                AssetImporter.GetAtPath(assetsToInclude[i]).SetAssetBundleNameAndVariant(bundleAssetName, "");
            }

            //this builds it
            AssetBundleManifest manifest = BuildPipeline.BuildAssetBundles(stagingDirectory, BuildAssetBundleOptions.UncompressedAssetBundle, EditorUserBuildSettings.activeBuildTarget);

            string assetBundleFilePath = assetBundleDirectory + "/" + bundleAssetName;
            //copy from staging folder
            //create directory if needed
            if (!Directory.Exists(assetBundleDirectory))
            {
                Directory.CreateDirectory(assetBundleDirectory);
            }

            if (destinationFolder != "")
            {
                assetBundleFilePath = destinationFolder + "/" + bundleAssetName;
            }

            File.Copy(stagingDirectory + "/" + bundleAssetName, assetBundleFilePath, true);

            InspectNewAssetBundle(assetBundleFilePath, assetsToInclude);

            //this opens Finder/Explorer to highlight file - we only want to do this if building manually
            if (destinationFolder == assetBundleDirectory)
            {
                EditorUtility.RevealInFinder(assetBundleFilePath);
            }
        }

        void InspectNewAssetBundle(string pathToBundle, List<string> assetsIncluded)
        {
            long fileSize = -1;
            System.IO.FileInfo fileInfo = new System.IO.FileInfo(pathToBundle);
            fileSize = fileInfo.Length;

            long totalAssetsSize = 0;

            string printout = "Build Report: ";

            Dictionary<string, long> assetDict = new Dictionary<string, long>();
            for (int i = 0; i < assetsIncluded.Count; i++)
            {
                long assetSize = GetCompressedFileSize(assetsIncluded[i]);
                assetDict.Add(assetsIncluded[i], assetSize);
                totalAssetsSize += assetSize;
            }

            printout += "\n" + FileManager.SizeSuffix(fileSize) + " - Packaged Size";

            printout += "\n" + FileManager.SizeSuffix(totalAssetsSize) + " - Total Size of Assets\nAssets:";

            foreach (KeyValuePair<string, long> assetInfo in assetDict.OrderByDescending(key => key.Value))
            {
                printout += "\n" + FileManager.SizeSuffix(assetInfo.Value) + " - " + assetInfo.Key;

            }
            Debug.Log(printout);
        }

        string GetFormattedSizeString(long bytes)
        {
            return "";
        }

        long GetCompressedFileSize(string assetPath)
        {
            string guid = AssetDatabase.AssetPathToGUID(assetPath);
            if (!string.IsNullOrEmpty(assetPath))
            {
                string assetRealPath = string.Format("{0}../../Library/metadata/{1}/{2}", Application.dataPath, guid.Substring(0, 2), guid);
                // Debug.Log("Asset path: " + assetRealPath);
                string p = Path.GetFullPath(assetRealPath);
                if (File.Exists(p))
                {
                    return new FileInfo(p).Length;
                }
            }
            return 0;
        }

        //adds the menu option to display the plugin window
        [MenuItem("NexTech/Open ARitizer")]
        public static void ShowWindow()
        {
            currentWindow = EditorWindow.GetWindow(typeof(ARitizer));
            // currentWindow.name = "ARitizer";
            currentWindow.titleContent = new GUIContent("ARitizer");
        }

        public static EditorWindow currentWindow;



        Texture2D GenerateTextureFromColor(Color colorToRender)
        {
            Texture2D tex = new Texture2D(1, 1);
            tex.SetPixel(1, 1, colorToRender);
            tex.Apply();
            return tex;
        }

        public Telepathy.Server previewServer;

        public void DeleteExperience(string experiencePath)
        {
            DestroyImmediate(selectedObjectPrefab);
            Directory.Delete(experiencePath, true);
            AssetDatabase.Refresh();
            currentMenu = ARitizer.Menu.home;
            currentExperienceMenu = ARitizer.ExperienceMenu.home;
        }

        public void BackFromHome()
        {
            ClosePreviewServer();
            currentExperienceMenu = ARitizer.ExperienceMenu.home;
            dataEditor = null;
            currentMenu = ARitizer.Menu.home;
            // if(selectedObjectPrefab != null)
            // {
            //     DestroyImmediate(selectedObjectPrefab);
            //     selectedObjectPrefab = null;
            // }
            currentSelectedExperience = -1;
        }


        void StartHost()
        {
            EditorApplication.update += NetworkUpdate;

            Telepathy.Logger.Log = Debug.Log;
            Telepathy.Logger.LogWarning = Debug.LogWarning;
            Telepathy.Logger.LogError = Debug.LogError;

            if (!previewServer.Active)
            {

                previewServer.Start(1337);
                Debug.Log("Server started");
            }
            else
            {
                Debug.Log("Server already active");
            }

        }

        void KillServer()
        {
            currentPreviewPlatform = PreviewPlatform.unknown;
            previewServer.Stop();

            EditorApplication.update -= NetworkUpdate;
        }

        void ReceivePlatformInfo(byte[] platformBytes)
        {
            string platformString = System.Text.Encoding.UTF8.GetString(platformBytes);

            if (platformString == "ios")
            {
                currentPreviewPlatform = PreviewPlatform.ios;
            }
            else if (platformString == "droid")
            {
                currentPreviewPlatform = PreviewPlatform.droid;
            }

        }

        public PreviewPlatform currentPreviewPlatform = PreviewPlatform.unknown;

        public enum PreviewPlatform
        {
            unknown,
            ios,
            droid
        }

        int lastConnectionId = -1;



        void NetworkUpdate()
        {
            // Debug.Log(IPAddress.Loopback);
            if (previewServer == null)
                return;


            Telepathy.Message msg;
            while (previewServer.GetNextMessage(out msg))
            {
                switch (msg.eventType)
                {
                    case Telepathy.EventType.Connected:
                        currentPreviewPlatform = PreviewPlatform.unknown;
                        lastConnectionId = msg.connectionId;
                        Debug.Log(msg.connectionId + " Connected_S");
                        break;
                    case Telepathy.EventType.Data:
                        Debug.Log(msg.connectionId + " Data_S: " + msg.data.Length);
                        ReceivePlatformInfo(msg.data);
                        break;
                    case Telepathy.EventType.Disconnected:
                        currentPreviewPlatform = PreviewPlatform.unknown;
                        Debug.Log(msg.connectionId + " Disconnected_S");
                        break;
                }
            }
        }

    }
}







