/// <summary>
            /// Tests to see if we can add the folder to the project.  Returns true if it's ok, false if it's not.
            /// </summary>
            /// <param name="folderToAdd">Project reference (from data object) using the format: {Guid}|project|folderPath</param>
            /// <param name="targetNode">Node to add the new folder to</param>
            private Addition CanAddFolderFromProjectReference(string folderToAdd) {
                Utilities.ArgumentNotNullOrEmpty(folderToAdd, "folderToAdd");

                var targetFolderNode = TargetNode.GetDragTargetHandlerNode();

                string folder;
                IVsHierarchy sourceHierarchy;
                GetPathAndHierarchy(folderToAdd, out folder, out sourceHierarchy);

                // Ensure we don't end up in an endless recursion
                if (Utilities.IsSameComObject(Project, sourceHierarchy)) {
                    if (String.Equals(folder, targetFolderNode.FullPathToChildren, StringComparison.OrdinalIgnoreCase)) {
                        if (DropEffect == DropEffect.Move &&
                            IsBadMove(targetFolderNode.FullPathToChildren, folder, false)) {
                            return null;
                        }
                    }

                    if (targetFolderNode.FullPathToChildren.StartsWith(folder, StringComparison.OrdinalIgnoreCase) &&
                        !String.Equals(targetFolderNode.FullPathToChildren, folder, StringComparison.OrdinalIgnoreCase)) {
                        // dragging a folder into a child, that's not allowed
                        Utilities.ShowMessageBox(
                            Project.Site,
                            SR.GetString(SR.CannotMoveIntoSubfolder, CommonUtils.GetFileOrDirectoryName(folder)),
                            null,
                            OLEMSGICON.OLEMSGICON_CRITICAL,
                            OLEMSGBUTTON.OLEMSGBUTTON_OK,
                            OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST);
                        return null;
                    }
                }

                var targetPath = Path.Combine(targetFolderNode.FullPathToChildren, CommonUtils.GetFileOrDirectoryName(folder));
                if (File.Exists(targetPath)) {
                    Utilities.ShowMessageBox(
                       Project.Site,
                       SR.GetString(SR.CannotAddFileExists, CommonUtils.GetFileOrDirectoryName(folder)),
                       null,
                       OLEMSGICON.OLEMSGICON_CRITICAL,
                       OLEMSGBUTTON.OLEMSGBUTTON_OK,
                       OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST);
                    return null;
                }

                if (Directory.Exists(targetPath)) {
                    if (DropEffect == DropEffect.Move) {
                        if (targetPath == folderToAdd) {
                            CannotMoveSameLocation(folderToAdd);
                        } else {
                            Utilities.ShowMessageBox(
                               Project.Site,
                               SR.GetString(SR.CannotMoveFolderExists, CommonUtils.GetFileOrDirectoryName(folder)),
                               null,
                               OLEMSGICON.OLEMSGICON_CRITICAL,
                               OLEMSGBUTTON.OLEMSGBUTTON_OK,
                               OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST);
                        }
                        return null;
                    }

                    var dialog = new OverwriteFileDialog(
                        SR.GetString(SR.OverwriteFilesInExistingFolder, CommonUtils.GetFileOrDirectoryName(folder)),
                        false
                    );
                    dialog.Owner = Application.Current.MainWindow;
                    var res = dialog.ShowDialog();
                    if (res == null) {
                        // cancel, abort the whole copy
                        return null;
                    } else if (!dialog.ShouldOverwrite) {
                        // no, don't copy the folder
                        return SkipOverwriteAddition.Instance;
                    }
                    // otherwise yes, and we'll prompt about the files.
                }

                string targetFileName = CommonUtils.GetFileOrDirectoryName(folder);
                if (Utilities.IsSameComObject(Project, sourceHierarchy) &&
                    String.Equals(targetFolderNode.FullPathToChildren, folder, StringComparison.OrdinalIgnoreCase)) {
                    // copying a folder onto its self, make a copy
                    targetFileName = GetCopyName(targetFolderNode.FullPathToChildren);
                }

                List<Addition> additions = new List<Addition>();
                uint folderId;
                if (ErrorHandler.Failed(sourceHierarchy.ParseCanonicalName(folder, out folderId))) {
                    // the folder may have been deleted between the copy & paste
                    ReportMissingItem(folder);
                    return null;
                }

                if (Path.Combine(targetFolderNode.FullPathToChildren, targetFileName).Length >= NativeMethods.MAX_FOLDER_PATH) {
                    Utilities.ShowMessageBox(
                        Project.Site,
                        SR.GetString(SR.FolderPathTooLongShortMessage),
                        null,
                        OLEMSGICON.OLEMSGICON_CRITICAL,
                        OLEMSGBUTTON.OLEMSGBUTTON_OK,
                        OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST);
                    return null;
                }

                if (!WalkSourceProjectAndAdd(sourceHierarchy, folderId, targetFolderNode.FullPathToChildren, false, additions, targetFileName)) {
                    return null;
                }

                if (additions.Count == 1) {
                    return (FolderAddition)additions[0];
                }

                Debug.Assert(additions.Count == 0);
                return null;
            }
            /// <summary>
            /// Adds an item from a project refererence to target node.
            /// </summary>
            /// <param name="projectRef"></param>
            /// <param name="targetNode"></param>
            private Addition CanAddFileFromProjectReference(string projectRef, string targetFolder, bool fromFolder = false) {
                Utilities.ArgumentNotNullOrEmpty("projectRef", projectRef);

                IVsSolution solution = Project.GetService(typeof(IVsSolution)) as IVsSolution;
                Utilities.CheckNotNull(solution);

                uint itemidLoc;
                IVsHierarchy hierarchy;
                string str;
                VSUPDATEPROJREFREASON[] reason = new VSUPDATEPROJREFREASON[1];
                if (ErrorHandler.Failed(solution.GetItemOfProjref(projectRef, out hierarchy, out itemidLoc, out str, reason))) {
                    // the file may have been deleted between the copy & paste
                    string path;
                    Guid projectGuid;
                    GetPathAndProjectId(projectRef, out projectGuid, out path);
                    ReportMissingItem(path);
                    return null;
                }

                Utilities.CheckNotNull(hierarchy);

                // This will throw invalid cast exception if the hierrachy is not a project.
                IVsProject project = (IVsProject)hierarchy;

                string moniker;
                ErrorHandler.ThrowOnFailure(project.GetMkDocument(itemidLoc, out moniker));

                if (DropEffect == DropEffect.Move && IsBadMove(targetFolder, moniker, true)) {
                    return null;
                }

                if (!File.Exists(moniker)) {
                    VsShellUtilities.ShowMessageBox(
                            Project.Site,
                            String.Format("The item '{0}' does not exist in the project directory. It may have been moved, renamed or deleted.", Path.GetFileName(moniker)),
                            null,
                            OLEMSGICON.OLEMSGICON_CRITICAL,
                            OLEMSGBUTTON.OLEMSGBUTTON_OK,
                            OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST);
                    return null;
                }

                string newPath = Path.Combine(targetFolder, Path.GetFileName(moniker));
                var existingChild = Project.FindNodeByFullPath(moniker);
                if (existingChild != null && existingChild.IsLinkFile) {
                    if (DropEffect == DropEffect.Move) {
                        // moving a link file, just update it's location in the hierarchy
                        return new ReparentLinkedFileAddition(Project, targetFolder, moniker);
                    } else {
                        // 
                        VsShellUtilities.ShowMessageBox(
                                Project.Site,
                                String.Format("Cannot copy linked files within the same project. You cannot have more than one link to the same file in a project."),
                                null,
                                OLEMSGICON.OLEMSGICON_CRITICAL,
                                OLEMSGBUTTON.OLEMSGBUTTON_OK,
                                OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST);
                        return null;
                    }
                } else if (File.Exists(newPath) && CommonUtils.IsSamePath(newPath, moniker)) {
                    newPath = GetCopyName(newPath);
                }

                bool ok = false;
                if (DropEffect == DropEffect.Move && Utilities.IsSameComObject(project, Project)) {
                    ok = Project.Tracker.CanRenameItem(moniker, newPath, VSRENAMEFILEFLAGS.VSRENAMEFILEFLAGS_NoFlags);
                } else {
                    ok = Project.Tracker.CanAddItems(
                        new[] { newPath },
                        new VSQUERYADDFILEFLAGS[] { VSQUERYADDFILEFLAGS.VSQUERYADDFILEFLAGS_NoFlags });
                }

                if (ok) {
                    if (File.Exists(newPath)) {
                        if (DropEffect == DropEffect.Move &&
                            Utilities.IsSameComObject(project, Project) &&
                            Project.FindNodeByFullPath(newPath) != null) {
                            // if we're overwriting an item, we're moving it, make sure that's ok.
                            // OverwriteFileAddition will handle the remove from the hierarchy
                            if (!Project.Tracker.CanRemoveItems(new[] { newPath }, new[] { VSQUERYREMOVEFILEFLAGS.VSQUERYREMOVEFILEFLAGS_NoFlags })) {
                                return null;
                            }
                        }
                        bool? overwrite = OverwriteAllItems;

                        if (overwrite == null) {
                            var dialog = new OverwriteFileDialog(String.Format("A file with the name '{0}' already exists.  Do you want to replace it?", Path.GetFileName(moniker)), true);
                            dialog.Owner = Application.Current.MainWindow;
                            bool? dialogResult = dialog.ShowDialog();

                            if (dialogResult != null && !dialogResult.Value) {
                                // user cancelled
                                return null;
                            }

                            overwrite = dialog.ShouldOverwrite;

                            if (dialog.AllItems) {
                                OverwriteAllItems = overwrite;
                            }
                        }

                        if (overwrite.Value) {
                            return new OverwriteFileAddition(Project, targetFolder, DropEffect, moniker, Path.GetFileName(newPath), project);
                        } else {
                            return NopAddition.Instance;
                        }
                    }

                    if (newPath.Length >= NativeMethods.MAX_PATH) {
                        VsShellUtilities.ShowMessageBox(
                            Project.Site,
                            "The filename is too long.",
                            null,
                            OLEMSGICON.OLEMSGICON_CRITICAL,
                            OLEMSGBUTTON.OLEMSGBUTTON_OK,
                            OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST);
                        return null;
                    }
                    return new FileAddition(Project, targetFolder, DropEffect, moniker, Path.GetFileName(newPath), project);
                }
                return null;
            }
            /// <summary>
            /// Prompts if the file should be overwriten.  Returns false if the user cancels, true if the user answered yes/no
            /// </summary>
            /// <param name="filename"></param>
            /// <param name="dialog"></param>
            /// <returns></returns>
            private static bool PromptOverwriteFile(string filename, out OverwriteFileDialog dialog) {
                dialog = new OverwriteFileDialog(SR.GetString(SR.FileAlreadyExists, Path.GetFileName(filename)), true);
                dialog.Owner = Application.Current.MainWindow;
                bool? dialogResult = dialog.ShowDialog();

                if (dialogResult != null && !dialogResult.Value) {
                    // user cancelled
                    return false;
                }
                return true;
            }
            /// <summary>
            /// Tests to see if we can add the folder to the project.  Returns true if it's ok, false if it's not.
            /// </summary>
            /// <param name="folderToAdd">Project reference (from data object) using the format: {Guid}|project|folderPath</param>
            /// <param name="targetNode">Node to add the new folder to</param>
            private Addition CanAddFolderFromProjectReference(string folderToAdd) {
                Utilities.ArgumentNotNullOrEmpty(folderToAdd, "folderToAdd");

                var targetFolderNode = TargetNode.GetDragTargetHandlerNode();

                string folder;
                IVsHierarchy sourceHierarchy;
                GetPathAndHierarchy(folderToAdd, out folder, out sourceHierarchy);

                // Ensure we don't end up in an endless recursion
                if (Utilities.IsSameComObject(Project, sourceHierarchy)) {
                    if (String.Equals(folder, targetFolderNode.FullPathToChildren, StringComparison.OrdinalIgnoreCase)) {
                        if (DropEffect == DropEffect.Move &&
                            IsBadMove(targetFolderNode.FullPathToChildren, folder, false)) {
                            return null;
                        }
                    }

                    if (targetFolderNode.FullPathToChildren.StartsWith(folder, StringComparison.OrdinalIgnoreCase) &&
                        !String.Equals(targetFolderNode.FullPathToChildren, folder, StringComparison.OrdinalIgnoreCase)) {
                        // dragging a folder into a child, that's not allowed
                        VsShellUtilities.ShowMessageBox(
                            Project.Site,
                            String.Format("Cannot move '{0}'. The destination folder is a subfolder of the source folder.", Path.GetFileName(CommonUtils.TrimEndSeparator(folder))),
                            null,
                            OLEMSGICON.OLEMSGICON_CRITICAL,
                            OLEMSGBUTTON.OLEMSGBUTTON_OK,
                            OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST);
                        return null;
                    }
                }

                var targetPath = Path.Combine(targetFolderNode.FullPathToChildren, Path.GetFileName(CommonUtils.TrimEndSeparator(folder)));
                if (File.Exists(targetPath)) {
                    VsShellUtilities.ShowMessageBox(
                       Project.Site,
                       String.Format("Unable to add '{0}'. A file with that name already exists.", Path.GetFileName(CommonUtils.TrimEndSeparator(folder))),
                       null,
                       OLEMSGICON.OLEMSGICON_CRITICAL,
                       OLEMSGBUTTON.OLEMSGBUTTON_OK,
                       OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST);
                    return null;
                }

                if (Directory.Exists(targetPath)) {
                    if (DropEffect == DropEffect.Move) {
                        if (targetPath == folderToAdd) {
                            CannotMoveSameLocation(folderToAdd);
                        } else {
                            VsShellUtilities.ShowMessageBox(
                               Project.Site,
                               String.Format("Cannot move the folder '{0}'. A folder with that name already exists in the destination directory.", Path.GetFileName(CommonUtils.TrimEndSeparator(folder))),
                               null,
                               OLEMSGICON.OLEMSGICON_CRITICAL,
                               OLEMSGBUTTON.OLEMSGBUTTON_OK,
                               OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST);
                        }
                        return null;
                    }

                    var dialog = new OverwriteFileDialog(String.Format(
@"This folder already contains a folder called '{0}'

If the files in the existing folder have the same names as files in the 
folder you are copying, do you want to replace the existing files?", Path.GetFileName(CommonUtils.TrimEndSeparator(folder))), false);
                    dialog.Owner = Application.Current.MainWindow;
                    var res = dialog.ShowDialog();
                    if (res == null) {
                        // cancel, abort the whole copy
                        return null;
                    } else if (!dialog.ShouldOverwrite) {
                        // no, don't copy the folder
                        return NopAddition.Instance;
                    }
                    // otherwise yes, and we'll prompt about the files.
                }

                string targetFileName = Path.GetFileName(CommonUtils.TrimEndSeparator(folder));
                if (Utilities.IsSameComObject(Project, sourceHierarchy) &&
                    String.Equals(targetFolderNode.FullPathToChildren, folder, StringComparison.OrdinalIgnoreCase)) {
                    // copying a folder onto its self, make a copy
                    targetFileName = GetCopyName(targetFolderNode.FullPathToChildren);
                }

                List<Addition> additions = new List<Addition>();
                uint folderId;
                if (ErrorHandler.Failed(sourceHierarchy.ParseCanonicalName(folder, out folderId))) {
                    // the folder may have been deleted between the copy & paste
                    ReportMissingItem(folder);
                    return null;
                }
                
                if (Path.Combine(targetFolderNode.FullPathToChildren, targetFileName).Length >= NativeMethods.MAX_FOLDER_PATH) {
                    VsShellUtilities.ShowMessageBox(
                        Project.Site,
                        "The folder name is too long.",
                        null,
                        OLEMSGICON.OLEMSGICON_CRITICAL,
                        OLEMSGBUTTON.OLEMSGBUTTON_OK,
                        OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST);
                    return null;
                }

                if (!WalkSourceProjectAndAdd(sourceHierarchy, folderId, targetFolderNode.FullPathToChildren, false, additions, targetFileName)) {
                    return null;
                }

                if (additions.Count == 1) {
                    return (FolderAddition)additions[0];
                }

                Debug.Assert(additions.Count == 0);
                return null;
            }