﻿using System;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;

namespace Krang.YEncoding
{
    public sealed class YDecoder
    {
        public YPart Decode(string data)
        {
            var beginIndex = data.IndexOf("=ybegin ", StringComparison.InvariantCulture);
            var beginLength = data.IndexOf("\r\n", beginIndex, StringComparison.InvariantCulture) - beginIndex + 2;
            var begin = data.Substring(beginIndex, beginLength);

            var partIndex = data.IndexOf("=ypart ", StringComparison.InvariantCulture);
            var partLength = data.IndexOf("\r\n", partIndex, StringComparison.InvariantCulture) - partIndex + 2;
            var part = data.Substring(partIndex, partLength);

            var endIndex = data.IndexOf("=yend ", StringComparison.InvariantCulture);
            var endLength = data.Length - endIndex;
            var end = data.Substring(endIndex, endLength);

            var partData = data.Substring(partIndex + partLength, data.Length - partLength - beginLength - endLength);
            var buffer = Encoding.Default.GetBytes(partData);

            using (var output = new MemoryStream())
            {
                var escape = false;

                foreach (byte b in buffer)
                {
                    byte c = b;

                    if (escape)
                    {
                        c = (byte) (c - 106);
                        escape = false;
                    }
                    else if (c == 0x3d)
                    {
                        escape = true;
                        continue;
                    }
                    else if (c == 0x0a || c == 0x0d)
                    {
                        continue;
                    }
                    else
                    {
                        c = (byte) (c - 42);
                    }

                    output.WriteByte(c);
                }

                var offset = GetBegin(part) - 1;
                var length = GetEnd(part) - offset - 1;

                return new YPart(output.ToArray())
                {
                    Offset = offset,
                    Length = length,
                    Name = GetName(begin),
                    Size = GetSize(begin)
                };
            }
        }

        private static int GetBegin(string line)
        {
            return int.Parse(Regex.Match(line, "begin=([\\d]+)").Groups[1].Value);
        }

        private static int GetEnd(string line)
        {
            return int.Parse(Regex.Match(line, "end=([\\d]+)").Groups[1].Value);
        }

        private static string GetName(string line)
        {
            return Regex.Match(line, "name=(.*)^").Groups[1].Value;
        }

        private static int GetSize(string line)
        {
            return int.Parse(Regex.Match(line, "size=([\\d]+)").Groups[1].Value);
        }
    }
}
