public static bool ValidateVersion(string vStr)
        {
            bool valid = true;

            try {
                LoadVersionInfo();
            } catch (Exception e) {
                ConsoleUtils.ErrorLn(e.Message);
                ConsoleUtils.WarnLn("Compilation aborted.");
                valid = false;
            }
            if (valid)
            {
                Match m = _versionRegex.Match(vStr);
                valid = m.Success;
                if (valid)
                {
                    int main = Convert.ToInt32(m.Groups[1].Value);
                    valid = _versions.ContainsKey(main);
                    if (valid)
                    {
                        Dictionary <int, Dictionary <int, int> > sub = _versions[main];
                        int major = Convert.ToInt32(m.Groups[2].Value);
                        valid = sub.ContainsKey(major);
                        if (valid)
                        {
                            if (m.Groups.Count == 4)
                            {
                                Dictionary <int, int> sub2 = sub[major];
                                int minor = Convert.ToInt32(m.Groups[3].Value);
                                valid = sub2.ContainsKey(minor);
                                if (!valid)
                                {
                                    ConsoleUtils.ErrorLn("v" + vStr + " no such minor version exists - compilation aborted.");
                                }
                            }
                        }
                        else
                        {
                            ConsoleUtils.ErrorLn("v" + vStr + " no such major version exists - compilation aborted.");
                        }
                    }
                    else
                    {
                        ConsoleUtils.ErrorLn("v" + vStr + " no such main version exists - compilation aborted.");
                    }
                }
                else
                {
                    ConsoleUtils.ErrorLn("v" + vStr + " is not a valid version string - compilation aborted.");
                }
            }
            return(valid);
        }
        public static bool Load(string id, bool isName, OrderedDictionary <string, Mod> mods)
        {
            bool keepOpen = true;

            try {
                string modFile = id + Mod.DefinitionExtension;
                bool   valid   = true;
                if (isName)
                {
                    Console.WriteLine("Searching for mod...");
                    id = id.ToLower();
                    var candidates = new Dictionary <string, (string File, int Index)>();
                    foreach (string file in Directory.GetFiles(Mod.DefinitionFolder))
                    {
                        string f2 = Mod.ResolvePath(file);
                        if (new FileInfo(f2).Extension == Mod.DefinitionExtension)
                        {
                            string name = Mod.FindName(f2);
                            if (name != null)
                            {
                                int index = name.ToLower().IndexOf(id);
                                if (index > -1)
                                {
                                    candidates.Add(name, (File: f2, Index: index));
                                }
                            }
                        }
                    }
                    if (candidates.Count > 1)
                    {
                        Console.WriteLine("Found " + candidates.Count + " candidate mods.");
                        Console.WriteLine("");
                        var names = new List <KeyValuePair <string, (string File, int Index)> >(candidates);
                        names.Sort((a, b) => a.Value.Index - b.Value.Index);
                        int i = 1;
                        foreach (KeyValuePair <string, (string, int)> name in names)
                        {
                            Console.WriteLine(i + ". " + name.Key);
                            i++;
                        }
                        Console.WriteLine("");
                        Console.Write("Input number corresponding to the mod you wish to load, or type \"exit\" to abort this load: ");
                        bool reading      = true;
                        int  n            = -1;
                        var  ordinalRegex = new Regex(@"^\d+$");
                        do
                        {
                            string line = Console.ReadLine();
                            if (line != null)
                            {
                                line = line.Trim();
                                if (line == "exit")
                                {
                                    Console.WriteLine("");
                                    Console.WriteLine("Aborting load.");
                                    reading = false;
                                    valid   = false;
                                }
                                else
                                {
                                    Match m = ordinalRegex.Match(line);
                                    if (m.Success)
                                    {
                                        n = Convert.ToInt32(line);
                                        if (n >= 1 && n <= names.Count)
                                        {
                                            reading = false;
                                        }
                                        else
                                        {
                                            ConsoleUtils.Warn("Invalid argument. Please specify a number in the range [1, " + names.Count + "] or \"exit\": ");
                                        }
                                    }
                                    else
                                    {
                                        ConsoleUtils.Warn("Invalid argument. Please specify a number or \"exit\": ");
                                    }
                                }
                            }
                            else
                            {
                                // Ctrl-C
                                reading  = false;
                                valid    = false;
                                keepOpen = false;
                            }
                        } while (reading);
                        if (valid && n > 0)
                        {
                            n--;
                            Console.WriteLine("");
                            Console.WriteLine("Selected mod \"" + names[n].Key + "\".");
                            modFile = candidates[names[n].Key].File;
                        }
                    }
                    else if (candidates.Count == 1)
                    {
                        Console.Write("Are you searching for \"" + candidates.First().Key + "\"? (y/n): ");
                        bool reading = true;
                        bool found   = false;
                        do
                        {
                            string line = Console.ReadLine();
                            if (line != null)
                            {
                                line = line.Trim().ToLower();
                                switch (line)
                                {
                                case "y":
                                case "yes":
                                    reading = false;
                                    found   = true;
                                    break;

                                case "n":
                                case "no":
                                    reading = false;
                                    break;

                                default:
                                    ConsoleUtils.Warn("Invalid argument. Please specify y/n: ");
                                    break;
                                }
                            }
                            else
                            {
                                // Ctrl-C
                                reading  = false;
                                valid    = false;
                                keepOpen = false;
                            }
                        } while (reading);
                        Console.WriteLine("");
                        if (found)
                        {
                            Console.WriteLine("Found mod.");
                            modFile = candidates.First().Value.File;
                        }
                        else
                        {
                            ConsoleUtils.WarnLn("Incorrect mod and no alternatives available; aborting load.");
                            valid = false;
                        }
                    }
                    else
                    {
                        ConsoleUtils.ErrorLn("Found zero candidate mods.");
                        valid = false;
                    }
                    if (valid)
                    {
                        modFile = Mod.ResolvePath(modFile);
                    }
                }
                else
                {
                    if (!modFile.EndsWith(Mod.DefinitionExtension))
                    {
                        modFile += Mod.DefinitionExtension;
                    }
                    modFile = Mod.ResolvePath(modFile);
                    Console.WriteLine("Attempting load of mod \"" + modFile + "\"...");
                }
                if (valid)
                {
                    if (mods.ContainsKey(modFile))
                    {
                        ConsoleUtils.WarnLn("Redundant load: That mod has already been loaded.");
                    }
                    else
                    {
                        mods.Add(modFile, new Mod(modFile));
                        Console.WriteLine("Mod loaded.");
                    }
                }
            } catch (Exception e) {
                ConsoleUtils.ErrorLn(e.Message);
                ConsoleUtils.ErrorLn("Mod has not been loaded.");
            }
            return(keepOpen);
        }
        public static bool Compile(OrderedDictionary <string, Mod> mods, string targetVersion, bool clear)
        {
            bool keepOpen = true;

            if (mods.Count > 0)
            {
                bool valid = true;
                try {
                    LoadVersionInfo();
                } catch (Exception e) {
                    ConsoleUtils.ErrorLn(e.Message);
                    ConsoleUtils.WarnLn("Compilation aborted.");
                    valid = false;
                }
                if (valid)
                {
                    int i = 0;
                    List <OrderedMod> mods2 = mods.Select(x => new OrderedMod(x.Value, i++)).ToList();
                    mods2.Sort((a, b) => {
                        int res = VersionCompare(a.Mod.Version, b.Mod.Version);
                        return(res != 0 ? res : a.Position.CompareTo(b.Position));
                    });
                    int[]      vTarget        = Mod.GetConcreteVersion(targetVersion);
                    int[]      currentVersion = mods2[0].Mod.Version;
                    Repository repo           = GitSetUp(mods2[0].Mod);
                    foreach (OrderedMod mod in mods2)
                    {
                        if (VersionCompare(mod.Mod.Version, vTarget) > 0)
                        {
                            ConsoleUtils.WarnLn("Mod \"" + mod.Mod.Name + "\" is targeting a newer version of Stellaris then compilation is targeting.");
                            ConsoleUtils.WarnLn("(Mod needs " + mod.Mod.VersionString + " but compilation is targeting " + targetVersion + ").");
                            ConsoleUtils.WarnLn("Skipping mod...");
                        }
                        else
                        {
                            int cmp = VersionCompare(mod.Mod.Version, currentVersion);
                            if (cmp > 0)
                            {
                                ChangeCoreVersion(currentVersion, mod.Mod);
                                currentVersion = mod.Mod.Version;
                            }
                            ApplyMod(mod.Mod);
                        }
                    }
                    string outDir = TearDownGit(repo);



//					int[] version = GetConcreteVersion(targetVersion);
                    //string vStr = GetVersionString(version);
                    //Console.WriteLine("Compiling against Stellaris " + vStr + "...");
                    //string gameFiles = GetGameFiles(version, "$CORE " + vStr, out valid);
                    if (valid)
                    {
                        /*
                         * var usedLines = new Dictionary<string, Dictionary<int, Mod>>();
                         * foreach (KeyValuePair<string, Mod> kvp in mods) {
                         *      Mod mod = kvp.Value;
                         *      //int[] modV = GetConcreteVersion(mod.Version);
                         *      //string modVStr = GetVersionString(modV);
                         *      bool compileThis = true;
                         *      if (vStr == modVStr) {
                         *              List<string> conflicts = GetConflicts(gameFiles, mod);
                         *              ConsoleUtils.WarnLn("Compilation is targeting " + vStr + " but mod \"" + mod.Name + "\" is targeting " + modVStr + ".");
                         *              if (conflicts.Count > 0) {
                         *                      ConsoleUtils.WarnLn("Vanilla files have been overridden - compiling this mod may lead to an unstable end product.");
                         *                      ConsoleUtils.WarnLn("List of overridden files:");
                         *                      foreach (string file in conflicts) {
                         *                              ConsoleUtils.WarnLn("  " + file);
                         *                      }
                         *              } else {
                         *                      ConsoleUtils.WarnLn("No vanilla files have been overriden, but features used by the mod may have changed between versions.");
                         *              }
                         *              ConsoleUtils.Warn("Do you want to compile this mod? (y/n): ");
                         *              bool reading = true;
                         *              do {
                         *                      string line = Console.ReadLine();
                         *                      if (line != null) {
                         *                              line = line.Trim().ToLower();
                         *                              switch (line) {
                         *                                      case "y":
                         *                                      case "yes":
                         *                                              compileThis = true;
                         *                                              reading = false;
                         *                                              break;
                         *                                      case "n":
                         *                                      case "no":
                         *                                              compileThis = false;
                         *                                              reading = false;
                         *                                              break;
                         *                                      default:
                         *                                              ConsoleUtils.Warn("Invalid argument. Please specify y/n: ");
                         *                                              break;
                         *                              }
                         *                      } else {
                         *                              reading = false;
                         *                              valid = false;
                         *                              keepOpen = false;
                         *                      }
                         *              } while (reading);
                         *              Console.WriteLine();
                         *      }
                         *      if (valid) {
                         *              if (compileThis) {
                         *                      Console.WriteLine("Compiling \"" + ResolveName(mod.Name) + "\"...");
                         *                      ModDiffer.ApplyDiff(gameFiles, mod, usedLines);
                         *              } else {
                         *                      Console.WriteLine("Skipping mod...");
                         *              }
                         *      }
                         * }
                         * if (valid) {
                         *      if (clear) {
                         *              mods.Clear();
                         *      }
                         * }
                         */
                    }
                }
            }
            else
            {
                ConsoleUtils.ErrorLn("No mods have been loaded - compilation aborted.");
            }
            return(keepOpen);
        }
        public static void Main(string[] args)
        {
            var mods = new OrderedDictionary <string, Mod>();

            SetConsoleCtrlHandler(eventType => {
                ClearTemp();
                return(false);
            }, true);

            if (Directory.Exists(Globals.TempFolder))
            {
                ClearTemp();
            }
            else
            {
                Directory.CreateDirectory(Globals.TempFolder);
            }

            bool keepOpen = true;

            do
            {
                Console.Write("StellarisModMerge> ");
                string cmdStr = Console.ReadLine();
                if (cmdStr != null)
                {
                    try {
                        var cmd = new ShellLikeCommand(cmdStr);
                        if (cmd.Args.Count > 0)
                        {
                            Console.WriteLine("");
                            ShellLikeCommand.Arg arg0 = cmd.Args[0];
                            bool valid;
                            switch (arg0.Text)
                            {
                            case "load":
                                if (cmd.Args.Count > 3)
                                {
                                    ConsoleUtils.ErrorLn("Command \"load\" doesn't take more than 2 arguments.");
                                }
                                else if (cmd.Args.Count == 1)
                                {
                                    ConsoleUtils.ErrorLn("Command\"load\" no mod ID or search string specified.");
                                }
                                else
                                {
                                    string id                 = null;
                                    bool   isName             = false;
                                    ShellLikeCommand.Arg arg1 = cmd.Args[1];
                                    bool req3Args             = false;
                                    valid = true;
                                    if (arg1.Type == ShellLikeCommand.ArgType.Switch)
                                    {
                                        if (arg1.Text == "s")
                                        {
                                            isName   = true;
                                            req3Args = true;
                                        }
                                        else
                                        {
                                            ConsoleUtils.ErrorLn("Command \"load\" unknown switch " + arg1 + ".");
                                            valid = false;
                                        }
                                    }
                                    else
                                    {
                                        id = arg1.Text;
                                    }
                                    if (valid)
                                    {
                                        if (cmd.Args.Count == 3)
                                        {
                                            ShellLikeCommand.Arg arg2 = cmd.Args[2];
                                            if (arg2.Type == ShellLikeCommand.ArgType.Text)
                                            {
                                                if (id != null)
                                                {
                                                    ConsoleUtils.ErrorLn("Command \"load\" unknown 2nd argument: " + arg2 + ".");
                                                    valid = false;
                                                }
                                                else
                                                {
                                                    id = arg2.Text;
                                                }
                                            }
                                            else if (id == null)
                                            {
                                                ConsoleUtils.ErrorLn("Command \"load\" no mod ID or search string specified.");
                                                valid = false;
                                            }
                                            else if (arg2.Text == "s")
                                            {
                                                isName = true;
                                            }
                                            else
                                            {
                                                ConsoleUtils.ErrorLn("Command \"load\" unknown switch " + arg2 + ".");
                                                valid = false;
                                            }
                                        }
                                        else if (req3Args)
                                        {
                                            ConsoleUtils.ErrorLn("Command \"load\" no mod ID or search string specified.");
                                            valid = false;
                                        }
                                    }
                                    if (valid)
                                    {
                                        keepOpen = ModLoader.Load(id, isName, mods);
                                    }
                                }
                                break;

                            case "compile":
                                // TODO: Allow version specifier
                                if (cmd.Args.Count > 3)
                                {
                                    ConsoleUtils.ErrorLn("Command \"compile\" doesn't take more than 2 arguments.");
                                }
                                else
                                {
                                    valid = true;
                                    string version = "";
                                    try {
                                        version = ModCompiler.LatestVersion;
                                    } catch (Exception e) {
                                        ConsoleUtils.ErrorLn(e.Message);
                                        ConsoleUtils.WarnLn("Compilation aborted.");
                                        valid = false;
                                    }
                                    if (valid)
                                    {
                                        bool clear         = false;
                                        bool expectVersion = false;
                                        for (int i = 1; valid && i < cmd.Args.Count; i++)
                                        {
                                            ShellLikeCommand.Arg arg = cmd.Args[i];
                                            if (expectVersion)
                                            {
                                                if (arg.Type == ShellLikeCommand.ArgType.Text)
                                                {
                                                    version = arg.Text.ToLower();
                                                    if (version.StartsWith("v"))
                                                    {
                                                        version = version.Substring(1);
                                                    }
                                                    expectVersion = false;
                                                }
                                                else
                                                {
                                                    valid = false;
                                                }
                                            }
                                            else if (arg.Type == ShellLikeCommand.ArgType.Switch)
                                            {
                                                if (arg.Text == "c")
                                                {
                                                    clear = true;
                                                }
                                                else if (arg.Text == "v")
                                                {
                                                    expectVersion = true;
                                                }
                                            }
                                            else
                                            {
                                                ConsoleUtils.ErrorLn("Command \"compile\" unexpected text argument: " + arg + ".");
                                                valid = false;
                                            }
                                        }
                                        if (expectVersion)
                                        {
                                            ConsoleUtils.ErrorLn("Version not specified after -v switch - compilation aborted.");
                                            valid = false;
                                        }
                                        if (valid)
                                        {
                                            if (ModCompiler.ValidateVersion(version))
                                            {
                                                keepOpen = ModCompiler.Compile(mods, version, clear);
                                            }
                                        }
                                    }
                                }
                                break;

                            case "clear":
                                if (cmd.Args.Count > 1)
                                {
                                    ConsoleUtils.ErrorLn("Command \"clear\" doesn't take any arguments.");
                                }
                                else
                                {
                                    mods.Clear();
                                    Console.WriteLine("Unloaded all mods.");
                                }
                                break;

                            case "list":
                                valid = true;
                                bool showFileName      = false;
                                bool showTargetVersion = false;
                                for (int i = 1; valid && i < cmd.Args.Count; i++)
                                {
                                    ShellLikeCommand.Arg arg = cmd.Args[i];
                                    if (arg.Type == ShellLikeCommand.ArgType.Text)
                                    {
                                        ConsoleUtils.ErrorLn("Command \"list\" doesn't take any text arguments.");
                                        valid = false;
                                    }
                                    else
                                    {
                                        switch (arg.Text)
                                        {
                                        case "f":
                                            if (showFileName)
                                            {
                                                ConsoleUtils.ErrorLn("Command \"list\" duplicate switch " + arg + ".");
                                                valid = false;
                                            }
                                            else
                                            {
                                                showFileName = true;
                                            }
                                            break;

                                        case "v":
                                            if (showTargetVersion)
                                            {
                                                ConsoleUtils.ErrorLn("Command \"list\" duplicate switch " + arg + ".");
                                                valid = false;
                                            }
                                            else
                                            {
                                                showTargetVersion = true;
                                            }
                                            break;

                                        default:
                                            ConsoleUtils.ErrorLn("Command \"list\" unknown switch " + arg + ".");
                                            valid = false;
                                            break;
                                        }
                                    }
                                }
                                if (valid)
                                {
                                    if (mods.Count > 0)
                                    {
                                        var ids      = new string[mods.Count];
                                        var names    = new string[mods.Count];
                                        var versions = new string[mods.Count];
                                        int i        = 0;
                                        foreach (KeyValuePair <string, Mod> kvp in mods)
                                        {
                                            ids[i]      = new FileInfo(kvp.Value.ModFile).Name;
                                            names[i]    = kvp.Value.Name ?? "$NONAME";
                                            versions[i] = kvp.Value.VersionString;
                                            i++;
                                        }
                                        const string idHead        = "MOD FILE";
                                        const string nameHead      = "MOD NAME";
                                        const string versionHead   = "GAME VERSION";
                                        int          idLength      = Math.Max(idHead.Length, ids.Max(id => id.Length));
                                        int          nameLength    = Math.Max(nameHead.Length, names.Max(name => name.Length));
                                        int          versionLength = Math.Max(versionHead.Length, versions.Max(version => version.Length));
                                        int          sumLength     = nameLength;
                                        if (showFileName)
                                        {
                                            Console.Write(PadStr(idHead, idLength) + " | ");
                                            sumLength += idLength + 3;
                                        }
                                        Console.Write(PadStr(nameHead, nameLength));
                                        if (showTargetVersion)
                                        {
                                            Console.Write(" | " + PadStr(versionHead, versionLength));
                                            sumLength += versionLength + 3;
                                        }
                                        Console.WriteLine();
                                        for (i = 0; i < sumLength; i++)
                                        {
                                            Console.Write('-');
                                        }
                                        Console.WriteLine();
                                        for (i = 0; i < ids.Length; i++)
                                        {
                                            if (showFileName)
                                            {
                                                Console.Write(PadStr(ids[i], idLength) + " | ");
                                            }
                                            Console.Write(PadStr(names[i], nameLength));
                                            if (showTargetVersion)
                                            {
                                                Console.Write(" | " + PadStr(versions[i], versionLength));
                                            }
                                            Console.WriteLine();
                                        }
                                    }
                                    else
                                    {
                                        Console.WriteLine("No mods have been loaded.");
                                    }
                                }
                                break;

                            case "exit":
                                if (cmd.Args.Count > 1)
                                {
                                    ConsoleUtils.ErrorLn("Command \"exit\" doesn't take any arguments.");
                                }
                                else
                                {
                                    keepOpen = false;
                                }
                                break;

                            case "help":
                                if (cmd.Args.Count > 1)
                                {
                                    ConsoleUtils.ErrorLn("Command \"help\" doesn't take any arguments.");
                                }
                                else
                                {
                                    Console.WriteLine("## LIST OF COMMANDS ##");
                                    Console.WriteLine("");
                                    Console.WriteLine("load => Load a mod into the system. The order this command is called in defines load order - later mods will override older mods.");
                                    Console.WriteLine("  -s: Specifies that arg1 is a mod name search string.");
                                    Console.WriteLine("  arg1: The mod to load (file name if -s is not present, search string if it is).");
                                    Console.WriteLine("");
                                    Console.WriteLine("compile => Compiles all loaded mods into one super-mod.");
                                    Console.WriteLine("  -c: Clears all loaded mods when compilation is done.");
                                    Console.WriteLine("");
                                    Console.WriteLine("exit => Exits the program.");
                                    Console.WriteLine("");
                                    Console.WriteLine("clear => Clears all loaded mods.");
                                    Console.WriteLine("");
                                    Console.WriteLine("help => This command.");
                                }
                                break;

                            default:
                                ConsoleUtils.WarnLn("Unknown command \"" + arg0.Text + "\". Type \"help\" for a list of commands.");
                                break;
                            }
                            Console.WriteLine("");
                        }
                    } catch (ArgumentException e) {
                        Console.WriteLine("");
                        ConsoleUtils.ErrorLn("Invalid command: " + e.Message);
                        Console.WriteLine("");
                    }
                }
                else
                {
                    // Ctrl-C
                    keepOpen = false;
                }
            } while (keepOpen);
            ClearTemp();
        }