/// <summary>
        /// Does the actual work of iterating the folder tree.
        /// This is a breadth-first traversal.
        /// Code was adapted from the MSDN documentation for
        /// walking an NTFS directory.
        /// </summary>
        /// <param name="rootFolder">Folder to start the traversal from</param>
        private Collection <ProcessedFileInfo> BreadthFirstTraversal(String rootFolder)
        {
            // Data structure to hold names of subfolders to be
            // examined for files.
            Stack <string> dirs = new Stack <string>(20);

            if (System.IO.Directory.Exists(rootFolder))
            {
                //
                OnDirectoryWalkStarted(new DirectoryWalkEventArgs(rootFolder,
                                                                  String.Empty,
                                                                  DirectoryWalkObjectType.Directory,
                                                                  DirectoryWalkOperationResult.NotApplicable,
                                                                  "Directory walk started."));

                dirs.Push(rootFolder);
                FileProcessorLengthFirst lengthFirstFileProc    = new FileProcessorLengthFirst();
                IFileProcessor           fileProcessorInterface = lengthFirstFileProc as IFileProcessor;
                fileProcessorInterface.Initialize();
                while (dirs.Count > 0)
                {
                    string   currentDir = dirs.Pop();
                    string[] subDirs;
                    try
                    {
                        subDirs = System.IO.Directory.GetDirectories(currentDir);
                        OnFileAccessed(new DirectoryWalkEventArgs(currentDir,
                                                                  String.Empty,
                                                                  DirectoryWalkObjectType.Directory,
                                                                  DirectoryWalkOperationResult.Success,
                                                                  "Directory listing (subdirectories) taken successfully."));
                    }
                    // An UnauthorizedAccessException exception will be thrown if we do not have
                    // discovery permission on a folder or file. It may or may not be acceptable
                    // to ignore the exception and continue enumerating the remaining files and
                    // folders. It is also possible (but unlikely) that a DirectoryNotFound exception
                    // will be raised. This will happen if currentDir has been deleted by
                    // another application or thread after our call to Directory.Exists. The
                    // choice of which exceptions to catch depends entirely on the specific task
                    // you are intending to perform and also on how much you know with certainty
                    // about the systems on which this code will run.
                    catch (UnauthorizedAccessException)
                    {
                        OnFileAccessed(new DirectoryWalkEventArgs(currentDir,
                                                                  String.Empty,
                                                                  DirectoryWalkObjectType.Directory,
                                                                  DirectoryWalkOperationResult.Failure,
                                                                  "Directory listing (subdirectories) could not be taken - insufficient permissions."));
                        continue;
                    }
                    catch (System.IO.DirectoryNotFoundException)
                    {
                        OnFileAccessed(new DirectoryWalkEventArgs(currentDir,
                                                                  String.Empty,
                                                                  DirectoryWalkObjectType.Directory,
                                                                  DirectoryWalkOperationResult.Error,
                                                                  "Directory listing (subdirectories) could not be taken - directory was deleted or moved."));
                        continue;
                    }

                    string[] files = null;
                    try
                    {
                        files = System.IO.Directory.GetFiles(currentDir);
                        OnFileAccessed(new DirectoryWalkEventArgs(currentDir,
                                                                  String.Empty,
                                                                  DirectoryWalkObjectType.Directory,
                                                                  DirectoryWalkOperationResult.Success,
                                                                  "Directory listing (files) taken successfully."));
                    }

                    catch (UnauthorizedAccessException)
                    {
                        OnFileAccessed(new DirectoryWalkEventArgs(currentDir,
                                                                  String.Empty,
                                                                  DirectoryWalkObjectType.Directory,
                                                                  DirectoryWalkOperationResult.Failure,
                                                                  "Directory listing (files) could not be taken - insufficient permissions."));
                        continue;
                    }

                    catch (System.IO.DirectoryNotFoundException)
                    {
                        OnFileAccessed(new DirectoryWalkEventArgs(currentDir,
                                                                  String.Empty,
                                                                  DirectoryWalkObjectType.Directory,
                                                                  DirectoryWalkOperationResult.Error,
                                                                  "Directory listing (files) could not be taken - directory was deleted or moved."));
                        continue;
                    }
                    // Perform the required action on each file here.
                    // Modify this block to perform your required task.
                    foreach (string file in files)
                    {
                        try
                        {
                            OnFileAccessed(new DirectoryWalkEventArgs(currentDir,
                                                                      Path.GetFileName(file),
                                                                      DirectoryWalkObjectType.File,
                                                                      DirectoryWalkOperationResult.NotApplicable,
                                                                      "Accessing file."));
                            System.IO.FileInfo fi = new System.IO.FileInfo(file);
                            fileProcessorInterface.ProcessFile(fi);
                            OnFileProcessed(new DirectoryWalkEventArgs(currentDir,
                                                                       Path.GetFileName(file),
                                                                       DirectoryWalkObjectType.File,
                                                                       DirectoryWalkOperationResult.Success,
                                                                       "File processed."));
                        }
                        catch (System.IO.FileNotFoundException)
                        {
                            // If file was deleted by a separate application
                            //  or thread since the call to TraverseTree()
                            // then just continue.
                            OnFileAccessed(new DirectoryWalkEventArgs(currentDir,
                                                                      String.Empty,
                                                                      DirectoryWalkObjectType.Directory,
                                                                      DirectoryWalkOperationResult.Error,
                                                                      "File could not be processed - it was deleted or moved."));
                            continue;
                        }
                    }

                    // Push the subdirectories onto the stack for traversal.
                    // This could also be done before handing the files.
                    foreach (string str in subDirs)
                    {
                        dirs.Push(str);
                    }
                }
                OnDirectoryWalkCompleted(new DirectoryWalkEventArgs(rootFolder,
                                                                    String.Empty,
                                                                    DirectoryWalkObjectType.Directory,
                                                                    DirectoryWalkOperationResult.NotApplicable,
                                                                    "Directory walk completed - computing hashes for length duplicates..."));
                Collection <ProcessedFileInfo> duplicateFiles = lengthFirstFileProc.DuplicateFiles;
                fileProcessorInterface.Close();
                return(duplicateFiles);
            }
            else
            {
                // Root folder does not exist
                throw new ArgumentException(String.Empty, "rootFolder");
            }
        } //BreadthFirstTraversal