using Microsoft.Extensions.Configuration; using Phares.Shared; using Serilog; using ShellProgressBar; using View_by_Distance.Copy.Distinct.Models; using View_by_Distance.Shared.Models; using View_by_Distance.Shared.Models.Methods; namespace View_by_Distance.Copy.Distinct; public class CopyDistinct { private readonly AppSettings _AppSettings; private readonly string _WorkingDirectory; private readonly Configuration _Configuration; private readonly IsEnvironment _IsEnvironment; private readonly IConfigurationRoot _ConfigurationRoot; private readonly IReadOnlyDictionary _FileGroups; private readonly Property.Models.Configuration _PropertyConfiguration; public CopyDistinct(List args, IsEnvironment isEnvironment, IConfigurationRoot configurationRoot, AppSettings appSettings, string workingDirectory, bool isSilent, IConsole console) { if (isSilent) { } if (console is null) { } _AppSettings = appSettings; _IsEnvironment = isEnvironment; _WorkingDirectory = workingDirectory; _ConfigurationRoot = configurationRoot; ILogger? log = Log.ForContext(); Property.Models.Configuration propertyConfiguration = Property.Models.Binder.Configuration.Get(isEnvironment, configurationRoot); Configuration configuration = Models.Binder.Configuration.Get(isEnvironment, configurationRoot, propertyConfiguration); _PropertyConfiguration = propertyConfiguration; _Configuration = configuration; propertyConfiguration.Update(); log.Information(propertyConfiguration.RootDirectory); (bool move, List allFiles, bool anyLenFiles, bool moveBack) = Verify(); _FileGroups = Shared.Models.Stateless.Methods.IPath.GetKeyValuePairs(propertyConfiguration, appSettings.CopyTo, new string[] { appSettings.ResultDirectoryKey }); List lines = CopyDistinctFilesInDirectories(log, move, allFiles, anyLenFiles, moveBack); if (lines.Any()) File.WriteAllLines($"D:/Tmp/Phares/{DateTime.Now.Ticks}.tsv", lines); _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(propertyConfiguration.RootDirectory); } private (bool, List, bool, bool) Verify() { if (_AppSettings is null) throw new NullReferenceException(nameof(_AppSettings)); if (_IsEnvironment is null) throw new NullReferenceException(nameof(_IsEnvironment)); if (_Configuration is null) throw new NullReferenceException(nameof(_Configuration)); if (_ConfigurationRoot is null) throw new NullReferenceException(nameof(_ConfigurationRoot)); if (_WorkingDirectory is null) throw new NullReferenceException(nameof(_WorkingDirectory)); if (_PropertyConfiguration is null) throw new NullReferenceException(nameof(_PropertyConfiguration)); bool moveBack; const string fileSearchFilter = "*"; const string directorySearchFilter = "*"; string copyTo = Path.GetFullPath(_AppSettings.CopyTo); bool move = copyTo == _PropertyConfiguration.RootDirectory; List filesCollection = Shared.Models.Stateless.Methods.IDirectory.GetFilesCollection(_PropertyConfiguration.RootDirectory, directorySearchFilter, fileSearchFilter); (_, List allFiles) = Get(filesCollection); bool anyLenFiles = allFiles.Any(l => l.EndsWith("len")); if (!move) moveBack = false; else { if (!anyLenFiles) throw new NotSupportedException("Use Mirror-Length app first!"); if (string.IsNullOrEmpty(_AppSettings.ResultDirectoryKey)) throw new NotSupportedException("Change appsettings!"); if (!Directory.Exists(Path.Combine(_PropertyConfiguration.RootDirectory, _AppSettings.ResultDirectoryKey))) moveBack = false; else { move = false; moveBack = true; } } return (move, allFiles, anyLenFiles, moveBack); } private static (List, List) Get(List filesCollection) { List results = new(); string? directory; List directories = new(); foreach (string[] files in filesCollection) { if (!files.Any()) continue; directory = Path.GetDirectoryName(files.First()); if (directory is null) continue; if (!directories.Contains(directory)) directories.Add(directory); results.AddRange(files); } return (directories, results); } private List<(FileHolder, string, string)> GetToDoCollection(ProgressBar progressBar, FileHolder[] fileHolders) { List<(FileHolder, string, string)> results = new(); string checkFile; string directory; FileInfo fileInfo; int directoryIndex; string directoryName; bool wrapped = false; List distinct = new(); FileHolder[] sortedFileHolders = (from l in fileHolders orderby l.LastWriteTime, l.FullName.Length descending select l).ToArray(); string key = string.IsNullOrEmpty(_AppSettings.ResultDirectoryKey) ? _PropertyConfiguration.ResultAllInOne : _AppSettings.ResultDirectoryKey; foreach (FileHolder fileHolder in sortedFileHolders) { progressBar.Tick(); if (fileHolder.Name.EndsWith("len") || fileHolder.ExtensionLowered == ".id" || fileHolder.ExtensionLowered == ".lsv" || fileHolder.DirectoryName is null) continue; (_, directoryIndex) = Shared.Models.Stateless.Methods.IPath.GetDirectoryNameAndIndex(_PropertyConfiguration.ResultAllInOneSubdirectoryLength, fileHolder.NameWithoutExtension); directoryName = Path.GetFileName(fileHolder.DirectoryName); if (directoryName.Length < _PropertyConfiguration.ResultAllInOneSubdirectoryLength + 3 || !fileHolder.Name.StartsWith(directoryName)) { if (wrapped) continue; directory = _FileGroups[key][directoryIndex]; } else { if (!wrapped) wrapped = true; directory = Path.Combine(_FileGroups[key][directoryIndex], directoryName); } checkFile = Path.Combine(directory, $"{fileHolder.NameWithoutExtension}{fileHolder.ExtensionLowered}"); if (distinct.Contains(checkFile)) { if (!_AppSettings.CopyDuplicates) continue; for (int i = 1; i < int.MaxValue; i++) { fileInfo = new(checkFile); if (!fileInfo.Exists || fileHolder.Length == fileInfo.Length && fileHolder.LastWriteTime == fileInfo.LastWriteTime) checkFile = Path.Combine(directory, $"{fileHolder.NameWithoutExtension}.{i}dup{fileHolder.ExtensionLowered}"); else checkFile = Path.Combine(directory, $"{fileHolder.NameWithoutExtension}.{i}why{fileHolder.ExtensionLowered}"); if (distinct.Contains(checkFile)) continue; distinct.Add(checkFile); results.Add(new(fileHolder, directory, checkFile)); break; } continue; } distinct.Add(checkFile); results.Add(new(fileHolder, directory, checkFile)); } return results; } private static List<(FileHolder, string, string)> GetMoveBackToDoCollection(List files) { List<(FileHolder, string, string)> results = new(); string key; string? value; string fileName; files.Reverse(); string? directory; string destinationFile; List distinctFound = new(); List distinctNeeded = new(); Dictionary nameToPath = new(); for (int i = 1; i < 3; i++) { foreach (string file in files) { fileName = Path.GetFileName(file); if (fileName.EndsWith("len")) { key = fileName[..^3]; destinationFile = file[..^3]; if (nameToPath.ContainsKey(key)) continue; nameToPath.Add(key, destinationFile); } else { if (!distinctNeeded.Contains(file)) distinctNeeded.Add(file); if (!nameToPath.ContainsKey(fileName)) continue; if (distinctFound.Contains(file)) continue; distinctFound.Add(file); } } if (distinctNeeded.Count != distinctFound.Count) continue; break; } foreach (string file in files) { // if (distinctNeeded.Count != distinctFound.Count) // continue; fileName = Path.GetFileName(file); if (fileName.EndsWith("len")) continue; if (!nameToPath.TryGetValue(fileName, out value)) continue; directory = Path.GetDirectoryName(value); if (string.IsNullOrEmpty(directory)) continue; results.Add(new(new(file), directory, value)); } return results; } private static List CopyOrMove(ProgressBar progressBar, List<(FileHolder, string, string)> toDoCollection, bool move, bool moveBack) { List results = new(); FileInfo fileInfo; foreach ((FileHolder fileHolder, string _, string to) in toDoCollection) { progressBar.Tick(); fileInfo = new(to); if (fileInfo.Exists) { if (fileHolder.Length != fileInfo.Length || fileHolder.LastWriteTime != fileInfo.LastWriteTime) fileInfo.Delete(); else continue; } results.Add(fileHolder.NameWithoutExtension); try { if (move || moveBack) File.Move(fileHolder.FullName, to); else File.Copy(fileHolder.FullName, to); } catch (Exception) { } } return results; } private List CopyDistinctFilesInDirectories(ILogger log, bool move, List allFiles, bool anyLenFiles, bool moveBack) { List results = new(); ProgressBar progressBar; ConsoleKey? consoleKey = null; string message = nameof(CopyDistinct); List distinctDirectories = new(); List<(FileHolder, string, string)> toDoCollection; ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; if (moveBack) { if (!anyLenFiles) throw new NotSupportedException(); toDoCollection = GetMoveBackToDoCollection(allFiles); } else { progressBar = new(allFiles.Count, message, options); FileHolder[] fileHolders = (from l in allFiles select new FileHolder(l)).ToArray(); toDoCollection = GetToDoCollection(progressBar, fileHolders); progressBar.Dispose(); } foreach ((FileHolder fileHolder, string directory, string to) in toDoCollection) { if (distinctDirectories.Contains(directory)) continue; distinctDirectories.Add(directory); } foreach (string distinctDirectory in distinctDirectories) { if (!Directory.Exists(distinctDirectory)) _ = Directory.CreateDirectory(distinctDirectory); } if (move) log.Information($"Ready to Move {toDoCollection.Count} file(s)?"); else if (!moveBack) log.Information($"Ready to Copy {toDoCollection.Count} file(s)?"); else log.Information($"Ready to Move back {toDoCollection.Count} file(s)?"); for (int y = 0; y < int.MaxValue; y++) { if (move) log.Information("Press \"Y\" key to move file(s), \"N\" key to log file(s) or close console to not move files"); else if (!moveBack) log.Information("Press \"Y\" key to copy file(s), \"N\" key to log file(s) or close console to not copy files"); else log.Information("Press \"Y\" key to move back file(s), \"N\" key to log file(s) or close console to not move back files"); consoleKey = System.Console.ReadKey().Key; if (consoleKey is ConsoleKey.Y or ConsoleKey.N) break; } log.Information(". . ."); if (consoleKey is null || consoleKey.Value != ConsoleKey.Y) { if (move || moveBack) log.Information("Nothing moved!"); else log.Information("Nothing copied!"); } else { progressBar = new(allFiles.Count, message, options); results.AddRange(CopyOrMove(progressBar, toDoCollection, move, moveBack)); progressBar.Dispose(); if (move || moveBack) log.Information("Done moving"); else log.Information("Done copying"); } return results; } }