using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Xml.Linq;

namespace Xmind2UnityConfigCore
{
    public static class TopicExt
    {
        public static int ToUnity(string xmindPath, string outDirPath)
        {
            if (!File.Exists(xmindPath))
            {
                Console.WriteLine($"{xmindPath} is not exist!!");
                return -1;
            }
            if(string.IsNullOrEmpty(outDirPath))
                outDirPath = System.IO.Path.GetDirectoryName(xmindPath);

            //var zipArchive = ZipFile.o(openFileDialog.FileName);
            //zipArchive.

            //解压缩的临时路径
            string tempPath = System.IO.Path.Combine(
                    System.IO.Path.GetTempPath(),
                    System.IO.Path.GetFileNameWithoutExtension(xmindPath));

            if (Directory.Exists(tempPath))
                Directory.Delete(tempPath, true);
            
            ZipFile.ExtractToDirectory(xmindPath, tempPath);

            string filePath = System.IO.Path.Combine(tempPath, "content.json");
            string json = File.ReadAllText(filePath);

            //var xmind = JsonConvert.DeserializeObject<XMindRootTopic[]>(json);

            //转义title
            //string unescape = System.Text.RegularExpressions.Regex.Unescape(str);

            JArray jArray = JsonConvert.DeserializeObject(json) as JArray;

            var jobject_topic = jArray.First() as JObject;
            var jobject_rootTopic = jobject_topic["rootTopic"] as JObject;
            Topic rootTopic = ToTopic(jobject_rootTopic);

            //json = Newtonsoft.Json.JsonConvert.SerializeObject(rootTopic, Formatting.Indented);
            //Console.WriteLine(json);

            //string path = System.IO.Path.Combine(
            //    System.IO.Path.GetDirectoryName(openFileDialog.FileName),
            //    System.IO.Path.GetFileNameWithoutExtension(openFileDialog.FileName)+".json");

            //File.WriteAllText(path, json);

            ToUnity(rootTopic, outDirPath);
            Console.WriteLine($@"success!!! out to {System.IO.Path.Combine(outDirPath, "unity")}");
            return 0;
        }
        static Topic ToTopic(JObject jObject)
        {
            var topic = new Topic();
            string str = jObject["title"].ToString();
            string unescape = System.Text.RegularExpressions.Regex.Unescape(str);
            topic.title = unescape;
            if (jObject.ContainsKey("children"))
            {
                var children = jObject["children"] as JObject;
                if (!children.ContainsKey("attached"))
                {
                    //什么都没有，假的
                    return topic;
                }

                var attached = children["attached"] as JArray;
                foreach (JObject subTopic in attached)
                {
                    topic.children.Add(ToTopic(subTopic));
                }
            }
            return topic;
        }


        static void ToUnity(Topic rootTopic, string path)
        {
            path = System.IO.Path.Combine(path, "unity");
            if (!Directory.Exists(path))
                Directory.CreateDirectory(path);

            //register \ntype=\"IUnityContainer\"\nname=\"root\"\n(根容器)

            //生成relationship.json

            RelationShip relationShip = ToRelationShip(rootTopic, path);
            string json = Newtonsoft.Json.JsonConvert.SerializeObject(relationShip, Newtonsoft.Json.Formatting.Indented);
            File.WriteAllText(System.IO.Path.Combine(path, "relationship.json"), json);

        }


        static RelationShip ToRelationShip(Topic topic, string path)
        {
            RelationShip relationShip = new RelationShip();

            var x_root = ToXElement(topic.title);

            string name = x_root.Attribute("name").Value;
            relationShip.Name = name;

            foreach (var subTopic in topic.children)
            {
                if (subTopic.title.Contains("(config文件)"))
                {
                    //这是config文件
                    //root.config\n(config文件)
                    var ss = subTopic.title.Split('\n');
                    string filename = ss[0].Trim();
                    relationShip.Path.Add(filename);
                    string filepath = System.IO.Path.Combine(path, filename);
                    //创建 xxx.config 文件 
                    ToConfig(subTopic.children, filepath);
                }
                else //if (unescape.StartsWith("register"))
                {
                    //这是子容器
                    var subRelationShip = ToRelationShip(subTopic, path);
                    relationShip.Children.Add(subRelationShip);
                }

            }
            return relationShip;
        }


        static XElement ToXElement(string title)
        {
            //把全部 中文的 （） 替换为 英文的 ()
            title = new string(title.Select((c) =>
            {
                switch (c)
                {
                    case '（':
                        return '(';
                    case '）':
                        return ')';
                    case '“':
                        return '"';
                    case '”':
                        return '"';
                    default:
                        return c;
                }
            }).ToArray());

            //删除全部注解
            Regex regex_instruction = new Regex(@"\([\s\S]*\)");

            title = regex_instruction.Replace(title, "");

            //全部注解删除后，什么也没有
            if (string.IsNullOrEmpty(title))
                return null;


            Regex regex_xml = new Regex(@"\<([\s\S]*)/\>");
            var match = regex_xml.Match(title);
            if (match.Success)
            {
                //它就是标准的xml格式
                //把头尾的 < /> 删除
                title = match.Groups[1].Value;
            }
            title = title.Trim();

            //什么也没有
            if (string.IsNullOrEmpty(title))
                return null;

            //把全部 中文的 “” 替换为 英文的 "


            Regex regex = new Regex(@"(\S+)\s*=\s*""([\s\S]*)""");

            var ss = title.Split('\n', ' ');

            var xname = ss.First().Trim();

            XElement x = new XElement(xname);
            for (int i = 1; i < ss.Length; i++)
            {
                var s = ss[i].Trim();
                match = regex.Match(s);
                if (match.Success)
                {
                    string attrName = match.Groups[1].Value;
                    string attrValue = match.Groups[2].Value;
                    x.Add(new XAttribute(attrName, attrValue));
                }
            }
            return x;
        }
        static XElement ToXElement(Topic topic)
        {
            XElement x = ToXElement(topic.title);
            if (x == null)
                return null;

            foreach (var sub in topic.children)
            {
                var x_sub = ToXElement(sub);
                if (x_sub == null)
                    continue;
                x.Add(x_sub);
            }
            return x;
        }

        static void ToConfig(List<Topic> topics, string filepath)
        {
            XDocument xdoc = new XDocument();
            //创建根元素
            XElement x_configuration = new XElement("configuration");
            //把根元素添加到文件中
            xdoc.Add(x_configuration);

            XElement x_configSections = new XElement("configSections");
            x_configuration.Add(x_configSections);

            XElement x_section = new XElement("section");
            x_configSections.Add(x_section);
            x_section.Add(
                new XAttribute("name", "unity"),
                new XAttribute("type", "Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,Unity.Configuration")
                );


            //XNamespace ns = "http://schemas.microsoft.com/practices/2010/unity";
            XElement x_unity = new XElement("unity");// (ns+"unity");
            x_configuration.Add(x_unity);


            //找出全部assembly 与 alias

            var assemblies_topics = topics.FindAll(t => t.title.Trim().StartsWith("assembly"));
            foreach (var assemblies_topic in assemblies_topics)
            {
                foreach (var assembly_topic in assemblies_topic.children)
                {
                    XElement x_assembly = new XElement("assembly");
                    x_unity.Add(x_assembly);
                    x_assembly.Add(new XAttribute("name", assembly_topic.title));

                    foreach (var namespace_topic in assembly_topic.children)
                    {
                        XElement x_namespace = new XElement("namespace");
                        x_unity.Add(x_namespace);
                        x_namespace.Add(new XAttribute("name", namespace_topic.title));
                    }
                }
            }

            var aliass_topics = topics.FindAll(t => t.title.Trim().StartsWith("alias"));
            foreach (var aliass_topic in aliass_topics)
            {
                foreach (var alias_topic in aliass_topic.children)
                {
                    XElement x_alias = new XElement("alias");
                    x_unity.Add(x_alias);
                    x_alias.Add(new XAttribute("alias", alias_topic.title));
                    x_alias.Add(new XAttribute("type", alias_topic.children[0].title));
                }
            }


            topics.RemoveAll(t => t.title.Trim().StartsWith("assembly") || t.title.Trim().StartsWith("alias"));



            //容器
            XElement x_container = new XElement("container");
            x_unity.Add(x_container);

            foreach (var topic in topics)
            {
                var x = ToXElement(topic);
                if (x == null)
                    continue;
                x_container.Add(x);
            }

            //保存
            xdoc.Save(filepath);
        }
    }


}
