using System.Collections.Generic;
using System.IO;
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 paddingOffSet = GetDepth(file[0]);
            var xml = new StringBuilder();
            var stack = new Stack<XmlTag>();
            var test = new List<string>();
            for (var i = 0; i < file.Length; i++)
            {
                var depth = GetDepth(file[i]);
                var tag = CreateTagFromString(file[i]);
                var padding = new StringBuilder();
                for (var j = depth - paddingOffSet; j > 0; j--)
                {
                    padding.Append(" ");
                }
                if (i == file.Length - 1)
                {
                    test[test.Count - 1] = padding + "<" + tag.Name + ">" + tag.Value + "</" + tag.Name + ">";
                    continue;
                }
                //xml.Append(padding + "<" + tag.Name + ">" + tag.Value == string.Empty ? Environment.NewLine : string.Empty);
                //test.Add(padding + "<" + tag.Name + ">");
                //if (stack.Count != 0)
                //{
                //    var t = stack.Pop();
                //    //xml.Append(t.Value + "</" + t.Name + ">");
                //    test.Add(t.Value + "</" + t.Name + ">");
                //}
                if (depth == lastDepthLevel)
                {
                    if (stack.Count != 0)
                    {
                        var t = stack.Pop();
                        test[test.Count - 1] = padding + test[test.Count - 1] + t.Value + "</" + t.Name + ">";
                    }
                }
                else if (depth < lastDepthLevel)
                {
                    //Moving up
                    if (stack.Count != 0)
                    {
                        var t = stack.Pop();
                        test[test.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();
                            for (var k = padding.Length - j; k != 0; k--)
                            {
                                subPadding.Append(" ");
                            }
                            if (stack.Count != 0)
                            {
                                test.Add(subPadding + "</" + stack.Pop().Name + ">");
                            }
                            else
                            {
                                break;
                            }
                        }
                    }
                }
                if(tag.Name != string.Empty) test.Add(padding + "<" + tag.Name + ">");
                stack.Push(tag);
                lastDepthLevel = depth;
            }

            return test;
        }

        private static XmlTag CreateTagFromString(string text, XmlTag parent = null)
        {
            var tag = new XmlTag();
            var clearingPadding = true;
            var foundDelimiter = false;
            var insideBraces = false;
            var name = new StringBuilder();
            var value = new StringBuilder();

            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() == ":" && !foundDelimiter)
                {
                    foundDelimiter = true;
                    continue;
                }
                
                clearingPadding = false;
                if (foundDelimiter)
                {
                    if (insideBraces && text[i] == ')')
                    {
                        insideBraces = false;
                        continue;
                    }
                    value.Append(text[i]);
                }
                else
                {
                    if (text[i] == '(')
                    {
                        insideBraces = true;
                        continue;
                    }
                    if(text[i] == ')')
                    {
                        insideBraces = false;
                        continue;
                    }
                    if(!insideBraces) name.Append(text[i]);
                }
            }
            if (text.Contains("Segment, "))
            {
                name.Clear();
            }
            tag.Name = FormatTagName(name.ToString());
            tag.Value = value.ToString().Trim();
            tag.Parent = parent;

            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;
        }
    }
}
