using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Text;
using Microsoft.Win32;

namespace Dota2ConsoleFont
{
    public class SourceConfigChanger
    {
        private const string SteamRegPath = @"HKEY_CURRENT_USER\SOFTWARE\Valve\Steam";
        private const string SteamInstallPathRegValueName = @"SteamPath";
        private const string SteamConfigPath = @"\config\config.vdf";
        private const string SteamConfigInstalPathParamName = @"InstallDir";
        private const string Dota2AppNumber = "\"570\"";
        private const string Dota2FontConfigPath = @"\dota\pak01_dir.vpk";
        private const string Dota2ConfigConsoleTextParamName = "\"ConsoleText\"";
        private const string Dota2ConfigFontNameParamName = "\"name\"";
        private const string Dota2ConfigFontNameParamValue = "\"Lucida Console\"";
        private const string Dota2ConfigFontTallParamName = "\"tall\"";
        

        public string GetSteamInstallPath()
        {
            try
            {
                return (string)Registry.GetValue(SteamRegPath,
                                                  SteamInstallPathRegValueName, null);
            }
            catch (Exception e)
            {
                return null;
            }
        }

        public string GetDota2InstallPath()
        {
            var sip = GetSteamInstallPath() ?? Environment.CurrentDirectory;

            try
            {
                string d2ip = null;
                using (var config = File.OpenText(sip + SteamConfigPath))
                {
                    while (!config.EndOfStream)
                    {
                        var str = config.ReadLine();

                        if (str != null && !str.Trim().Equals(Dota2AppNumber))
                            continue;
                        StringBuilder paramScope = new StringBuilder();
                        while (true)
                        {
                            var innerStr = config.ReadLine();
                            if (innerStr == null)
                                break;
                            paramScope.AppendLine(innerStr);
                            if (innerStr.Trim() == "}")
                                break;
                        }
                        d2ip = GetParamValue(paramScope.ToString(),
                                             SteamConfigInstalPathParamName);
                        if (d2ip != null)
                            d2ip = d2ip.Substring(1, d2ip.Length - 2);
                        break;
                    }
                }
                return d2ip;
            }
            catch (Exception e)
            {
                return null;
            }
        }

        private string GetParamValue(string paramScope, string paramName)
        {
            try
            {
                var pars = paramScope.Split('\n');
                foreach (var par in pars)
                {
                    if (par.IndexOf(paramName,
                        StringComparison.InvariantCultureIgnoreCase) != -1)
                    {
                        var parts = par.Trim().Split('\t');
                        return parts[parts.Length - 1];
                    }

                }
                return null;
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                return null;
            }
        }
        
        public bool ChangeDota2ConsoleFontSize(int newSize)
        {
            string d2ip = GetDota2InstallPath();
            if (d2ip == null)
            {
                return false;
            }
            string configPath = d2ip + Dota2FontConfigPath;
            
            try
            {
                var configText = File.ReadAllText(configPath, Encoding.Default);

                // ищем все разделы с Console Text
                List<int> consoleTextPositions = new List<int>();
                int startPos = 0;
                while (true)
                {
                    var foundIndex = configText.IndexOf(Dota2ConfigConsoleTextParamName,
                                                        startPos, StringComparison.OrdinalIgnoreCase);
                    if (foundIndex == -1)
                        break;
                    consoleTextPositions.Add(foundIndex);
                    startPos = foundIndex + 1;
                }

                // переворачиваем, чтобы изменение размера числа не сломало файл
                consoleTextPositions.Reverse();
                // ищем те console text, где Lucida console и заменяем высоту
                foreach (var pos in consoleTextPositions)
                {
                    var foundEndScope = configText.IndexOf('}', pos);
                    var newLinePos = pos;
                    while (true)
                    {
                        var endlineIndex = configText.IndexOf('\n', newLinePos);
                        if (endlineIndex > foundEndScope)
                            break;
                        var str = configText.Substring(newLinePos, endlineIndex - newLinePos);
                        var foundParam = GetParamValue(str, Dota2ConfigFontNameParamName);
                        if (foundParam == null)
                        {
                            newLinePos = endlineIndex + 1;
                            continue;
                        }
                        if (foundParam == Dota2ConfigFontNameParamValue)
                        {
                            // ищем строку с высотой и заменяем значение
                            int endlineTallIndex = 0;
                            string tallStr = "";
                            while (endlineTallIndex < foundEndScope)
                            {
                                endlineTallIndex = configText.IndexOf('\n', endlineIndex + 1);
                                tallStr = configText.Substring(endlineIndex + 1,
                                                                   endlineTallIndex - endlineIndex);

                                if (!tallStr.Contains(Dota2ConfigFontTallParamName))
                                {
                                    endlineIndex = endlineTallIndex;
                                }
                                else
                                {
                                    break;
                                }

                            }
                            var newTallStr = ReplaceParamValue(tallStr,
                                newSize.ToString(CultureInfo.InvariantCulture));

                            // подменяем текст конфига
                            var newConfigTextBuilder = new StringBuilder(configText.Length);
                            newConfigTextBuilder.Append(configText.Substring(0, endlineIndex + 1));
                            newConfigTextBuilder.Append(newTallStr);
                            newConfigTextBuilder.Append(configText.Substring(endlineTallIndex + 1));
                            configText = newConfigTextBuilder.ToString();
                        }
                        break;
                    }
                }

                File.WriteAllText(configPath, configText, Encoding.Default);
                return true;
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                return false;
            }
        }

        private string ReplaceParamValue(string paramLine, string newValue)
        {
            StringBuilder newTallstr = new StringBuilder();
            int quotesCount = 0;
            int curPos;
            for (curPos = 0; curPos < paramLine.Length; curPos++)
            {
                newTallstr.Append(paramLine[curPos]);
                if (paramLine[curPos] == '\"')
                {
                    quotesCount++;
                }
                if (quotesCount == 3)
                    break;
            }
            newTallstr.Append(newValue);

            int lastQuotePos = paramLine.IndexOf('\"', curPos + 1);
            newTallstr.Append(paramLine.Substring(lastQuotePos,
                paramLine.Length - lastQuotePos));
            return newTallstr.ToString();
        }
    }
}
