public ArchiveValidationReport VerifyArchiveHashes(IProgress <ArchiveValidationReport> progress)
        {
            var stopWatch = new Stopwatch();

            stopWatch.Start();
            var progressReport = new ArchiveValidationReport()
            {
                TotalElapsedTime = stopWatch.Elapsed, Successful = true
            };

            var filesToCheck = Directory.EnumerateFiles(Destination, "[arc]*.*", SearchOption.AllDirectories);

            progressReport.TotalFilesToProcess = filesToCheck.Count();

            foreach (var fn in filesToCheck)
            {
                if (stopWatch.Elapsed - progressReport.TotalElapsedTime > TimeSpan.FromMilliseconds(1000))
                {
                    // send progress notification
                    progressReport.TotalElapsedTime = stopWatch.Elapsed;
                    progress.Report(progressReport);
                }

                var hashOnfileName = Path.GetFileName(fn).Substring("[arc]".Length, 44);
                var calculatedHash = FileProcessor.MakeFileNameSafeHash(FileProcessor.CalculateHash(fn));
                if (calculatedHash != hashOnfileName)
                {
                    progressReport.Successful = false;
                    Logger.Log($"[Critical Event][Hashes do NOT match!] [{fn}][fHash: {hashOnfileName}][calcHash: {calculatedHash}]");
                    //Console.WriteLine($"[Critical Event][Hashes do NOT match!] [{fn}][fHash: {hashOnfileName}][calcHash: {calculatedHash}]");
                }
                progressReport.TotalProcessedFiles++;
            }

            stopWatch.Stop();
            progressReport.TotalElapsedTime = stopWatch.Elapsed;
            return(progressReport);
        }
        public ArchiveProgressReport Archive(IProgress <ArchiveProgressReport> progress, ArchiveOptionsEnum options = ArchiveOptionsEnum.SimulateOnly)
        {
            var stopWatch = new Stopwatch();

            stopWatch.Start();
            var progressReport = new ArchiveProgressReport()
            {
                TotalElapsedTime = stopWatch.Elapsed
            };

            var ptCultureInfo = System.Globalization.CultureInfo.CreateSpecificCulture("pt-PT");

            var validExtensions = new List <string>();

            validExtensions.AddRange(ValidImageExtensions);
            validExtensions.AddRange(ValidVideoExtensions);

            progressReport.TotalFilesInSource = Directory.EnumerateFiles(Source, "*.*", SearchOption.AllDirectories)
                                                .Count(fn => !Path.GetFileName(fn).StartsWith(".", StringComparison.InvariantCultureIgnoreCase));
            progressReport.TotalFilesToProcess = FileProcessor.EnumerateSpecificFiles(Source, validExtensions, SearchOption.AllDirectories).Count();

            var sourceFiles = FileProcessor.EnumerateSpecificFiles(Source, validExtensions, SearchOption.AllDirectories);

            foreach (var srcFile in sourceFiles)
            {
                if (stopWatch.Elapsed - progressReport.TotalElapsedTime > TimeSpan.FromMilliseconds(1000))
                {
                    // send progress notification
                    progressReport.TotalElapsedTime = stopWatch.Elapsed;
                    progress.Report(progressReport);
                }

                var fInfo           = new FileInfo(srcFile);
                var srcHash         = FileProcessor.CalculateHash(srcFile);
                var srcHashFileSafe = FileProcessor.MakeFileNameSafeHash(srcHash);

                var fileExtension = Path.GetExtension(srcFile).ToLowerInvariant();


                var estimatedFileDate = fInfo.CreationTime.Year <= 1970 ? fInfo.LastWriteTime : fInfo.CreationTime;

                if (estimatedFileDate.Year <= 1980 || (estimatedFileDate > DateTime.Now.AddDays(1)))
                {
                    var ddd = fInfo.LastWriteTime;
                    var zzz = ddd;
                }

                //if (fInfo.CreationTime.Year <= 1980)
                //{
                //    var xx = "";
                //}

                if (ValidImageExtensions.Any(ext => ext.Equals(fileExtension, StringComparison.InvariantCultureIgnoreCase)))
                {
                    var dt = GetBestDateForImage(srcFile);
                    if (dt.HasValue)
                    {
                        estimatedFileDate = dt.Value;
                    }
                }


                var destFile = FindFileInDestination(srcHashFileSafe);
                //if (destFile != null && srcHash != FileProcessor.CalculateHash(destFile.FullName))
                //{
                //    Console.WriteLine($"[Critical Event] [{srcFile}][{srcHash}][{destFile.FullName}] Hashes(filename) match but Hashes(real non file-name-safe) do NOT match!");
                //}

                if (destFile != null)
                {
                    progressReport.SignalFileExcludedDuplicate(fInfo.Length);
                }
                else
                {
                    var isImage = ValidImageExtensions.Contains(fileExtension);
                    var isVideo = ValidVideoExtensions.Contains(fileExtension);

                    var destFolder = $"{Destination}";
                    if (options.HasFlag(ArchiveOptionsEnum.UseInboxFolder))
                    {
                        destFolder = Path.Combine(destFolder, "inbox");
                    }
                    if (options.HasFlag(ArchiveOptionsEnum.KeepSourceStructure))
                    {
                        destFolder = Path.Combine(destFolder, Path.GetDirectoryName(Path.GetRelativePath(Source, srcFile)));
                    }
                    else
                    {
                        var mediaType = isImage ? "fotos" : (isVideo ? "videos" : "misc");
                        destFolder = Path.Combine(destFolder, mediaType, estimatedFileDate.Year.ToString(), ptCultureInfo.DateTimeFormat.GetMonthName(estimatedFileDate.Month));
                        //destFolder = $"/{mediaType}/{estimatedFileDate.Year}/{estimatedFileDate.Month.ToString().PadLeft(2, '0')}";
                    }


                    var destfFilename = $"[arc]{srcHashFileSafe}-{fInfo.Name}";

                    if (!options.HasFlag(ArchiveOptionsEnum.SimulateOnly))
                    {
                        if (!Directory.Exists(destFolder))
                        {
                            Directory.CreateDirectory(destFolder);
                        }
                        File.Copy(srcFile, Path.Combine(destFolder, destfFilename), overwrite: false);
                    }

                    if (isImage)
                    {
                        progressReport.SignalImageFileAdded(fInfo.Length);
                    }
                    else if (isVideo)
                    {
                        progressReport.SignalVideoFileAdded(fInfo.Length);
                    }
                    else
                    {
                        progressReport.SignalOtherFileAdded(fInfo.Length);
                    }
                }
            }

            stopWatch.Stop();
            progressReport.TotalElapsedTime = stopWatch.Elapsed;
            return(progressReport);
        }