/****************************************************
 文件：FixPanelScript.cs
 作者：张铮
 邮箱：834207172@qq.com
 日期：2022/3/3 17:53:52
 功能：
*****************************************************/

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

namespace Stary.Evo
{
    namespace AssetEditor
    {
        public enum Mode
        {
            创建,
            以关键字更新,
            指定更新
        }

        enum RuleKey
        {
            Txt,
            Btn,
            Img
        }

        public class FixPanelScript : EditorWindow
        {
            static Dictionary<string, string> childrenNames; //对象子物体列表

            static Dictionary<string, string> Rules = new Dictionary<string, string>()
            {
                { "Txt", "Text" }, { "Btn", "Button" }, { "Img", "Image" }
            }; //命名规则

            static Transform SelTran; //选择的对象
            static List<string> names; //重名的子物体
            static List<string> btnNames; //所有按钮
            TextAsset txt; //Fix选择的脚本
            private RuleKey ruleKey;
            string input; //Fix规则
            private Mode mode;
            static Dictionary<string, string> FixChilderNames; //fix新加的子物体
            static List<string> FixBtnNames; //fix新加的按钮

            const string FixDef = "//FixStartDefiened";
            const string FixFind = "//FixStartFind";
            const string FixAddEvent = "//FixStartAddEvent";
            const string FixEvent = "//FixStartEvent";

            private bool isHelp = false;

            [MenuItem("Evo/Utility/获取子对象")]
            static void Fix()
            {
                FixPanelScript window =
                    GetWindow<FixPanelScript>(true, "获取所有子对象");
                window.Show();
            }

            private void OnEnable()
            {
                isHelp = false;
            }

            private void OnGUI()
            {
                mode = (Mode)GUILayout.Toolbar((int)mode, Enum.GetNames(typeof(Mode)));
                switch (mode)
                {
                    case Mode.创建:
                        Create();
                        break;
                    case Mode.以关键字更新:
                        FixKeyUpdate();
                        break;
                    case Mode.指定更新:
                        FixNameUpdate();
                        break;
                }
            }

            public void Create()
            {
                EditorGUILayout.Space(10);
                SelTran = EditorGUILayout.ObjectField("父物体", SelTran, typeof(Transform), true) as Transform;
                EditorGUILayout.Space(10);
                CreateButton("Create", CreateFile);
                EditorGUILayout.Space(10);
            }

            public void FixKeyUpdate()
            {
                EditorGUILayout.Space(10);
                txt = EditorGUILayout.ObjectField("脚本", txt, typeof(TextAsset), true) as TextAsset;
                EditorGUILayout.Space(10);
                SelTran = EditorGUILayout.ObjectField("父物体", SelTran, typeof(Transform), true) as Transform;
                EditorGUILayout.Space(10);
                ruleKey = (RuleKey)EditorGUILayout.EnumPopup("选择关键字进行更新", ruleKey);
                input = ruleKey.ToString();
                EditorGUILayout.Space(10);
                CreateButton("FixKeyUpdate", FixScripts);
            }


            public void FixNameUpdate()
            {
                EditorGUILayout.Space(10);
                txt = EditorGUILayout.ObjectField("脚本", txt, typeof(TextAsset), true) as TextAsset;
                EditorGUILayout.Space(10);
                SelTran = EditorGUILayout.ObjectField("父物体", SelTran, typeof(Transform), true) as Transform;
                EditorGUILayout.Space(10);
                input = EditorGUILayout.TextField("输入名字指定更新", input);
                EditorGUILayout.Space(10);
                CreateButton("FixNameUpdate", FixScripts);
            }

            public void CreateButton(string name, Action action)
            {
                GUI.color = Color.green;
                if (GUILayout.Button(name, GUILayout.MinWidth(200), GUILayout.MinHeight(50)))
                {
                    isHelp = false;
                    action?.Invoke();
                }

                GUI.color = Color.white;
                if (isHelp)
                {
                    EditorGUILayout.HelpBox("未筛选到物体", MessageType.Warning);
                }
            }

            void FixScripts()
            {
                FixChilderNames = new Dictionary<string, string>();
                FixBtnNames = new List<string>();
                names = new List<string>();
                string path = AssetDatabase.GetAssetPath(txt); //获取选定脚本的路径
                Debug.Log(path);
                if (string.IsNullOrEmpty(input))
                {
                    Debug.LogError("Error!!!");
                    return;
                }

                GetChildren(SelTran, string.Empty, input);

                StreamReader sr = new StreamReader(path, Encoding.UTF8);
                string msg = sr.ReadToEnd();
                FixDealScript(ref msg);
                sr.Close();
                StreamWriter sw = new StreamWriter(path, false, Encoding.UTF8);
                sw.Write(msg);
                sw.Close();
                AssetDatabase.Refresh();
                Debug.Log("fix ok------");
            }


            void FixDealScript(ref string msg)
            {
                StringBuilder sbDef = new StringBuilder();
                Debug.Log(FixChilderNames.Count);
                foreach (KeyValuePair<string, string> item in FixChilderNames)
                {
                    Debug.Log(item.Key);
                }

                var dic = FixChilderNames.GetEnumerator();
                while (dic.MoveNext())
                {
                    string[] names = dic.Current.Key.Split('/');
                    string name = names[names.Length - 1];
                    string value = dic.Current.Value;
                    if (!msg.Contains(name))
                    {
                        sbDef.AppendFormat("\tprivate {0} {1};", value, name);
                        sbDef.AppendLine();
                    }
                }

                sbDef.AppendLine("\t" + FixDef);
                Debug.Log(sbDef.ToString());


                StringBuilder sbFind = new StringBuilder();
                dic = FixChilderNames.GetEnumerator();
                while (dic.MoveNext())
                {
                    string[] names = dic.Current.Key.Split('/');
                    string name = names[names.Length - 1];
                    string value = dic.Current.Value;
                    string path = dic.Current.Key;
                    path = path.Substring(SelTran.name.Length + 1);
                    if (!msg.Contains(name))
                    {
                        sbFind.AppendFormat("\t\t{0} = transform.Find<{2}>(\"{1}\");", name, path, value);
                        sbFind.AppendLine();
                    }

                    if (value == Rules["Btn"]) FixBtnNames.Add(name);
                }

                sbFind.AppendLine("\t\t" + FixFind);

                StringBuilder sbAddEvent = new StringBuilder();
                for (int i = 0; i < FixBtnNames.Count; i++)
                {
                    if (!msg.Contains(FixBtnNames[i]))
                    {
                        sbAddEvent.AppendFormat("\t\tEventTriggerListener.Get({0}.gameObject).onClick = BtnClicked;",
                            FixBtnNames[i]);
                        sbAddEvent.AppendLine();
                    }
                }

                sbAddEvent.AppendLine("\t\t" + FixAddEvent);

                StringBuilder sbEvent = new StringBuilder();
                for (int i = 0; i < FixBtnNames.Count; i++)
                {
                    if (!msg.Contains(FixBtnNames[i]))
                    {
                        sbEvent.AppendFormat("\t\telse if({0}.gameObject==go)", FixBtnNames[i]);
                        CreatEvent(sbEvent, i);
                    }
                }

                sbEvent.AppendLine("\t\t" + FixEvent);
                Debug.Log(msg);
                msg = msg.Replace(FixDef, sbDef.ToString()).Replace(FixFind, sbFind.ToString())
                    .Replace(FixAddEvent, sbAddEvent.ToString()).Replace(FixEvent, sbEvent.ToString());
                Debug.Log(msg);
            }

            void CreateFile()
            {
                childrenNames = new Dictionary<string, string>();
                names = new List<string>();
                btnNames = new List<string>();
                GetChildren(SelTran);
                CreateScript(Application.dataPath + "/" + SelTran.name.Replace(" ", "") + ".cs",
                    DealScript().ToString());
            }

            void GetChildren(Transform tran, string name = "", string rule = "")
            {
                if (string.IsNullOrEmpty(name)) name = tran.name;
                int childNum = tran.childCount;
                if (string.IsNullOrEmpty(rule)) //Create
                {
                    Debug.Log(AddName(tran.name) + "进入1");
                    string value = AddName(tran.name);
                    if (!string.IsNullOrEmpty(value))
                    {
                        Debug.Log("进入" + tran.name);
                        childrenNames.Add(name, value); //符合规则，加入列表
                    }
                }
                else //fix
                {
                    string valuefix = AddName(tran.name, rule);
                    if (!string.IsNullOrEmpty(valuefix)) FixChilderNames.Add(name, valuefix);
                }

                if (childNum == 0)
                {
                    return;
                }
                else
                {
                    string temp = name;
                    for (int i = 0; i < childNum; i++)
                    {
                        temp = name;
                        temp = temp + "/" + tran.GetChild(i).name;
                        GetChildren(tran.GetChild(i), temp, rule);
                    }
                }
            }

            /// <summary>
            ///检测关键字是否包含返回字段
            /// </summary>
            /// <param name="name">新增的物体</param>
            /// <param name="rule">关键字段</param>
            /// <returns></returns>
            string AddName(string name, string rule = "")
            {
                if (names.Contains(name))
                {
                    Debug.LogError(name + "重名!!!!");
                }

                foreach (KeyValuePair<string, string> item in Rules)
                {
                    if (name.Contains(item.Key))
                    {
                        if (string.IsNullOrEmpty(rule)) //Create
                        {
                            return item.Value;
                        }
                        else //fix
                        {
                            Debug.Log(item + "----------------");
                            Debug.Log(name + "----------------" + rule);

                            if (name.Contains(rule) && mode == Mode.以关键字更新) return item.Value;
                            else if (name.Equals(rule) && mode == Mode.指定更新) return item.Value;
                            else
                            {
                                isHelp = true;
                            }
                        }
                    }
                }

                return string.Empty;
            }


            StringBuilder DealScript()
            {
                StringBuilder sb = new StringBuilder();
                sb.AppendLine("using UnityEngine;");
                sb.AppendLine("using UnityEngine.UI;");
                sb.AppendLine("using System.Text;");
                sb.AppendLine("using WFramework;");
                sb.AppendLine();
                sb.AppendLine();

                sb.AppendFormat("public class {0} : MonoBehaviour ", SelTran.name.Replace(" ", ""));
                sb.AppendLine();
                sb.AppendLine("{");

                var dic = childrenNames.GetEnumerator();
                while (dic.MoveNext())
                {
                    string[] names = dic.Current.Key.Split('/');
                    string name = names[names.Length - 1];
                    string value = dic.Current.Value;
                    sb.AppendFormat("\tprivate {0} {1};", value, name);
                    sb.AppendLine();
                }

                sb.AppendLine("\t" + FixDef);

                sb.AppendLine("\tvoid Awake() {");
                sb.AppendLine("\t\tInit();");
                sb.AppendLine("\t}");

                sb.AppendLine();
                sb.AppendLine("\tvoid Init() {");
                sb.AppendLine();

                dic = childrenNames.GetEnumerator();
                Debug.Log(childrenNames.Count);
                while (dic.MoveNext())
                {
                    string[] names = dic.Current.Key.Split('/');
                    string name = names[names.Length - 1];
                    string value = dic.Current.Value;
                    string path = dic.Current.Key;
                    path = path.Substring(SelTran.name.Length + 1);


                    sb.AppendFormat("\t\t{0} =transform.Find<{2}>(\"{1}\");", name, path, value);
                    sb.AppendLine();
                    if (value == Rules["Btn"]) btnNames.Add(name);
                }

                sb.AppendLine("\t\t" + FixFind);
                sb.AppendLine();

                for (int i = 0; i < btnNames.Count; i++)
                {
                    sb.AppendFormat("\t\tEventTriggerListener.Get({0}.gameObject).onClick = BtnClicked;", btnNames[i]);
                    sb.AppendLine();
                }

                sb.AppendLine("\t\t" + FixAddEvent);
                sb.AppendLine();

                sb.AppendLine("\t}");

                sb.AppendLine();
                sb.AppendLine("\tvoid BtnClicked(GameObject go)");
                sb.AppendLine("\t{");
                for (int i = 0; i < btnNames.Count; i++)
                {
                    if (i == 0)
                    {
                        sb.AppendFormat("\t\tif({0}.gameObject==go)", btnNames[i]);
                    }
                    else
                    {
                        sb.AppendFormat("\t\telse if({0}.gameObject==go)", btnNames[i]);
                    }

                    CreatEvent(sb, i);
                }

                sb.AppendLine("\t\t" + FixEvent);
                sb.AppendLine("\t}");
                sb.AppendLine();
                sb.AppendLine("}");

                return sb;
            }

            /// <summary>
            /// 创建方法里的Event
            /// </summary>
            /// <param name="sb"></param>
            /// <param name="index"></param>
            private void CreatEvent(StringBuilder sb, int index = 0)
            {
                sb.AppendLine();
                sb.AppendLine("\t\t{");
                sb.AppendFormat("\t\t\tDebug.Log({0}+\"Clicked\");", btnNames[index]);
                sb.AppendLine();
                sb.AppendLine("\t\t}");
            }

            void CreateScript(string path, string msg)
            {
                StreamWriter sw = new StreamWriter(path, false, Encoding.UTF8);
                sw.Write(msg);
                sw.Flush();
                sw.Close();
                Debug.Log("ok----------");
                AssetDatabase.Refresh();
            }
        }
    }
}