/// <summary>
        /// Finds the root folder of the mod that can be installed to the KSP install folder.
        /// </summary>
        /// <param name="node">Node to start the search from.</param>
        /// <returns>The root folder of the mod that can be installed to the KSP install folder.</returns>
        private static bool FindAndSetDestinationPaths(ModNode node)
        {
            List <ModNode> kspFolders = new List <ModNode>();
            List <ModNode> craftFiles = new List <ModNode>();

            ModSelectionTreeModel.GetAllKSPFolders(node, ref kspFolders, ref craftFiles);
            if (kspFolders.Count == 1)
            {
                SetDestinationPaths(kspFolders[0], false);
            }
            else if (kspFolders.Count > 1)
            {
                kspFolders.Sort((node1, node2) =>
                {
                    if (node2.Depth == node1.Depth)
                    {
                        return(node1.Text.CompareTo(node2.Text));
                    }
                    else
                    {
                        return(node2.Depth - node1.Depth);
                    }
                });

                bool lastResult = false;
                foreach (ModNode kspFolder in kspFolders)
                {
                    lastResult = SetDestinationPaths(kspFolder, lastResult);
                }
            }

            if (craftFiles.Count > 0)
            {
                foreach (ModNode craftNode in craftFiles)
                {
                    string vab = KSPPathHelper.GetPath(KSPPaths.VAB);
                    string sph = KSPPathHelper.GetPath(KSPPaths.SPH);
                    if (!craftNode.HasDestination || (!craftNode.Destination.StartsWith(vab, StringComparison.CurrentCultureIgnoreCase) &&
                                                      !craftNode.Destination.StartsWith(sph, StringComparison.CurrentCultureIgnoreCase)))
                    {
                        SetCraftDestination(craftNode);
                    }
                }
            }

            if (node.HasDestination || node.HasDestinationForChilds)
            {
                node.SetChecked(true);
            }

            return((kspFolders.Count > 0) || (craftFiles.Count > 0));
        }
        /// <summary>
        /// Checks the node and all parents.
        /// </summary>
        /// <param name="node">The node to check.</param>
        private static void CheckNodeAndParents(ModNode node)
        {
            // check node and parent nodes.
            node.SetChecked(true);

            if (node.Parent == null || node.Parent.Index == -1)
            {
                return;
            }

            Node parent = node.Parent;

            while (parent != null && parent.Index > -1)
            {
                ((ModNode)parent).SetChecked(true);
                parent = parent.Parent;
            }
        }
        /// <summary>
        /// Removes the part from KSP and unchecks it in the mod selection.
        /// </summary>
        /// <param name="partNode">The part node to remove.</param>
        public static void RemovePart(PartNode partNode)
        {
            if (partNode == null)
            {
                return;
            }

            string  partPath = Path.GetDirectoryName(KSPPathHelper.GetAbsolutePath(partNode.FilePath));
            ModNode node     = ModSelectionTreeModel.SearchNodeByDestination(partNode.FilePath, ModSelectionController.Model);

            DialogResult dlgResult = DialogResult.Cancel;

            if (node == null)
            {
                dlgResult = MessageBox.Show(View.ParentForm, Messages.MSG_PART_NOT_FROM_MOD_DELETE_WARNING, string.Empty, MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
            }

            if (partNode.Nodes != null && partNode.Nodes.Count > 0)
            {
                StringBuilder sb = new StringBuilder();
                sb.AppendLine(Messages.MSG_PART_USED_DELETE_WARNING);
                foreach (PartNode tempNode in partNode.Nodes)
                {
                    sb.AppendFormat("- {0}{1}", tempNode.Title, Environment.NewLine);
                }
                sb.AppendLine();
                sb.AppendLine(Messages.MSG_DELETE_ANYWAY);
                dlgResult = MessageBox.Show(View.ParentForm, sb.ToString(), string.Empty, MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
            }

            if ((node != null || dlgResult == DialogResult.Yes) && Directory.Exists(partPath))
            {
                Messenger.AddInfo(string.Format(Messages.MSG_DIR_0_OF_PART_1_DELETED, partPath, Path.GetFileName(partPath)));
                Directory.Delete(partPath, true);

                if (partNode.Nodes != null)
                {
                    foreach (var n in partNode.Nodes)
                    {
                        var craft = n.Tag as CraftNode;
                        if (craft == null)
                        {
                            continue;
                        }

                        craft.RemovePartRelation(partNode);
                    }
                }

                if (node != null)
                {
                    node = node.Parent as ModNode;
                    node.SetChecked(false);
                    node.IsInstalled = false;
                    node.NodeType    = NodeType.UnknownFolder;
                    Messenger.AddInfo(string.Format(Messages.MSG_MODNODE_0_UNCHECKED, node.Name));
                    foreach (ModNode child in node.Nodes)
                    {
                        child.SetChecked(false);
                        child.IsInstalled = false;
                        child.NodeType    = child.IsFile ? NodeType.UnknownFile : NodeType.UnknownFolder;
                        Messenger.AddInfo(string.Format(Messages.MSG_MODNODE_0_UNCHECKED, child.Name));
                    }
                }

                model.Nodes.Remove(partNode);
                allNodes.Remove(partNode);
            }
        }
        /// <summary>
        /// Creates a TreeNode for the XmlNode information.
        /// </summary>
        private static void FillModTreeNode(XmlNode mod, ref ModNode node)
        {
            string kspForumURL   = string.Empty;
            string curseForgeURL = string.Empty;

            node.AddDate = DateTime.Now.ToString();
            foreach (XmlAttribute att in mod.Attributes)
            {
                if (att.Name == Constants.NAME)
                {
                    node.Name = att.Value;
                }
                else if (att.Name == Constants.KEY)
                {
                    node.Key = att.Value;
                }
                else if (att.Name == Constants.ADDDATE)
                {
                    node.AddDate = att.Value;
                }
                else if (att.Name == Constants.VERSION)
                {
                    node.Version = att.Value;
                }
                else if (att.Name == Constants.GAMEVERSION)
                {
                    node.KSPVersion = att.Value;
                }
                else if (att.Name == Constants.NOTE)
                {
                    node.Note = att.Value;
                }
                else if (att.Name == Constants.PRODUCTID)
                {
                    node.ProductID = att.Value;
                }
                else if (att.Name == Constants.CREATIONDATE)
                {
                    node.CreationDate = att.Value;
                }
                else if (att.Name == Constants.CHANGEDATE)
                {
                    node.ChangeDate = att.Value;
                }
                else if (att.Name == Constants.AUTHOR)
                {
                    node.Author = att.Value;
                }
                else if (att.Name == Constants.RATING)
                {
                    node.Rating = att.Value;
                }
                else if (att.Name == Constants.DOWNLOADS)
                {
                    node.Downloads = att.Value;
                }
                else if (att.Name == Constants.MODURL)
                {
                    node.ModURL = att.Value;
                }
                else if (att.Name == Constants.AVCURL)
                {
                    node.AvcURL = att.Value;
                }
                else if (att.Name == Constants.ADDITIONALURL)
                {
                    node.AdditionalURL = att.Value;
                }
                else if (att.Name == Constants.CHECKED)
                {
                    node.SetChecked((att.Value.Equals(Constants.TRUE, StringComparison.CurrentCultureIgnoreCase)), true);
                }
                else if (att.Name == Constants.NODETYPE)
                {
                    node.NodeType = (NodeType)int.Parse(att.Value);
                }
                else if (att.Name == Constants.DESTINATION)
                {
                    node.Destination = att.Value;
                }
                else if (att.Name == Constants.FORUMURL)
                {
                    kspForumURL = att.Value;
                }
                else if (att.Name == Constants.CURSEFORGEURL)
                {
                    curseForgeURL = att.Value;
                }
                else if (att.Name == Constants.VERSIONCONTROLERNAME)
                {
                    node.SiteHandlerName = att.Value;

                    switch (att.Value)
                    {
                    case "KSPForum":     // KSPForum
                        if (string.IsNullOrEmpty(node.ModURL))
                        {
                            node.ModURL = kspForumURL;
                        }
                        if (string.IsNullOrEmpty(node.AdditionalURL))
                        {
                            node.AdditionalURL = curseForgeURL;
                        }
                        break;

                    case "CurseForge":     // CurseForge
                        if (string.IsNullOrEmpty(node.ModURL))
                        {
                            node.ModURL = curseForgeURL;
                        }
                        if (string.IsNullOrEmpty(node.AdditionalURL))
                        {
                            node.AdditionalURL = kspForumURL;
                        }
                        break;
                    }
                }
            }

            foreach (XmlNode modEntry in mod.ChildNodes)
            {
                ModNode newNode = new ModNode();
                node.Nodes.Add(newNode);
                FillModTreeNode(modEntry, ref newNode);
            }
        }
        /// <summary>
        /// Tries to find notes in the new mod, that matches to the outdated mod.
        /// If a matching node was found the destination and/or the checked state of the node will be copied.
        /// </summary>
        /// <param name="outdatedMod">The outdated mod.</param>
        /// <param name="newMod">The new (updated) mod.</param>
        /// <returns>True if matching files where found, otherwise false.</returns>
        public static bool TryCopyDestToMatchingNodes(ICopyModInfo outdatedMod, ModNode newMod)
        {
            // Get all files with destination.
            List <ICopyModInfo> outdatedFileNodes = outdatedMod.GetAllFileNodesAsICopyModInfo();

            if (outdatedFileNodes.Count == 0)
            {
                Messenger.AddInfo("No files in outdated mod found!");
                return(false);
            }

            // Get all files of the new mod
            List <ICopyModInfo> newModFileNodes         = newMod.GetAllFileNodesAsICopyModInfo();
            List <ICopyModInfo> matchingNewModFileNodes = new List <ICopyModInfo>();

            if (newModFileNodes.Count == 0)
            {
                Messenger.AddInfo("No files in new mod found!");
                return(false);
            }

            foreach (var file in outdatedFileNodes)
            {
                // Ignore mod folder cause it may contain version numbers
                var fullTreePath = file.GetFullTreePath().Remove(0, file.GetRoot().GetFullTreePath().Length);

                ModNode matchingNew = ModSelectionTreeModel.SearchNodeByPathNew(fullTreePath, newMod, '/');
                if (matchingNew == null)
                {
                    // ignore not matching old files
                    continue;
                }

                if (newModFileNodes.Contains(matchingNew))
                {
                    newModFileNodes.Remove(matchingNew);
                }

                matchingNew.Destination = file.Destination;
                matchingNew.SetChecked(file.Checked, true);
                matchingNewModFileNodes.Add(matchingNew);

                // Copy infos for each parent up to root node.
                var parentNew = matchingNew.Parent as ModNode;
                var parentOld = file.GetParent();
                while (parentNew != null && parentOld != null)
                {
                    parentNew.Destination = parentOld.Destination;
                    parentNew.SetChecked(parentOld.Checked || parentOld.HasCheckedChilds, true);

                    parentNew = parentNew.Parent as ModNode;
                    parentOld = parentOld.GetParent();
                }
            }

            var unknownPaths = new List <ICopyModInfo>();

            if (newModFileNodes.Count > 0)
            {
                unknownPaths = CheckForUnknownDestinationPaths(newModFileNodes, matchingNewModFileNodes, outdatedFileNodes);
            }

            if (unknownPaths.Count > 0)
            {
                Messenger.AddInfo("Invalid destination path found for:");

                foreach (var file in unknownPaths)
                {
                    Messenger.AddInfo(string.Format("File: {0}", file.Destination));
                }

                Messenger.AddInfo("Manual update is required!");

                return(false);
            }

            return(true);
        }