public static void CleanUpFolder(string folderPath, Action <Progress> ProgressChanged = null)
        {
            ProgressChanged?.Invoke(Progress.Indetermined("Cleaning up mod folder."));

            foreach (string subFolderPath in Directory.EnumerateDirectories(folderPath))
            {
                string subFolderName = Path.GetFileName(subFolderPath).ToLower();

                // Move data folder one up:
                if (subFolderName == "data")
                {
                    ModInstallations.MoveDirectory(subFolderPath, folderPath);
                }
            }

            foreach (String filePath in Directory.EnumerateFiles(folderPath))
            {
                string fileExtension = Path.GetExtension(filePath).ToLower().Trim();

                // Extract archives within folder:
                if (fileExtension == ".ba2" || Utils.SevenZipSupportedFileTypes.Contains(fileExtension))
                {
                    ModInstallations.ExtractArchive(filePath, folderPath, ProgressChanged);
                    File.Delete(filePath);
                }

                // Delete crap:
                else if (fileExtension == ".txt")
                {
                    File.Delete(filePath);
                }
            }
        }
        /// <summary>
        /// Extracts the archive and adds the mod to the list.
        /// Saves the xml file afterwards.
        /// </summary>
        /// <param name="useSourceBA2Archive">When false, creates a new "frozen" mod.</param>
        public static void InstallArchive(ManagedMods mods, string filePath, bool useSourceBA2Archive = false, Action <Progress> ProgressChanged = null)
        {
            ManagedMod newMod = ModInstallations.FromArchive(mods.GamePath, filePath, useSourceBA2Archive, ProgressChanged);

            mods.Add(newMod);
            mods.Save();
            ProgressChanged?.Invoke(Progress.Done("Mod archive installed."));
        }
        /// <summary>
        /// Copies the folder and adds the mod to the list.
        /// Saves the xml file afterwards.
        /// </summary>
        public static void InstallFolder(ManagedMods mods, string folderPath, Action <Progress> ProgressChanged = null)
        {
            ManagedMod newMod = ModInstallations.FromFolder(mods.GamePath, folderPath, ProgressChanged);

            mods.Add(newMod);
            mods.Save();
            ProgressChanged?.Invoke(Progress.Done("Mod folder installed."));
        }
        /// <summary>
        /// Downloads and installs a mod from NexusMods. (by using NXM links)
        /// </summary>
        /// <param name="useSourceBA2Archive">When false, creates a new "frozen" mod.</param>
        public static bool InstallRemote(ManagedMods mods, string nxmLinkStr, bool useSourceBA2Archive = false, Action <Progress> ProgressChanged = null)
        {
            NXMLink nxmLink = NXMHandler.ParseLink(nxmLinkStr);

            // Get the download link from NexusMods:
            ProgressChanged(Progress.Indetermined("Requesting mod download link..."));
            string dlLinkStr = NMMod.RequestDownloadLink(nxmLink);

            if (dlLinkStr == null)
            {
                ProgressChanged?.Invoke(Progress.Aborted("Couldn't retrieve download link..."));
                return(false);
            }
            Uri    dlLink     = new Uri(dlLinkStr);
            string dlFileName = dlLink.Segments.Last();
            string dlPath     = Path.Combine(Shared.DownloadsFolder, dlFileName);

            // Download mod, unless we already have it:
            if (!File.Exists(dlPath))
            {
                DownloadFile(dlLink.OriginalString, dlPath, ProgressChanged);
            }

            if (!File.Exists(dlPath))
            {
                ProgressChanged?.Invoke(Progress.Aborted("Download failed."));
                return(false);
            }

            // Get remote mod info:
            ProgressChanged(Progress.Indetermined("Requesting mod information and thumbnail..."));
            NMMod nmMod = NexusMods.RequestModInformation(nxmLink.modId);

            // Install mod:
            ProgressChanged(Progress.Indetermined($"Installing '{nmMod.Title}'..."));
            ManagedMod newMod = ModInstallations.FromArchive(mods.GamePath, dlPath, useSourceBA2Archive, ProgressChanged);

            newMod.Title   = nmMod.Title;
            newMod.Version = nmMod.LatestVersion;
            newMod.URL     = nmMod.URL;
            mods.Add(newMod);
            mods.Save();
            ProgressChanged?.Invoke(Progress.Done($"'{nmMod.Title}' installed."));

            return(true);
        }
        /// <summary>
        /// Creates a new mod from any supported archive. (zip, tar, rar, 7z, ba2)
        /// BA2 files can be installed frozen if needed.
        /// </summary>
        /// <param name="gamePath">Path to the game installation</param>
        /// <param name="filePath">Path to archive</param>
        /// <param name="useSourceBA2Archive">When false, creates a new "frozen" mod.</param>
        /// <returns></returns>
        private static ManagedMod FromArchive(string gamePath, string filePath, bool useSourceBA2Archive = false, Action <Progress> ProgressChanged = null)
        {
            // Get path information:
            string longFilePath  = EnsureLongPathSupport(filePath);
            string fileNameWOEx  = Path.GetFileNameWithoutExtension(longFilePath);
            string fileExtension = Path.GetExtension(longFilePath);

            // Install mod:
            ManagedMod newMod = new ManagedMod(gamePath);

            newMod.Title             = fileNameWOEx;
            newMod.ArchiveName       = fileNameWOEx + ".ba2";
            newMod.ManagedFolderName = fileNameWOEx;
            if (!Utils.IsFileNameValid(newMod.ManagedFolderName) || Directory.Exists(newMod.ManagedFolderPath))
            {
                newMod.ManagedFolderName = newMod.DefaultManagedFolderName;
            }

            // Extract mod:
            ProgressChanged?.Invoke(Progress.Indetermined($"Extracting {Path.GetFileName(filePath)}"));
            ModInstallations.ExtractArchive(longFilePath, newMod.ManagedFolderPath);

            // Freeze mod conditionally:
            if (useSourceBA2Archive && fileExtension == ".ba2")
            {
                // Copy *.ba2 into FrozenData:
                FileInfo frozenPath = new FileInfo(newMod.FrozenArchivePath);
                ProgressChanged?.Invoke(Progress.Indetermined($"Copying {Path.GetFileName(filePath)} to {frozenPath.DirectoryName}"));
                Directory.CreateDirectory(frozenPath.DirectoryName);
                File.Copy(longFilePath, frozenPath.FullName, true);

                newMod.Frozen         = true;
                newMod.Freeze         = true;
                newMod.PreviousMethod = ManagedMod.DeploymentMethod.SeparateBA2;
                newMod.Method         = ManagedMod.DeploymentMethod.SeparateBA2;
            }
            else
            {
                ModActions.CleanUpFolder(newMod.ManagedFolderPath, ProgressChanged);
                ModActions.DetectOptimalModInstallationOptions(newMod);
            }

            return(newMod);
        }
        /// <summary>
        /// Extracts the archive and then copy and replaces from the temp folder into the managed mod folder.
        /// </summary>
        public static void AddArchive(ManagedMod mod, string filePath, Action <Progress> ProgressChanged = null)
        {
            string longFilePath   = EnsureLongPathSupport(filePath);
            string tempFolderPath = Path.Combine(Path.GetTempPath(), $"tmp_{mod.guid}");

            if (Directory.Exists(tempFolderPath))
            {
                Directory.Delete(tempFolderPath, true);
            }
            Directory.CreateDirectory(tempFolderPath);

            ProgressChanged?.Invoke(Progress.Indetermined($"Extracting {Path.GetFileName(filePath)}"));
            ModInstallations.ExtractArchive(longFilePath, tempFolderPath);
            ModActions.CleanUpFolder(tempFolderPath, ProgressChanged);
            CopyDirectory(tempFolderPath, mod.ManagedFolderPath, ProgressChanged);

            Directory.Delete(tempFolderPath, true);

            ProgressChanged?.Invoke(Progress.Done("Archive added to mod."));
        }
        /// <summary>
        /// Looks through the resource lists in the *.ini and imports *.ba2 archives.
        /// </summary>
        public static void ImportInstalledMods(ManagedMods mods, Action <Progress> ProgressChanged = null)
        {
            // TODO: ProgressChanged for ImportInstalledMods
            ProgressChanged?.Invoke(Progress.Indetermined("Importing already installed mods..."));

            // Get all archives:
            ResourceList IndexFileList = ResourceList.GetResourceIndexFileList();
            ResourceList Archive2List  = ResourceList.GetResourceArchive2List();

            /*
             * Prepare list:
             */

            // Add all archives:
            List <string> installedMods = new List <string>();

            installedMods.AddRange(IndexFileList);
            installedMods.AddRange(Archive2List);
            installedMods.AddRange(mods.Resources);

            // Remove bundled archives:
            installedMods = installedMods.FindAll(e => !e.ToLower().Contains("bundled"));

            // Remove currently managed archives:
            foreach (ManagedMod mod in mods)
            {
                if (mod.PreviousMethod == ManagedMod.DeploymentMethod.SeparateBA2)
                {
                    installedMods.Remove(mod.CurrentArchiveName);
                }
            }

            // Ignore any game files ("SeventySix - *.ba2"):
            foreach (string archiveName in IndexFileList)
            {
                if (archiveName.Trim().ToLower().StartsWith("seventysix"))
                {
                    installedMods.Remove(archiveName);
                }
            }
            foreach (string archiveName in Archive2List)
            {
                if (archiveName.Trim().ToLower().StartsWith("seventysix"))
                {
                    installedMods.Remove(archiveName);
                }
            }
            foreach (string archiveName in mods.Resources)
            {
                if (archiveName.Trim().ToLower().StartsWith("seventysix"))
                {
                    installedMods.Remove(archiveName);
                }
            }

            /*
             * Import installed mods:
             */

            foreach (string archiveName in installedMods)
            {
                string path = Path.Combine(mods.GamePath, "Data", archiveName);
                if (File.Exists(path) && !archiveName.Trim().ToLower().StartsWith("seventysix"))
                {
                    // Import archive:
                    ModInstallations.InstallArchive(mods, path, true);
                    File.Delete(path);

                    // Remove from lists:
                    IndexFileList.Remove(archiveName);
                    Archive2List.Remove(archiveName);
                }
            }

            // Save *.ini files:
            IndexFileList.CommitToINI();
            Archive2List.CommitToINI();
            //IniFiles.Instance.SaveAll();

            mods.Save();
        }