using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

namespace MKVTest
{
    internal class SerializeMkvInfo
    {
        public List<string> SerializeFile(string filePath)
        {
            var file = File.ReadAllLines(filePath);
            if (file.Length == 0) return new List<string>();
            var lastDepthLevel = 0;
            //var xml = new StringBuilder();
            var stack = new Stack<XmlTag>();
            var xml = new List<string> {"<File>"};
            //Create a root node for the file.
            var rootNode = new XmlTag()
            {
                Name = "File"
            };
            stack.Push(rootNode);
            for (var i = 0; i < file.Length; i++)
            {
                var depth = GetDepth(file[i]);
                var tag = CreateTagFromString(file[i], depth);
                var padding = new StringBuilder();
                for (var j = tag.Depth - 1; j > 0; j--)
                {
                    padding.Append(" ");
                }
                if (i == file.Length - 1)
                {
                    var t = stack.Pop();
                    xml.Insert(xml.Count - 1, padding + "<" + t.Name + ">" + t.Value + "</" + t.Name + ">");
                    xml[xml.Count - 1] = padding + "<" + tag.Name + ">" + tag.Value + "</" + tag.Name + ">";
                    //Unwind the stack.
                    xml.AddRange(stack.Select(s => "</" + s.Name + ">"));

                    continue;
                }
                if (depth == lastDepthLevel)
                {
                    if (stack.Count != 0)
                    {
                        var t = stack.Pop();
                        xml[xml.Count - 1] = padding + "<" + t.Name + ">" + t.Value + "</" + t.Name + ">";
                    }
                }
                else if (depth < lastDepthLevel)
                {
                    //Moving up
                    if (stack.Count != 0)
                    {
                        var t = stack.Pop();
                        xml[xml.Count - 1] = padding + "<" + t.Name + ">" + t.Value + "</" + t.Name + ">";
                        var diff = lastDepthLevel - depth;
                        var subPadding = new StringBuilder();
                        for (var j = 0; j < diff; j++)
                        {
                            subPadding.Clear();
                            var subTag = stack.Pop();
                            for (var k = subTag.Depth - 1; k != 0; k--)
                            {
                                subPadding.Append(" ");
                            }
                            if (stack.Count != 0)
                            {
                                xml.Add(subPadding + "</" + subTag.Name + ">");
                            }
                            else
                            {
                                break;
                            }
                        }
                    }
                }
                if(tag.Name != string.Empty) xml.Add(padding + "<" + tag.Name + ">");
                stack.Push(tag);
                lastDepthLevel = depth;
            }
            //File.WriteAllLines(@"C:\Users\glmcc\Desktop\Test.info", xml);
            return xml;
        }

        private static XmlTag CreateTagFromString(string text, int tagDepth)
        {
            var tag = new XmlTag();
            var clearingPadding = true;
            var foundDelimiter = false;
            var insideBraces = false;
            var name = new StringBuilder();
            var value = new StringBuilder();
            //var attributes = new List<MkvAttribute>();

            for (var i = 0; i < text.Length; i++)
            {
                if ((char.IsSymbol(text[i]) || char.IsPunctuation(text[i]) || char.IsWhiteSpace(text[i])) && clearingPadding)
                {
                    continue;
                }

                if ((text[i].ToString() == ":" || text[i] == ',') && !foundDelimiter)
                {
                    foundDelimiter = true;
                    continue;
                }
                
                clearingPadding = false;
                if (foundDelimiter)
                {
                    if (text[i] == '(')
                    {
                        insideBraces = true;
                        continue;
                    }
                    if (insideBraces && text[i] == ')')
                    {
                        insideBraces = false;
                        continue;
                    }

                    if(!insideBraces) value.Append(text[i]);
                }
                else
                {
                    if (text[i] == '(')
                    {
                        insideBraces = true;
                        continue;
                    }
                    if(text[i] == ')')
                    {
                        insideBraces = false;
                        continue;
                    }
                    if(!insideBraces) name.Append(text[i]);
                }
            }
            tag.Name = FormatTagName(name.ToString());
            tag.Value = value.ToString().Trim();
            tag.Depth = tagDepth;

            return tag;
        }

        private static string FormatTagName(string text)
        {
            if (text.Length == 0) return string.Empty;
            var name = new StringBuilder();
            var previousCharWasWhiteSpace = false;

            foreach (var c in text)
            {
                if (!char.IsWhiteSpace(c))
                {
                    name.Append(previousCharWasWhiteSpace ? char.ToUpper(c) : c);
                    previousCharWasWhiteSpace = false;
                }

                if (char.IsWhiteSpace(c))
                {
                    previousCharWasWhiteSpace = true;
                }
            }

            return name.ToString();
        }

        private static int GetDepth(string line)
        {
            if (line.Length == 0) return -1;
            var depth = 0;

            for (var i = 0; i < line.Length; i++)
            {
                if (char.IsPunctuation(line[i]) || char.IsWhiteSpace(line[i]) || char.IsSymbol(line[i]))
                {
                    depth++;
                }
                else
                {
                    break;
                }
            }

            return depth;
        }
    }
}
