// Copyright (c) Microsoft Corporation. 
// Licensed under the MIT license. 

using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Reflection;
using System.Text;
using UnityEngine;
using UnityEditor;

namespace Simplygon.Unity.EditorPlugin
{
    public static class SimplygonUtils
    {
        public static string GetNewTempDirectory()
        {
            string simplygon9TempDirectory = Environment.GetEnvironmentVariable("SIMPLYGON_9_TEMP");

            if (string.IsNullOrWhiteSpace(simplygon9TempDirectory))
            {
                simplygon9TempDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Temp", "Simplygon");
                Debug.LogWarning("SIMPLYGON_9_TEMP environment variable missing. Please restart Unity and Unity Hub and try again.");
            }
            simplygon9TempDirectory = Environment.ExpandEnvironmentVariables(simplygon9TempDirectory);
            string tempDirectory = Path.Combine(simplygon9TempDirectory, Guid.NewGuid().ToString());
            if (!Directory.Exists(tempDirectory))
            {
                Directory.CreateDirectory(tempDirectory);
            }

            return tempDirectory;
        }

        public static string GetTempPipelineFileName()
        {
            string tempPipelineDirectory = SimplygonUtils.GetNewTempDirectory();
            if (!string.IsNullOrEmpty(tempPipelineDirectory))
            {
                string tempPipelineFile = Path.Combine(tempPipelineDirectory, "pipeline.json");
                return tempPipelineFile;
            }
            return null;
        }

        public static string[] GetSelectionSetNamesInSelection()
        {
            return Resources.FindObjectsOfTypeAll<SimplygonSelectionSet>().Where(i => (Selection.Contains(i.gameObject) || Selection.gameObjects.Any(p => i.transform.IsChildOf(p.transform))) && i.gameObject.GetComponent<Camera>() == null).Select(i => i.SelectionSetName).ToArray();
        }

        public static string[] GetCameraObjectNamesInScene()
        {
            return Resources.FindObjectsOfTypeAll<SimplygonSelectionSet>().Where(i => i.gameObject.GetComponent<Camera>() != null || ((Selection.Contains(i.gameObject) || Selection.gameObjects.Any(p => i.transform.IsChildOf(p.transform))) && i.gameObject.GetComponent<Camera>() == null)).Select(i => i.SelectionSetName).ToArray();
        }

        private static int LODColorIndex;
        public static Color GetLODColor()
        {
            List<Color> lodColors = new List<Color>()
            {
                new Color(0x27/255.0f, 0xa9/255.0f, 0xe0/255.0f), // Lod 1
                new Color(0x37/255.0f, 0xdd/255.0f, 0x37/255.0f), // Lod 2
                new Color(0xff/255.0f, 0x00/255.0f, 0x63/255.0f), // Lod 3
                new Color(0xdd/255.0f, 0x9b/255.0f, 0x37/255.0f), // Lod 4
                new Color(0x00/255.0f, 0x75/255.0f, 0xad/255.0f), // Lod 5
                new Color(0xdd/255.0f, 0x37/255.0f, 0xdd/255.0f), // Lod 6
                new Color(0x69/255.0f, 0x91/255.0f, 0x57/255.0f), // Lod 7
                new Color(0x3b/255.0f, 0x47/255.0f, 0xbc/255.0f), // Lod 8
                new Color(0xb9/255.0f, 0xdf/255.0f, 0x1f/255.0f), // Lod 9
                new Color(0x9f/255.0f, 0x40/255.0f, 0xbf/255.0f), // Lod 10
            };
            return lodColors[(LODColorIndex++) % 10];
        }

        private static Texture2D simplygonLogoTexture;
        public static Texture2D LoadSimplygonLogo()
        {
            if(simplygonLogoTexture == null)
            {
                simplygonLogoTexture = LoadDllResource("simplygon_process_enabled.png", 256, 128);
            }
            return simplygonLogoTexture;
        }

        private static Texture2D transparentSimplygonLogoTexture;
        public static Texture2D LoadTransparentSimplygonLogo()
        {
            if (transparentSimplygonLogoTexture == null)
            {
                transparentSimplygonLogoTexture = LoadDllResource("simplygon_process_disabled.png", 256, 128);
            }
            return transparentSimplygonLogoTexture;
        }

        private static Texture2D LoadDllResource(string resourceName, int width, int height)
        {
#if USEDLLRESOURCE
            Texture2D texture = new Texture2D(width, height, TextureFormat.ARGB32, true, true);

            var myAssembly = Assembly.GetExecutingAssembly();

            var myStream = myAssembly.GetManifestResourceStream("SimplygonUnityEditorPlugin." + resourceName);

            if (myStream != null)
            {
                texture.LoadImage(ReadToEnd(myStream));
                myStream.Close();

                return texture;
            }
#else
            string[] guids = AssetDatabase.FindAssets(Path.GetFileNameWithoutExtension(resourceName));
            if (guids.Length > 0)
            {
                string path = AssetDatabase.GUIDToAssetPath(guids[0]);
                Texture2D texture = AssetDatabase.LoadAssetAtPath<Texture2D>(path);
                return texture;
            }
#endif
            else
            {
                Debug.LogError(string.Format("Failed to load {0} resource", resourceName));
            }

            return null;
        }

        private static byte[] ReadToEnd(Stream stream)
        {
            long originalPosition = stream.Position;

            stream.Position = 0;
            try
            {
                byte[] readBuffer = new byte[4096];
                int totalBytesRead = 0;
                int bytesRead;

                while ((bytesRead = stream.Read(readBuffer, totalBytesRead, readBuffer.Length - totalBytesRead)) > 0)
                {
                    totalBytesRead += bytesRead;

                    if (totalBytesRead == readBuffer.Length)
                    {
                        int nextByte = stream.ReadByte();

                        if (nextByte != -1)
                        {
                            byte[] temp = new byte[readBuffer.Length * 2];

                            Buffer.BlockCopy(readBuffer, 0, temp, 0, readBuffer.Length);

                            Buffer.SetByte(temp, totalBytesRead, (byte)nextByte);

                            readBuffer = temp;

                            totalBytesRead++;
                        }
                    }
                }

                byte[] buffer = readBuffer;

                if (readBuffer.Length != totalBytesRead)
                {
                    buffer = new byte[totalBytesRead];
                    Buffer.BlockCopy(readBuffer, 0, buffer, 0, totalBytesRead);
                }

                return buffer;
            }

            finally
            {

                stream.Position = originalPosition;

            }

        }
    }
}
