using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Codice.Client.BaseCommands;
using UnityEditor;
using UnityEngine;

public class MapCreator : EditorWindow
{
    private int toolmode;
    private string[] toolmodes = new string[] {"MapCreator", "BatchTool"};
    //MapCreator所需参数
    private Material mat;
    private int maptype = 0,_maptype;
    private string[] maptypes = new string[] {"Mask Map", "Detail Map", "Custom"};
    private Texture2D metallic, occlusion, detailmask, smoothness, deAbedo, deNormal, deSmoothness;
    private bool useRoughness;
    //用以记录输入是否更新
    private bool changed;
    private Texture2D _metallic, _occlusion, _detailmask, _smoothness, _deAbedo, _deNormal, _deSmoothness;
    private bool _useRoughness;
    //BatchTool所需参数
    bool resize , fixsettings, createmask ,deleteunused;
    private Vector2 resizeWH = new Vector2(2048,2048);
    private string _folderPath;
    protected string FolderPath {
        get {
            if (string.IsNullOrEmpty(_folderPath))
                _folderPath = "Assets";
            return _folderPath;
        }

        set {
            string pstr = Directory.GetParent(Application.dataPath).FullName;
            pstr = pstr.Replace("\\", "/");
            if (value != null && value.Contains(pstr))
                _folderPath = value.Replace(pstr + "/", "");
            else
                _folderPath = value;
        }
    }
    
    //创建菜单栏
    [MenuItem("Window/Tools/TextureTool")]
    //创建窗口
    static void OpenMapCreator()
    {
        MapCreator mapCreator = GetWindow<MapCreator>("TextureTool");
        mapCreator.Init();
    }
    //初始化材质
    private void Init()
    {
        if (mat == null)
        {
            mat = new Material(Shader.Find("Hidden/MapCreator"));//create material
            mat.hideFlags = HideFlags.HideAndDontSave;
        }
    }
    //窗口界面
    public void OnGUI()
    {
        //选择工具模式
        GUILayout.Space(8);
        EditorGUILayout.BeginHorizontal();
        GUILayout.FlexibleSpace();
        toolmode = GUILayout.Toolbar(toolmode, toolmodes,GUILayout.Width(250),GUILayout.Height(24));
        GUILayout.FlexibleSpace();
        EditorGUILayout.EndHorizontal();
        //MapCreator GUI
        if(toolmode == 0) MapCreatorGUI();
        else if(toolmode == 1) BatchToolGUI();
    }

    private void MapCreatorGUI()
    {
        //选择生成贴图类型
        GUILayout.Space(10);
        maptype = EditorGUILayout.Popup("Map Type", maptype, maptypes);
        GUILayout.Space(10);
        //绘制贴图盒
        if (maptype == 0 )//mask map
        {
            useRoughness = EditorGUILayout.Toggle("use Roughness?", useRoughness);
            MaskMapInput();
        }
        else if (maptype == 1) //detail map
        {
            useRoughness = EditorGUILayout.Toggle("use Roughness?", useRoughness);
            DetailMapInput();
        }
        else//custom map
        {
            EditorGUILayout.Space(20);
            CustomInput();
        }
        if (maptype != _maptype || useRoughness!=_useRoughness)
        {
            changed = true;
            _maptype = maptype;
            _useRoughness = useRoughness;
        }
        //绘制预览贴图
        Preview();
        //绘制创建按钮
        EditorGUILayout.BeginHorizontal();
        if (GUILayout.Button("Create Map"))
        {
            GenPictureAuto();
        }
        if (GUILayout.Button("...", GUILayout.Width(40)))
        {
            GenPictureCustom();
        }
        EditorGUILayout.EndHorizontal();
        //绘制批处理按钮
        if (maptype == 0)
        {
            EditorGUILayout.BeginHorizontal();
            if (GUILayout.Button("Batch Create!"))
            {
                BatchCreate();
            }

            EditorGUILayout.EndHorizontal();
        }
    }

    private void BatchToolGUI()
    {
        //选择批处理文件夹
        GUILayout.Space(10);
        SelectFolderPath();
        GUILayout.Space(10);
        GUILayout.Label("Select functions:");
        //是否resize
        EditorGUILayout.BeginHorizontal();
        if (resize = GUILayout.Toggle(resize, "Resize"))
        {
            resizeWH.x = EditorGUILayout.FloatField(resizeWH.x);
            resizeWH.y = EditorGUILayout.FloatField(resizeWH.y);
        }
        EditorGUILayout.EndHorizontal();
        //是否检查导入设置
        EditorGUILayout.BeginHorizontal();
        fixsettings = GUILayout.Toggle(fixsettings, "Fix Import Settings");
        EditorGUILayout.EndHorizontal();
        //是否生成mask map
        EditorGUILayout.BeginHorizontal();
        if (createmask = GUILayout.Toggle(createmask, "Create Mask Maps"))
        {
            deleteunused = GUILayout.Toggle(deleteunused, "Delete Unused Map?");
        }
        EditorGUILayout.EndHorizontal();
        //开始批量处理
        BeginBatch();
    }
    private void MaskMapInput()
    {
        EditorGUILayout.BeginHorizontal("Box");
        _metallic = TextureField("Metallic", metallic);
        if (_metallic != metallic)
        {
            metallic = _metallic;
            changed = true;
        }
        _occlusion = TextureField("Occlusion", occlusion);
        if (_occlusion != occlusion)
        {
            occlusion = _occlusion;
            changed = true;
        }

        _detailmask = TextureField("Detailmask", detailmask);
        if (_detailmask != detailmask)
        {
            detailmask = _detailmask;
            changed = true;
        }

        if (!useRoughness)
        {
            _smoothness = TextureField("Smoothness", smoothness);
        }
        else
        {
            _smoothness = TextureField("Roughness", smoothness);
        }
        if (_smoothness != smoothness)
        {
            smoothness = _smoothness;
            changed = true;
        }
        EditorGUILayout.EndHorizontal();
    }

    private void DetailMapInput()
    {
        EditorGUILayout.BeginHorizontal("Box");
        _deAbedo = TextureField("Abedo", deAbedo);
        if (_deAbedo != deAbedo)
        {
            deAbedo = _deAbedo;
            changed = true;
        }
        _deNormal = TextureField("Normal", deNormal);
        if (_deNormal != deNormal)
        {
            deNormal = _deNormal;
            changed = true;
        }
        if (!useRoughness)
        {
            _deSmoothness = TextureField("Smoothness", deSmoothness);
        }
        else
        {
            _deSmoothness = TextureField("Roughness", deSmoothness);
        }
        if (_deSmoothness != deSmoothness)
        {
            deSmoothness = _deSmoothness;
            changed = true;
        }
        EditorGUILayout.EndHorizontal();
    }
    private void CustomInput()
    {
        EditorGUILayout.BeginHorizontal("Box");
        _metallic = TextureField("R", metallic);
        if (_metallic != metallic)
        {
            metallic = _metallic;
            changed = true;
        }
        _occlusion = TextureField("G", occlusion);
        if (_occlusion != occlusion)
        {
            occlusion = _occlusion;
            changed = true;
        }
        _detailmask = TextureField("B", detailmask);
        if (_detailmask != detailmask)
        {
            detailmask = _detailmask;
            changed = true;
        }
        _smoothness = TextureField("A", smoothness);
        if (_smoothness != smoothness)
        {
            smoothness = _smoothness;
            changed = true;
        }
        EditorGUILayout.EndHorizontal();
    }
    private Texture2D TextureField(string name, Texture2D texture)
    {
        EditorGUILayout.BeginVertical();
        var style = new GUIStyle(GUI.skin.label);
        style.alignment = TextAnchor.MiddleCenter;
        style.fixedWidth = 80;
        GUILayout.Label(name,style);
        Texture2D result = EditorGUILayout.ObjectField(texture, typeof(Texture2D), false, GUILayout.Width(80),GUILayout.Height(80)) as Texture2D;
        EditorGUILayout.EndVertical();
        return result;
    }

    
    private Texture2D preview = null;
    private void Preview()
    {
        EditorGUILayout.BeginHorizontal();
        GUILayout.Label("Preview Output");
        EditorGUILayout.EndHorizontal();
        //居中绘制贴图框
        EditorGUILayout.BeginHorizontal();
        Rect previewRect = new Rect(this.position.width / 2 - 75, 230, 150, 150);
        //初始绘制默认纹理
        if (preview == null)
        {
            preview = Texture2D.blackTexture;
        }
        //每当输入参数改变时，刷新材质
        if (changed)
        {
            //path只用于自动更名保存，这里其实不需要
            string path = "";
            preview = GetTexture(ref path);
            changed = false;
        }
        //在贴图框中绘制贴图
        EditorGUI.DrawPreviewTexture(previewRect,preview);
        EditorGUILayout.Space(170);
        EditorGUILayout.EndHorizontal();
    }
    
    //根据其他贴图的路径自动保存贴图
    private void GenPictureAuto()
    {
        string savepath = "";
        Texture2D output = GetTexture(ref savepath);
        if(maptype == 0) savepath += "_mask";
        else if (maptype == 1) savepath += "_detailmap";
        byte[] bytes = output.EncodeToPNG();
        FileStream file = File.Open(savepath + ".png", FileMode.Create);
        BinaryWriter writer = new BinaryWriter(file);
        writer.Write(bytes);
        file.Close();
        Texture2D.DestroyImmediate(output);
        output = null;
        AssetDatabase.Refresh();
        var im = AssetImporter.GetAtPath(savepath + ".png") as TextureImporter;
        im.sRGBTexture = false;
        im.SaveAndReimport();
    }
    //手动保存贴图
    private void GenPictureCustom()
    {
        string savepath = "";
        Texture2D output = GetTexture(ref savepath);
        string savePath = EditorUtility.SaveFilePanel("Save", Application.dataPath, "Texture.png", "png");
        File.WriteAllBytes(savePath,output.EncodeToPNG());
        AssetDatabase.Refresh();
        var im = AssetImporter.GetAtPath(savepath + ".png") as TextureImporter;
        im.sRGBTexture = false;
        im.SaveAndReimport();
    }
    //KEY FUNCTION 渲染贴图至RT
    private Texture2D GetTexture(ref string path)
    {   //保持新创建的贴图与原贴图尺寸相同
        Vector2 rtSize = new Vector2(2048, 2048);
        //用于路径更名
        char[] splitor = {'_'};

        //传入shader所需参数
        Shader.SetGlobalInt("maptype", maptype);
        if (!useRoughness) Shader.SetGlobalInt("useRoughness", 0);
        else Shader.SetGlobalInt("useRoughness", 1);
        //传入shader所需贴图
        if (maptype == 1)
        {
            if (deAbedo != null)
            {
                mat.SetTexture("_deAbedo", deAbedo);
                rtSize.x = deAbedo.width;
                rtSize.y = deAbedo.height;
                path = AssetDatabase.GetAssetPath(deAbedo);
                path = Reverse(path);
                path = path.Split(splitor, 2)[1];
                path = Reverse(path);
            }
            if (deNormal != null)
            {
                mat.SetTexture("_deNormal", deNormal);
                rtSize.x = deNormal.width;
                rtSize.y = deNormal.height;
                path = AssetDatabase.GetAssetPath(deNormal);
                path = Reverse(path);
                path = path.Split(splitor, 2)[1];
                path = Reverse(path);
            }
            if (deSmoothness != null)
            {
                mat.SetTexture("_deSmoothness", deSmoothness);
                rtSize.x = deSmoothness.width;
                rtSize.y = deSmoothness.height;
                path = AssetDatabase.GetAssetPath(deSmoothness);
                path = Reverse(path);
                path = path.Split(splitor, 2)[1];
                path = Reverse(path);
            }
        }
        else
        {
            if (metallic != null)
            {
                mat.SetTexture("_Metallic", metallic);
                rtSize.x = metallic.width;
                rtSize.y = metallic.height;
                path = AssetDatabase.GetAssetPath(metallic);
                path = Reverse(path);
                path = path.Split(splitor, 2)[1];
                path = Reverse(path);
            }
            else if(maptype==0) mat.SetTexture("_Metallic", Texture2D.blackTexture);
            if (occlusion != null)
            {
                mat.SetTexture("_Occlusion", occlusion);
                rtSize.x = occlusion.width;
                rtSize.y = occlusion.height;
                path = AssetDatabase.GetAssetPath(occlusion);
                path = Reverse(path);
                path = path.Split(splitor, 2)[1];
                path = Reverse(path);
            }
            else if(maptype==0) mat.SetTexture("_Occlusion", Texture2D.whiteTexture);
            if (detailmask != null)
            {
                mat.SetTexture("_DetailMask", detailmask);
                rtSize.x = detailmask.width;
                rtSize.y = detailmask.height;
                path = AssetDatabase.GetAssetPath(detailmask);
                path = Reverse(path);
                path = path.Split(splitor, 2)[1];
                path = Reverse(path);
            }
            else if(maptype==0) mat.SetTexture("_DetailMask", Texture2D.blackTexture);
            if (smoothness != null)
            {
                mat.SetTexture("_Smoothness", smoothness);
                rtSize.x = smoothness.width;
                rtSize.y = smoothness.height;
                path = AssetDatabase.GetAssetPath(smoothness);
                path = Reverse(path);
                path = path.Split(splitor, 2)[1];
                path = Reverse(path);
            }
            else if(maptype==0) mat.SetTexture("_Smoothness", Texture2D.whiteTexture);
        }
        
        //创建RT作为Blit()的渲染目标target
        RenderTexture tempRT = new RenderTexture((int)rtSize.x, (int)rtSize.y, 16, RenderTextureFormat.ARGB32);
        tempRT.Create();
        //创建texture作为Blit()的源材质source
        Texture2D temp2 = new Texture2D(tempRT.width, tempRT.height, TextureFormat.ARGB32, false);
        //计算贴图
        Graphics.Blit(temp2,tempRT,mat);
        
        //暂存当前激活的RT
        RenderTexture preview = RenderTexture.active;
        //激活渲染结果RT并从中读取数据
        RenderTexture.active = tempRT;
        Texture2D output = new Texture2D(tempRT.width, tempRT.height, TextureFormat.ARGB32, false);
        output.ReadPixels(new Rect(0,0,tempRT.width,tempRT.height),0,0);
        output.Apply();
        //还原激活的RT
        RenderTexture.active = preview;

        return output;
    }
    public string Reverse(string text)
    {
        char[] cArray = text.ToCharArray();
        string reverse = String.Empty;
        for (int i = cArray.Length - 1; i > -1; i--)
        {
            reverse += cArray[i];
        }
        return reverse;
    }
    private void BatchCreate()
    {
        string path = "";
        Texture2D output = GetTexture(ref path);
        path = path.Replace("/Texture","^");
        path = path.Split('^')[0] + "/Textures";
        DirectoryInfo directoryInfo = new DirectoryInfo(path);//获得文件夹的info
        FileSystemInfo[] fileSystemInfos = directoryInfo.GetFileSystemInfos();//获得文件夹中文件的info
        foreach (var file in fileSystemInfos)
        {
            if(file is DirectoryInfo) continue;//忽略文件夹
            Debug.Log(file);
        }
    }

    private void SelectFolderPath()
    {
        GUILayout.BeginHorizontal();
        {
            FolderPath = EditorGUILayout.TextField("Textures Folder", FolderPath);
            //从弹出窗口选择路径
            if (GUILayout.Button("...", GUILayout.Width(25))) {
                FolderPath = EditorUtility.OpenFolderPanel("Select a folder", "Assets", "");
            }
            //EditorGUIUtility.labelWidth = 0;
        }
        GUILayout.EndHorizontal();
    }

    private void BeginBatch()
    {
        EditorGUILayout.Space(10);
        EditorGUILayout.BeginHorizontal();
        if (GUILayout.Button("Start"))
        {
            if (!Directory.Exists(FolderPath)) {
                Debug.LogError("Folder isn't exist!");
                return;
            }
            
            if (resize) ResizeTextures();
            if (createmask) BatchMask();
            if (fixsettings) FixSettings();
        }
        EditorGUILayout.EndHorizontal();
    }
    private void ResizeTextures()
    {
        var tempTexture = new Texture2D((int) resizeWH.x, (int) resizeWH.y, TextureFormat.ARGB32, false);
        //获取文件夹下全部材质
        var texture2Ds = AssetDatabase.FindAssets ("t:Texture2D", new[]{FolderPath});
        foreach (var textureguid in texture2Ds)
        {
            var texturepath = AssetDatabase.GUIDToAssetPath(textureguid);
            var texture = AssetDatabase.LoadAssetAtPath<Texture2D>(texturepath);
            //若不需要重新调整大小，则跳过
            Vector2 currentsize = new Vector2(texture.width, texture.height);
            if(currentsize == resizeWH) 
                continue;
            var rt = RenderTexture.GetTemporary((int) resizeWH.x, (int) resizeWH.y, 0, RenderTextureFormat.ARGB32);
            rt.DiscardContents();
            Graphics.Blit(texture,rt);
            RenderTexture.active = rt;
            tempTexture.ReadPixels(new Rect(0,0,rt.width,rt.height),0,0);
            tempTexture.Apply();
            if (texturepath.EndsWith(".png"))
            {   //如果该材质含有tif标签，则跳过
                var im = AssetImporter.GetAtPath (texturepath);
                if (im.userData.Contains ("FromTIF;"))
                    continue;
                File.WriteAllBytes(texturepath, tempTexture.EncodeToPNG());
            }
            else if (texturepath.EndsWith(".jpg"))
            {
                File.WriteAllBytes(texturepath, tempTexture.EncodeToJPG());
            }
            else if (texturepath.EndsWith(".tif"))
            {
                Debug.LogWarningFormat(texturepath + "has been saved as PNG.");
                string newname = texturepath.Substring(0, texturepath.Length - 3) + "png";
                File.WriteAllBytes(newname, tempTexture.EncodeToPNG());
                //为tif转换的png图片增加标签
                var im = AssetImporter.GetAtPath(newname);
                im.userData += "FromTIF;";
            }
            RenderTexture.ReleaseTemporary(rt);
        }
        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();
    }

    private void BatchMask()
    {
        var texture2Ds = AssetDatabase.FindAssets ("t:Texture2D", new[]{FolderPath});
        string currentTexture = "";
        maptype = 0;
        bool hasM=false, hasAO=false,hasDM = false, hasR=false;
        foreach (var textureguid in texture2Ds)
        {
            var texturepath = AssetDatabase.GUIDToAssetPath(textureguid);
            //获取前缀前的材质名，用于识别贴图组
            string exactname = Reverse(texturepath);
            exactname = exactname.Split(new char[]{'_'}, 2)[1];
            exactname = Reverse(exactname);
            //当读入新的贴图名时，生成上一贴图组的maskmap
            if (exactname != currentTexture)
            {
                //当至少含有一张生成maskmap所需贴图时
                if (hasM || hasR || hasDM || hasAO)
                {
                    //将没有的贴图改为默认值，以免用到上一贴图组的贴图
                    if(!hasM) metallic = null;
                    if(!hasAO) occlusion = null;
                    if(!hasDM) detailmask = null;
                    if(!hasR) smoothness = null;
                    GenPictureAuto();
                    //如果需要删除hdrp不需要的贴图
                    if (deleteunused)
                    {
                        string deletepath;
                        if (hasM)
                        {
                            deletepath = AssetDatabase.GetAssetPath(metallic);
                            AssetDatabase.DeleteAsset(deletepath);
                        }
                        if (hasAO)
                        {
                            deletepath = AssetDatabase.GetAssetPath(occlusion);
                            AssetDatabase.DeleteAsset(deletepath);
                        }
                        if (hasDM)
                        {
                            deletepath = AssetDatabase.GetAssetPath(detailmask);
                            AssetDatabase.DeleteAsset(deletepath);
                        }
                        if (hasR)
                        {
                            deletepath = AssetDatabase.GetAssetPath(smoothness);
                            AssetDatabase.DeleteAsset(deletepath);
                        }
                        AssetDatabase.Refresh();
                    }
                }
                //重置信息
                hasM = false; hasR = false; hasDM = false; hasAO = false;
                currentTexture = exactname;
            }
            //若为金属度贴图
            if (texturepath.Contains("_metallic") || texturepath.Contains("_Metallic"))
            {
                hasM = true;
                metallic = AssetDatabase.LoadAssetAtPath<Texture2D>(texturepath);
            }
            //若为ao
            else if(texturepath.Contains("_ao") || texturepath.Contains("_AO") 
                                               || texturepath.Contains("_occlusion")|| texturepath.Contains("_Occlusion")) 
            {
                hasAO = true;
                occlusion = AssetDatabase.LoadAssetAtPath<Texture2D>(texturepath);
            }
            //若为Smoothness
            else if(texturepath.Contains("_smoothness") || texturepath.Contains("_Smoothness"))
            {
                hasR = true;
                useRoughness = false;
                smoothness = AssetDatabase.LoadAssetAtPath<Texture2D>(texturepath);
            }
            //若为Roughness
            else if(texturepath.Contains("_Roughness") || texturepath.Contains("_roughness"))
            {
                hasR = true;
                useRoughness = true;
                smoothness = AssetDatabase.LoadAssetAtPath<Texture2D>(texturepath);
            }
            //若为DetailMask
            else if(texturepath.Contains("_DetailMask") || texturepath.Contains("_detailmask"))
            {
                hasDM = true;
                detailmask = AssetDatabase.LoadAssetAtPath<Texture2D>(texturepath);
            }
        }
    }

    private void FixSettings()
    {
        //获取文件夹下全部材质
        var texture2Ds = AssetDatabase.FindAssets ("t:Texture2D", new[]{FolderPath});
        foreach (var textureguid in texture2Ds)
        {
            var texturepath = AssetDatabase.GUIDToAssetPath(textureguid);
            //从路径获取importer
            var importer = AssetImporter.GetAtPath(texturepath) as TextureImporter;
            //只处理2D材质
            if (importer.textureShape == TextureImporterShape.Texture2D)
            {
                //法线贴图，type设置为normal
                if (texturepath.Contains("_normal")||texturepath.Contains("_Normal"))
                {
                    if (importer.textureType != TextureImporterType.NormalMap)
                    {
                        importer.textureType = TextureImporterType.NormalMap;
                        importer.SaveAndReimport();
                    }
                    continue;
                }
                //固有色贴图，开启sRGB
                if (texturepath.Contains("_albedo") || texturepath.Contains("_Albedo") ||
                    texturepath.Contains("_basecolor") || texturepath.Contains("_BaseColor") ||
                    texturepath.Contains("_baseColor")|| texturepath.Contains("_color") )
                {
                    if (!importer.sRGBTexture)
                    {
                        importer.sRGBTexture = true;
                        importer.SaveAndReimport();
                    }
                    continue;
                }
                //其他贴图，不开启sRGB
                else
                {
                    if (importer.sRGBTexture)
                    {
                        importer.sRGBTexture = false;
                        importer.SaveAndReimport();
                    }
                }
            }

        }
    }
}


//by Erin.Z erinz.xyz
//published on 28/4/2022
