/// <summary>
        /// Rename all rushes in the path to standard form.
        /// </summary>
        /// <param name="directoryPath"></param>
        /// <param name="startingIndex">The first index</param>
        /// <returns></returns>
        public IEnumerable <IRenameResult> RenameFiles(string directoryPath, long startingIndex, out long lastIndex)
        {
            this.Logger.LogInformation($"Renaming files in directory '{directoryPath}'");
            using (this.Logger.BeginScope(null))
            {
                var retval        = new List <IRenameResult>();
                var directoryInfo = new DirectoryInfo(directoryPath);
                if (!directoryInfo.Exists)
                {
                    throw new ArgumentException($"No directory found at path '{directoryPath}'.");
                }

                /* #region Walk through all the video files in the root of the directory (ordered by name) */
                var files = directoryInfo.GetFiles().OrderBy(p => p.Name).ToArray();
                lastIndex = startingIndex + files.Length;

                for (int i = 0; i < files.Length; i++)
                {
                    var file = files[i];
                    if (!VideoFileHelpers.IsVideoFile(file))
                    {
                        continue;
                    }
                    var newId = startingIndex + i;

                    var convention  = this.FileNamingConventionFactory.GetConvention();
                    var newFileName = this.FileNameProvider.GetFileName(file.FullName, convention, newId);

                    var newFilePath = Path.Combine(directoryInfo.FullName, newFileName);
                    var newFileInfo = new FileInfo(newFilePath);
                    if (newFileInfo.Exists)
                    {
                        throw new Exception($"File already found at path '{newFilePath}'.");
                    }
                    var result = new RenameResult()
                    {
                        OldFilePath = file.FullName,
                        NewFilePath = newFilePath
                    };
                    retval.Add(result);
                    this.Logger.LogInformation($"Renaming '{file.Name}' to '{newFileName}'.");
                    if (!this.Settings.Debug)
                    {
                        File.Move(file.FullName, newFilePath);
                    }
                }
                /* #endregion*/



                /* #region Log the moves. */
                var logFilePath = Path.Combine(directoryInfo.FullName, directoryInfo.Name + "." + DefaultLogFileName);
                this.LogFileWriter.WriteLogFile(retval, logFilePath);
                /* #endregion*/


                return(retval);
            }
        }
        public void OrganizeFolder(string tapeFolderPath)
        {
            List <RenameResult> renameResults = new List <RenameResult>();

            this.Logger.LogDebug($"Organizing folder '{tapeFolderPath}'.");
            var directoryInfo = new DirectoryInfo(tapeFolderPath);

            if (!directoryInfo.Exists)
            {
                throw new Exception($"Cannot organise folder '{tapeFolderPath}'. Folder does not exist.");
            }

            /* #region Get all video files, not direct children of the tape folder */
            var allFiles = directoryInfo.GetFilesAndDirectories(p =>
            {
                if (!(p is FileInfo))
                {
                    return(false);
                }
                var fi = p as FileInfo;
                if (string.Equals(fi.Directory.FullName, directoryInfo.FullName, StringComparison.OrdinalIgnoreCase))
                {
                    return(false);
                }
                return(VideoFileHelpers.IsVideoFile(fi));
            }, recursive: true).Cast <FileInfo>().ToArray();

            /* #endregion*/

            /* #region Check if we've got anything to do. If not, exit. */
            if (!allFiles.Any())
            {
                Logger.LogInformation("No files need organising.");
                return;
            }
            /* #endregion*/


            /* #region Check for any issues with the copy. */
            List <string> issues = new List <string>();

            foreach (var file in allFiles)
            {
                var newFilePath = Path.Combine(directoryInfo.FullName, file.Name);
                var newFileInfo = new FileInfo(newFilePath);
                if (newFileInfo.Exists)
                {
                    issues.Add($"Organize would result in duplicate files called@ '{file.Name}'.");
                }
            }
            /* #endregion*/



            /* #region If there are any issues, then abort the copy. */
            if (issues.Any())
            {
                var issueText = "Unable to organize folder." + Environment.NewLine;
                issueText += string.Join(Environment.NewLine, issues.Select(p => "- " + p + Environment.NewLine));
                throw new Exception(issueText);
            }
            /* #endregion*/

            /* #region Move all the video files to the tape folder root  */
            foreach (var file in allFiles)
            {
                var newFilePath = Path.Combine(directoryInfo.FullName, file.Name);
                var newFileInfo = new FileInfo(newFilePath);

                this.Logger.LogInformation($"Moving file '{file.Name}' to '{newFileInfo.Directory.FullName}'.");
                renameResults.Add(new RenameResult()
                {
                    OldFilePath = file.FullName,
                    NewFilePath = newFileInfo.FullName
                });

                if (!this.Settings.Debug)
                {
                    file.MoveTo(newFileInfo.FullName);
                }
                else
                {
                    this.Logger.LogDebug($"Skipping file move in debug mode.");
                }
            }
            /* #endregion*/


            /* #region Log the moves */
            var logFilePath = Path.Combine(directoryInfo.FullName, directoryInfo.Name + "." + DefaultLogFileName);

            this.LogWriter.WriteLogFile(renameResults, logFilePath);
            /* #endregion*/
        }
        /* #endregion Public Constructors */
        /* #region Interface: 'Maptz.Avid.Rushes.IRushesReflectionService' Methods */

        /// <summary>
        /// Get flattened directory summaries.
        /// </summary>
        /// <param name="rootDirectoryPath"></param>
        /// <returns></returns>
        public IEnumerable <IDirectorySummary <IConventionFileInfo> > GetDirectorySummary(string rootDirectoryPath, bool recursive = true)
        {
            var rootDirectoryInfo = new DirectoryInfo(rootDirectoryPath);
            //Get All the video files,
            var allFiles = rootDirectoryInfo.GetFilesAndDirectories(p => p is FileInfo && VideoFileHelpers.IsVideoFile(p as FileInfo), recursive: recursive).OfType <FileInfo>();

            //Get all the files as serializable files.
            var serializableFiles = allFiles.Select(p => new SerializableFileInfo(p as FileInfo));

            //Group by directory name.
            var distinctDirectories = serializableFiles.GroupBy(p => Path.GetDirectoryName(p.FullName));
            //Create a new Directory Summary for each file.
            var summaries = distinctDirectories.Select(p =>
            {
                var files = p.Select(q => new ConventionFormFileInfo(q, this.FileNamingConvention)).Cast <IConventionFileInfo>().ToArray();


                return((IDirectorySummary <IConventionFileInfo>) new DirectorySummary <IConventionFileInfo>()
                {
                    DirectoryPath = p.Key,
                    FileCount = p.Count(),
                    CreatedDate = p.Max(q => q.LastWriteTimeUtc).ToString("yyyyMMdd"),
                    FileTypes = p.Select(q => Path.GetExtension(q.FullName).Trim('.')).ToArray(),
                    Files = files
                });
            });

            return(summaries.ToArray());
        }