/// <summary>
        /// Uninstalls and removes the mods from the ModSelection.
        /// </summary>
        /// <param name="modsToRemove">The mods to remove.</param>
        protected static void RemoveModsAsync(ModNode[] modsToRemove, bool silent = false)
        {
            EventDistributor.InvokeAsyncTaskStarted(Instance);
            View.SetEnabledOfAllControls(false);
            View.SetProgressBarStates(true, modsToRemove.Length, 0);

            int doneCount = 0;
            AsyncTask<bool> asyncJob = new AsyncTask<bool>();
            asyncJob.SetCallbackFunctions(
                () =>
                {
                    foreach (ModNode mod in modsToRemove)
                    {
                        if (!silent)
                        {
                            Messenger.AddInfo(Constants.SEPARATOR);
                            Messenger.AddInfo(string.Format(Messages.MSG_REMOVING_MOD_0, mod.Name));
                            Messenger.AddInfo(Constants.SEPARATOR);
                        }

                        ModNode modToRemove = mod.ZipRoot;

                        try
                        {
                            // prepare to uninstall all mods
                            modToRemove.UncheckAll();

                            // uninstall all mods
                            ProcessMods(new ModNode[] { modToRemove }, silent);
                            ModRegister.RemoveRegisteredMod(modToRemove);

                            View.InvokeIfRequired(() => { Model.RemoveMod(modToRemove); });
                        }
                        catch (Exception ex)
                        {
                            Messenger.AddError(string.Format(Messages.MSG_ERROR_DURING_REMOVING_MOD_0, modToRemove.Name), ex);
                        }

                        asyncJob.PercentFinished = doneCount++;

                        Messenger.AddInfo(string.Format(Messages.MSG_MOD_RMODVED_0, modToRemove.Name));

                        if (!silent)
                            Messenger.AddInfo(Constants.SEPARATOR);
                    }

                    return true;
                },
                (result, ex) =>
                {
                    EventDistributor.InvokeAsyncTaskDone(Instance);
                    View.SetEnabledOfAllControls(true);
                    View.SetProgressBarStates(false);
                    View.ResetSelectedNode();

                    InvalidateView();

                    MainController.SaveKSPConfig();
                },
                (percentage) => { View.SetProgressBarStates(true, modsToRemove.Length, percentage); });
            asyncJob.Run();
        }
        /// <summary>
        /// Scans the KSP GameData directory for installed mods and adds them to the ModSelection.
        /// </summary>
        internal static void ScanGameData()
        {
            Messenger.AddDebug(Constants.SEPARATOR);
            Messenger.AddDebug(Messages.MSG_SCAN_GAMDATA_FOLDER_STARTED);
            Messenger.AddDebug(Constants.SEPARATOR);
            EventDistributor.InvokeAsyncTaskStarted(Instance);
            View.SetEnabledOfAllControls(false);
            View.ShowBusy = true;

            AsyncTask<bool> asyncJob = new AsyncTask<bool>();
            asyncJob.SetCallbackFunctions(() =>
            {
                string[] ignoreDirs = new string[] { "squad", "myflags", "nasamission" };
                List<ScanInfo> entries = new List<ScanInfo>();
                try
                {
                    string scanDir = KSPPathHelper.GetPath(KSPPaths.GameData);
                    string[] dirs = Directory.GetDirectories(scanDir);
                    foreach (string dir in dirs)
                    {
                        string dirname = dir.Substring(dir.LastIndexOf(Path.DirectorySeparatorChar) + 1);
                        if (!ignoreDirs.Contains(dirname.ToLower()))
                        {
                            Messenger.AddDebug(string.Format(Messages.MSG_DIRECTORY_0_FOUND, dirname));
                            ScanInfo scanInfo = new ScanInfo(dirname, dir, false);
                            entries.Add(scanInfo);
                            ScanDir(scanInfo);
                        }
                    }

                    List<ScanInfo> unknowns = GetUnknowenNodes(entries);
                    if (unknowns.Count > 0)
                    {
                        foreach (ScanInfo unknown in unknowns)
                        {
                            ModNode node = ScanInfoToKSPMA_TreeNode(unknown);
                            RefreshCheckedStateOfMods(new[] { node });
                            Model.Nodes.Add(node);
                            Messenger.AddInfo(string.Format(Messages.MSG_MOD_ADDED_0, node.Text));
                        }
                    }
                    else
                        Messenger.AddInfo(Messages.MSG_SCAN_NO_NEW_MODS_FOUND);
                }
                catch (Exception ex)
                {
                    Messenger.AddError(Messages.MSG_SCAN_ERROR_DURING_SCAN, ex);
                }

                return true;
            },
                (result, ex) =>
                {
                    Messenger.AddDebug(Constants.SEPARATOR);

                    EventDistributor.InvokeAsyncTaskDone(Instance);
                    View.SetEnabledOfAllControls(true);
                    View.ShowBusy = false;
                });
            asyncJob.Run();
        }
        /// <summary>
        /// Processes all passed nodes. (Adds/Removes the MOD to/from the KSP install folders).
        /// Calls SolveConflicts if there are any conflicts.
        /// </summary>
        /// <param name="nodeArray">The NodeArray to process.</param>
        /// <param name="silent">Determines if info messages should be added displayed.</param>
        public static void ProcessModsAsync(ModNode[] nodeArray, bool silent = false)
        {
            if (ModRegister.HasConflicts)
            {
                if (!OpenConflictSolver())
                {
                    MessageBox.Show(View.ParentForm, Messages.MSG_PROCESSING_ABORDED_CONFLICTS_DETECTED, Messages.MSG_TITLE_CONFLICTS_DETECTED);
                    Messenger.AddInfo(Messages.MSG_PROCESSING_ABORDED_CONFLICTS_DETECTED);
                    return;
                }
            }

            EventDistributor.InvokeAsyncTaskStarted(Instance);
            View.SetEnabledOfAllControls(false);
            View.SetProgressBarStates(true, 1, 0);

            AsyncTask<bool> asyncJob = new AsyncTask<bool>();
            asyncJob.SetCallbackFunctions(() =>
            {
                ProcessMods(nodeArray, silent);

                return true;
            },
                (result, ex) =>
                {
                    EventDistributor.InvokeAsyncTaskDone(Instance);
                    View.SetEnabledOfAllControls(true);
                    View.SetProgressBarStates(false);

                    if (ex != null)
                    {
                        string msg = string.Format(Messages.MSG_ERROR_DURING_PROCESSING_MOD_0, ex.Message);
                        Messenger.AddError(msg, ex);
                        MessageBox.Show(View, msg, Messages.MSG_TITLE_ERROR, MessageBoxButtons.OK, MessageBoxIcon.Error);
                    }
                });
            asyncJob.Run();
        }
        /// <summary>
        /// Creates nodes from the ModInfos and adds the nodes to the ModSelection.
        /// </summary>
        /// <param name="modInfos">The nodes to add.</param>
        internal static void AddModsAsync(ModInfo[] modInfos, bool showCollisionDialog = true)
        {
            if (modInfos.Length <= 0)
            {
                Messenger.AddError(Messages.MSG_ADD_MODS_FAILED_PARAM_EMPTY_MODINFOS);
                return;
            }

            EventDistributor.InvokeAsyncTaskStarted(Instance);
            View.SetEnabledOfAllControls(false);
            View.SetProgressBarStates(true, modInfos.Length, 0);

            AsyncTask<List<ModNode>> asnyJob = new AsyncTask<List<ModNode>>();
            asnyJob.SetCallbackFunctions(() =>
            {
                return AddMods(modInfos, showCollisionDialog, asnyJob);
            },
                (result, ex) =>
                {
                    EventDistributor.InvokeAsyncTaskDone(Instance);
                    View.SetEnabledOfAllControls(true);
                    View.SetProgressBarStates(false);
                },
                (percentage) =>
                {
                    View.SetProgressBarStates(true, modInfos.Length, percentage);
                });
            asnyJob.Run();
        }
        /// <summary>
        /// Starts a update check for the mod and updates it if it's outdated.
        /// </summary>
        /// <param name="mods">The mod of the mod to update.</param>
        public static void UpdateOutdatedModsAsync(ModNode[] mods)
        {
            EventDistributor.InvokeAsyncTaskStarted(Instance);
            View.SetEnabledOfAllControls(false);
            View.ShowBusy = true;

            AsyncTask<bool> asyncJob = new AsyncTask<bool>();
            asyncJob.SetCallbackFunctions(() =>
            {
                _UpdateOutdatedMods(mods);
                return true;
            },
                (result, ex) =>
                {
                    EventDistributor.InvokeAsyncTaskDone(Instance);
                    View.SetEnabledOfAllControls(true);
                    View.ShowBusy = false;

                    if (ex != null)
                        Messenger.AddError(string.Format(Messages.MSG_ERROR_DURING_MOD_UPDATE_0, ex.Message), ex);
                });
            asyncJob.Run();
        }
        /// <summary>
        /// Checks all Mods from the ModSelection.
        /// </summary>
        public static void CheckAllMods()
        {
            Messenger.AddDebug(Messages.MSG_CHECKING_ALL_MODS);

            EventDistributor.InvokeAsyncTaskStarted(Instance);
            View.SetEnabledOfAllControls(false);

            int maxCount = Mods.Length;
            View.SetProgressBarStates(true, maxCount, 0);

            int count = 0;
            AsyncTask<bool> asyncJob = new AsyncTask<bool>();
            asyncJob.SetCallbackFunctions(
                () =>
                {
                    foreach (ModNode mod in Mods)
                    {
                        Messenger.AddDebug(string.Format(Messages.MSG_CHECKING_MOD_0, mod.Name));
                        asyncJob.ProgressChanged(null, new ProgressChangedEventArgs(++count, null));
                        View.InvokeIfRequired(() => { mod.Checked = true; });
                    }

                    return true;
                },
                (result, ex) =>
                {
                    EventDistributor.InvokeAsyncTaskDone(Instance);
                    View.SetEnabledOfAllControls(true);
                    View.SetProgressBarStates(false);

                    InvalidateView();

                    if (ex != null)
                        Messenger.AddError(string.Format(Messages.MSG_ERROR_DURING_REFRESH_CHECKED_STATE_0, ex.Message), ex);
                },
                (processedCount) =>
                {
                    View.SetProgressBarStates(true, maxCount, processedCount);
                });
            asyncJob.Run();
        }
        /// <summary>
        /// Traversing the complete tree and renews the checked state of all nodes.
        /// </summary>
        public static void RefreshCheckedStateOfModsAsync(ModNode[] mods)
        {
            EventDistributor.InvokeAsyncTaskStarted(Instance);
            View.SetEnabledOfAllControls(false);

            int maxCount = ModSelectionTreeModel.GetFullNodeCount(mods);
            View.SetProgressBarStates(true, maxCount, 0);

            int count = 0;
            AsyncTask<bool> asyncJob = new AsyncTask<bool>();
            asyncJob.SetCallbackFunctions(
                () =>
                {
                    foreach (ModNode mod in mods)
                    {
                        Messenger.AddDebug(string.Format(Messages.MSG_REFRESHING_CHECKEDSTATE_0, mod.Name));
                        ModNode rootNode = mod.ZipRoot;
                        RefreshCheckedState(rootNode, ref count, asyncJob);
                    }
                    return true;
                },
                (result, ex) =>
                {
                    EventDistributor.InvokeAsyncTaskDone(Instance);
                    View.SetEnabledOfAllControls(true);
                    View.SetProgressBarStates(false);
                    InvalidateView();

                    if (ex != null)
                        Messenger.AddError(string.Format(Messages.MSG_ERROR_DURING_REFRESH_CHECKED_STATE_0, ex.Message), ex);
                },
                (processedCount) =>
                {
                    View.SetProgressBarStates(true, maxCount, processedCount);
                });
            asyncJob.Run();
        }