using Microsoft.Extensions.Configuration; using Phares.Shared; using System.Globalization; using System.Text.Json; using View_by_Distance.Compare.Models; using View_by_Distance.Property.Models; using View_by_Distance.Shared.Models.Methods; using WindowsShortcutFactory; namespace View_by_Distance.Compare; public class Compare { private readonly Serilog.ILogger? _Log; private readonly AppSettings _AppSettings; private readonly List _Exceptions; private readonly string[] _VerifyToSeason; private readonly IsEnvironment _IsEnvironment; private readonly Models.Configuration _Configuration; private readonly List> _FileKeyValuePairs; private readonly List<(string Find, string Replace)> _RenameFindReplace; private readonly List<(string Find, string Replace)> _RenameBFindReplace; private readonly List<(string Find, string Replace)> _RenameCFindReplace; private readonly List<(string Find, string Replace)> _SpellingFindReplace; private readonly Dictionary>> _FilePropertiesKeyValuePairs; public Compare(List args, IsEnvironment isEnvironment, IConfigurationRoot configurationRoot, AppSettings appSettings, string workingDirectory, bool isSilent, IConsole console) { if (isSilent) { } if (console is null) { } string renameFrom; string renameTo; string[] segments; _AppSettings = appSettings; if (appSettings.MaxDegreeOfParallelism is null) throw new Exception($"{nameof(appSettings.MaxDegreeOfParallelism)} is null!"); _RenameFindReplace = new(); _RenameBFindReplace = new(); _RenameCFindReplace = new(); _SpellingFindReplace = new(); _IsEnvironment = isEnvironment; _Exceptions = new List(); _Log = Serilog.Log.ForContext(); _FileKeyValuePairs = new List>(); _FilePropertiesKeyValuePairs = new Dictionary>>(); string message; string searchPattern = "*"; long ticks = DateTime.Now.Ticks; List topDirectories = new(); Property.Models.Configuration propertyConfiguration = Property.Models.Stateless.Configuration.Get(isEnvironment, configurationRoot, workingDirectory); Property.Models.Configuration.Verify(propertyConfiguration); Models.Configuration configuration = Models.Stateless.Configuration.Get(isEnvironment, configurationRoot, workingDirectory, propertyConfiguration); Verify(configuration); if (propertyConfiguration.MaxImagesInDirectoryForTopLevelFirstPass is null) throw new Exception($"{nameof(propertyConfiguration.MaxImagesInDirectoryForTopLevelFirstPass)} is null!"); if (propertyConfiguration.PopulatePropertyId is null) throw new Exception($"{nameof(propertyConfiguration.PopulatePropertyId)} is null!"); foreach (string spelling in configuration.Spelling) { segments = spelling.Split('|'); if (segments.Length != 2) throw new Exception("Change configuration"); if (segments[1].Contains(segments[0])) throw new Exception($"Change configuration {segments[1]}.Contains({segments[0]})!"); _SpellingFindReplace.Add(new(segments[0], segments[1])); } foreach (string rename in configuration.Rename) { segments = rename.Split('|'); if (segments.Length is not 2 and not 4) throw new Exception("Change configuration"); renameFrom = Path.Combine(propertyConfiguration.RootDirectory, segments[0]); renameTo = Path.Combine(propertyConfiguration.RootDirectory, segments[1]); if (renameTo.Contains(renameFrom)) throw new Exception($"Change configuration {renameTo}.Contains({renameFrom})!"); _RenameFindReplace.Add(new(renameFrom, renameTo)); if (segments.Length == 4) { renameFrom = Path.Combine(propertyConfiguration.RootDirectory, segments[2]); renameTo = Path.Combine(propertyConfiguration.RootDirectory, segments[3]); if (renameTo.Contains(renameFrom)) throw new Exception($"Change configuration {renameTo}.Contains({renameFrom})!"); _RenameFindReplace.Add(new(renameFrom, renameTo)); } } foreach (string rename in configuration.RenameB) { segments = rename.Split('|'); if (segments.Length is not 2) throw new Exception("Change configuration"); renameFrom = Path.GetFullPath(string.Concat(propertyConfiguration.RootDirectory, segments[0])); renameTo = Path.GetFullPath(string.Concat(propertyConfiguration.RootDirectory, segments[1])); if (renameTo.Contains(renameFrom)) throw new Exception($"Change configuration {renameTo}.Contains({renameFrom})!"); _RenameBFindReplace.Add(new(renameFrom, renameTo)); } for (int i = 0; i < configuration.RenameC.Length; i++) { renameFrom = Path.GetFullPath(string.Concat(propertyConfiguration.RootDirectory, configuration.RenameC[i])); renameTo = Path.Combine(propertyConfiguration.RootDirectory, GetRename(configuration.RenameC[i])); if (renameTo.Contains(renameFrom)) throw new Exception("Change configuration!"); _RenameCFindReplace.Add(new(renameFrom, renameTo)); } List<(int g, string sourceDirectory, string[] sourceDirectoryFiles, int r)> groupCollection = Property.Models.Stateless.A_Property.GetGroupCollection(propertyConfiguration.RootDirectory, searchPattern, topDirectories, propertyConfiguration.MaxImagesInDirectoryForTopLevelFirstPass.Value, reverse: false); if (appSettings.MaxDegreeOfParallelism.Value < 2) ticks = LogDelta(ticks, nameof(Property.Models.Stateless.A_Property.GetGroupCollection)); _Log.Information($"{nameof(Property.Models.Stateless.A_Property.GetGroupCollection)} has finished"); _VerifyToSeason = propertyConfiguration.VerifyToSeason.Select(l => Path.Combine(propertyConfiguration.RootDirectory, l)).ToArray(); List missingVerifyToSeasonCollection = GetMissingVerifyToSeasonCollection(topDirectories, groupCollection); if (missingVerifyToSeasonCollection.Any()) throw new Exception($"Update configuration with the following {Environment.NewLine} {string.Join(Environment.NewLine, missingVerifyToSeasonCollection)}"); if (PossiblyRename(topDirectories, groupCollection)) { topDirectories.Clear(); _ = Property.Models.Stateless.IPath.DeleteEmptyDirectories(propertyConfiguration.RootDirectory); groupCollection = Property.Models.Stateless.A_Property.GetGroupCollection(propertyConfiguration.RootDirectory, searchPattern, topDirectories, propertyConfiguration.MaxImagesInDirectoryForTopLevelFirstPass.Value, reverse: false); if (appSettings.MaxDegreeOfParallelism.Value < 2) ticks = LogDelta(ticks, nameof(Property.Models.Stateless.A_Property.GetGroupCollection)); } _Log.Information($"{nameof(PossiblyRename)} has finished"); if (PossiblyRenameB(topDirectories, groupCollection)) { topDirectories.Clear(); _ = Property.Models.Stateless.IPath.DeleteEmptyDirectories(propertyConfiguration.RootDirectory); groupCollection = Property.Models.Stateless.A_Property.GetGroupCollection(propertyConfiguration.RootDirectory, searchPattern, topDirectories, propertyConfiguration.MaxImagesInDirectoryForTopLevelFirstPass.Value, reverse: false); if (appSettings.MaxDegreeOfParallelism.Value < 2) ticks = LogDelta(ticks, nameof(Property.Models.Stateless.A_Property.GetGroupCollection)); } _Log.Information($"{nameof(PossiblyRenameB)} has finished"); if (PossiblyRenameC(topDirectories, groupCollection)) { topDirectories.Clear(); _ = Property.Models.Stateless.IPath.DeleteEmptyDirectories(propertyConfiguration.RootDirectory); groupCollection = Property.Models.Stateless.A_Property.GetGroupCollection(propertyConfiguration.RootDirectory, searchPattern, topDirectories, propertyConfiguration.MaxImagesInDirectoryForTopLevelFirstPass.Value, reverse: false); if (appSettings.MaxDegreeOfParallelism.Value < 2) ticks = LogDelta(ticks, nameof(Property.Models.Stateless.A_Property.GetGroupCollection)); } _Log.Information($"{nameof(PossiblyRenameC)} has finished"); if (PossiblyCorrect(topDirectories, groupCollection)) { topDirectories.Clear(); _ = Property.Models.Stateless.IPath.DeleteEmptyDirectories(propertyConfiguration.RootDirectory); groupCollection = Property.Models.Stateless.A_Property.GetGroupCollection(propertyConfiguration.RootDirectory, searchPattern, topDirectories, propertyConfiguration.MaxImagesInDirectoryForTopLevelFirstPass.Value, reverse: false); if (appSettings.MaxDegreeOfParallelism.Value < 2) ticks = LogDelta(ticks, nameof(Property.Models.Stateless.A_Property.GetGroupCollection)); } _Log.Information($"{nameof(PossiblyCorrect)} has finished"); string[] dbFiles = Directory.GetFiles(propertyConfiguration.RootDirectory, "*.db", SearchOption.AllDirectories); foreach (string dbFile in dbFiles) File.Delete(dbFile); _Log.Information("deleting *.db files has finished"); if (dbFiles.Any()) { topDirectories.Clear(); _ = Property.Models.Stateless.IPath.DeleteEmptyDirectories(propertyConfiguration.RootDirectory); groupCollection = Property.Models.Stateless.A_Property.GetGroupCollection(propertyConfiguration.RootDirectory, searchPattern, topDirectories, propertyConfiguration.MaxImagesInDirectoryForTopLevelFirstPass.Value, reverse: false); if (appSettings.MaxDegreeOfParallelism.Value < 2) ticks = LogDelta(ticks, nameof(Property.Models.Stateless.A_Property.GetGroupCollection)); } PropertyLogic propertyLogic = GetPropertyLogic(); if (_IsEnvironment.Development && propertyConfiguration.PopulatePropertyId.Value && !propertyLogic.IndicesFromOld.Any()) throw new Exception("Copy keyValuePairs-####.json file"); _Exceptions.AddRange(propertyLogic.DoWork(propertyConfiguration, topDirectories, groupCollection, firstPass: true)); message = $"There were {_Exceptions.Count} exception(s) thrown! {Environment.NewLine}{string.Join(Environment.NewLine, _Exceptions)}"; _Log.Information(message); if (_Exceptions.Count != 0) throw new Exception(message); if (appSettings.MaxDegreeOfParallelism.Value < 2) ticks = LogDelta(ticks, nameof(PropertyLogic.DoWork)); if (!isSilent) { _Log.Information("First pass completed"); for (int y = 0; y < int.MaxValue; y++) { _Log.Information("Press \"Y\" key to continue or close console if compare not needed"); if (Console.ReadKey().Key == ConsoleKey.Y) break; } _Log.Information(". . ."); } string aPropertySingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(propertyConfiguration, nameof(A_Property), "{}"); string aPropertyContentCollectionDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(propertyConfiguration, nameof(A_Property), "[()]"); if (!isSilent) { if (Directory.Exists(aPropertySingletonDirectory)) { ConsoleKey? consoleKey = null; for (int y = 0; y < int.MaxValue; y++) { _Log.Information($"Execute {nameof(ChangeExtensionFromDeleteToJson)} \"Y(es)\" or \"N(o)\"?"); consoleKey = Console.ReadKey().Key; if (consoleKey is ConsoleKey.Y or ConsoleKey.N) break; } _Log.Information(". . ."); if (consoleKey == ConsoleKey.Y) ChangeExtensionFromDeleteToJson(aPropertySingletonDirectory); for (int y = 0; y < int.MaxValue; y++) { _Log.Information($"Execute {nameof(Property.Models.Stateless.A_Property.SearchForAbandonedFilesFull)} \"Y(es)\" or \"N(o)\"?"); consoleKey = Console.ReadKey().Key; if (consoleKey is ConsoleKey.Y or ConsoleKey.N) break; } _Log.Information(". . ."); if (consoleKey == ConsoleKey.Y) { Property.Models.Stateless.A_Property.SearchForAbandonedFilesFull(propertyConfiguration.RootDirectory, aPropertySingletonDirectory, onlyJson: false); for (int y = 0; y < int.MaxValue; y++) { _Log.Information($"Execute {nameof(Property.Models.Stateless.IPath.DeleteEmptyDirectories)} \"Y(es)\" or \"N(o)\"?"); consoleKey = Console.ReadKey().Key; if (consoleKey is ConsoleKey.Y or ConsoleKey.N) break; } _Log.Information(". . ."); _ = Property.Models.Stateless.IPath.DeleteEmptyDirectories(propertyConfiguration.RootDirectory); _ = Property.Models.Stateless.IPath.DeleteEmptyDirectories(aPropertySingletonDirectory); } } } topDirectories.Clear(); groupCollection = Property.Models.Stateless.A_Property.GetGroupCollection(propertyConfiguration.RootDirectory, searchPattern, topDirectories, propertyConfiguration.MaxImagesInDirectoryForTopLevelFirstPass.Value, reverse: false); _Exceptions.AddRange(propertyLogic.DoWork(propertyConfiguration, topDirectories, groupCollection, firstPass: false)); message = $"There were {_Exceptions.Count} exception(s) thrown! {Environment.NewLine}{string.Join(Environment.NewLine, _Exceptions)}"; _Log.Information(message); if (_Exceptions.Count != 0) throw new Exception(message); if (!isSilent) { _Log.Information("Second pass completed"); for (int y = 0; y < int.MaxValue; y++) { _Log.Information("Press \"Y\" key to continue or close console if compare not needed"); if (Console.ReadKey().Key == ConsoleKey.Y) break; } _Log.Information(". . ."); } ThirdPassToMove(propertyLogic, propertyConfiguration, aPropertyContentCollectionDirectory, topDirectories, groupCollection); if (!isSilent) { _Log.Information("Third pass completed"); for (int y = 0; y < int.MaxValue; y++) { _Log.Information("Press \"Y\" key to continue or close console if compare not needed"); if (Console.ReadKey().Key == ConsoleKey.Y) break; } _Log.Information(". . ."); } FourthPassCreateWindowsShortcuts(propertyLogic, propertyConfiguration, topDirectories, groupCollection, saveToCollection: false, keepAll: false); if (!isSilent) { _Log.Information("Fourth pass completed"); for (int y = 0; y < int.MaxValue; y++) { _Log.Information("Press \"Y\" key to continue or close console if compare not needed"); if (Console.ReadKey().Key == ConsoleKey.Y) break; } _Log.Information(". . ."); } SaveDiffFilesOrSaveLogAndMoveFiles(propertyConfiguration); string currentYearDirectory = Path.Combine(propertyConfiguration.RootDirectory, $". {DateTime.Now:yyyy}"); if (!Directory.Exists(currentYearDirectory)) _ = Directory.CreateDirectory(currentYearDirectory); _Configuration = configuration; } private string GetRename(string renameA) { string result; int season; DateTime dateTime; string seasonName; string[] pathSegments; string[] directorySegments; string corrected = renameA[1..]; if ((from l in _SpellingFindReplace where corrected.Contains(l.Find) select true).Any()) { foreach ((string find, string replace) in _SpellingFindReplace) corrected = corrected.Replace(find, replace); } corrected = corrected.Replace("Back to the hospital", "September 2007").Replace("Birthday", "September 2007").Replace("Aug Sept 09", "Sept 09"); pathSegments = corrected.Split('/'); directorySegments = pathSegments[0].Split(' '); bool hasZzz = directorySegments.Contains("zzz"); if (hasZzz) { corrected = corrected.Replace("zzz ", string.Empty); pathSegments = corrected.Split('/'); directorySegments = pathSegments[0].Split(' '); } if (pathSegments[^1].Contains('-')) { directorySegments = pathSegments[^1].Split(' '); if (!DateTime.TryParseExact(string.Join(' ', directorySegments.Take(3)), "yyyy-MM-dd", CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime)) throw new Exception("l"); (season, seasonName) = Property.Models.Stateless.A_Property.GetSeason(dateTime.DayOfYear); result = string.Concat($"={dateTime:yyyy}.{season} {seasonName} ", string.Join(' ', pathSegments[0].Split(' ').Take(2))); } else if (pathSegments.Length == 1) { directorySegments = pathSegments[^1].Split(' '); if (DateTime.TryParseExact(directorySegments[^1], "yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime)) { (season, seasonName) = Property.Models.Stateless.A_Property.GetSeason(dateTime.DayOfYear); result = string.Concat($"={dateTime:yyyy}.{season} {seasonName} ", string.Join(' ', pathSegments[0].Split(' ').Take(2))); } else throw new Exception("1"); } else if (pathSegments.Length == 2) { directorySegments = pathSegments[^1].Split(' '); if (directorySegments.Length == 1) { directorySegments = pathSegments[0].Split(' '); if (DateTime.TryParseExact(directorySegments[^1], "yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime)) { (season, seasonName) = Property.Models.Stateless.A_Property.GetSeason(dateTime.DayOfYear); result = string.Concat($"={dateTime:yyyy}.{season} {seasonName} ", string.Join(' ', pathSegments[0].Split(' ').Take(2))); } else throw new Exception("2,1"); } else if (directorySegments.Length == 4) { directorySegments = pathSegments[0].Split(' '); if (DateTime.TryParseExact(directorySegments[^1], "yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime)) { (season, seasonName) = Property.Models.Stateless.A_Property.GetSeason(dateTime.DayOfYear); result = string.Concat($"={dateTime:yyyy}.{season} {seasonName} ", string.Join(' ', pathSegments[0].Split(' ').Take(2))); } else throw new Exception("2,4"); } else if (directorySegments.Length == 2) { if (DateTime.TryParseExact(string.Join(' ', directorySegments.Take(2)), "MMM yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime)) { (season, seasonName) = Property.Models.Stateless.A_Property.GetSeason(dateTime.DayOfYear); result = string.Concat($"={dateTime:yyyy}.{season} {seasonName} ", string.Join(' ', pathSegments[0].Split(' ').Take(2))); } else if (DateTime.TryParseExact(string.Join(' ', directorySegments.Take(2)), "MMM yy", CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime)) { (season, seasonName) = Property.Models.Stateless.A_Property.GetSeason(dateTime.DayOfYear); result = string.Concat($"={dateTime:yyyy}.{season} {seasonName} ", string.Join(' ', pathSegments[0].Split(' ').Take(2))); } else if (DateTime.TryParseExact(string.Concat(directorySegments[0][..3], ' ', directorySegments[1]), "MMM yy", CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime)) { (season, seasonName) = Property.Models.Stateless.A_Property.GetSeason(dateTime.DayOfYear); result = string.Concat($"={dateTime:yyyy}.{season} {seasonName} ", string.Join(' ', pathSegments[0].Split(' ').Take(2))); } else if (DateTime.TryParseExact(string.Join(' ', directorySegments.Take(2)), "MMMM yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime)) { (season, seasonName) = Property.Models.Stateless.A_Property.GetSeason(dateTime.DayOfYear); result = string.Concat($"={dateTime:yyyy}.{season} {seasonName} ", string.Join(' ', pathSegments[0].Split(' ').Take(2))); } else throw new Exception("2,2"); } else if (directorySegments.Length == 3) { if (DateTime.TryParseExact(string.Join(' ', directorySegments.Take(3)), "MMMM dd yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime)) { (season, seasonName) = Property.Models.Stateless.A_Property.GetSeason(dateTime.DayOfYear); result = string.Concat($"={dateTime:yyyy}.{season} {seasonName} ", string.Join(' ', pathSegments[0].Split(' ').Take(2))); } else if (DateTime.TryParseExact(string.Join(' ', directorySegments.Take(3)), "MMMM d yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime)) { (season, seasonName) = Property.Models.Stateless.A_Property.GetSeason(dateTime.DayOfYear); result = string.Concat($"={dateTime:yyyy}.{season} {seasonName} ", string.Join(' ', pathSegments[0].Split(' ').Take(2))); } else throw new Exception("2,3"); } else throw new Exception("2"); } else if (pathSegments.Length == 3) { directorySegments = pathSegments[^1].Split(' '); if (DateTime.TryParseExact(string.Join(' ', directorySegments.Take(3)), "MMMM dd yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime)) { (season, seasonName) = Property.Models.Stateless.A_Property.GetSeason(dateTime.DayOfYear); result = string.Concat($"={dateTime:yyyy}.{season} {seasonName} ", string.Join(' ', pathSegments[0].Split(' ').Take(2))); } else if (DateTime.TryParseExact(string.Join(' ', directorySegments.Take(3)), "MMMM d yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime)) { (season, seasonName) = Property.Models.Stateless.A_Property.GetSeason(dateTime.DayOfYear); result = string.Concat($"={dateTime:yyyy}.{season} {seasonName} ", string.Join(' ', pathSegments[0].Split(' ').Take(2))); } else throw new Exception("3"); } else throw new Exception("e"); if (hasZzz) result = string.Concat("zzz ", result); return result; } private static void Verify(Models.Configuration configuration) { if (configuration.Spelling is null || !configuration.Spelling.Any()) throw new Exception($"{nameof(configuration.Spelling)} should have at least one!"); } private long LogDelta(long ticks, string methodName) { long result; if (_Log is null) throw new Exception($"{nameof(_Log)} is null!"); double delta = new TimeSpan(DateTime.Now.Ticks - ticks).TotalMilliseconds; _Log.Debug($"{methodName} took {Math.Floor(delta)} millisecond(s)"); result = DateTime.Now.Ticks; return result; } private PropertyLogic GetPropertyLogic() { PropertyLogic result; if (_AppSettings.MaxDegreeOfParallelism is null) throw new Exception($"{nameof(_AppSettings.MaxDegreeOfParallelism)} is null!"); if (_Configuration?.PropertyConfiguration is null) throw new Exception($"{nameof(_Configuration.PropertyConfiguration)} must be set!"); result = new(_AppSettings.MaxDegreeOfParallelism.Value, _Configuration.PropertyConfiguration, _VerifyToSeason); string fromPerpareForOld = "34720-637858334555170379.tsv"; string fromPerpareForOldFile = Path.Combine(_Configuration.PropertyConfiguration.RootDirectory, fromPerpareForOld); if (File.Exists(fromPerpareForOldFile)) { string[] lines; string[] columns; List debug = new(); long ticks = DateTime.Now.Ticks; lines = File.ReadAllLines(fromPerpareForOldFile); string resultsDirectory = $"{_Configuration.PropertyConfiguration.RootDirectory} - Results"; int[]? zeros = (from l in result.IndicesFromNew where l.Value.Any() select l.Value[0]).ToArray(); lines = (from l in result.IndicesFromNew select string.Concat(l.Key, '\t', string.Join('\t', l.Value))).ToArray(); if (!Directory.Exists(resultsDirectory)) _ = Directory.CreateDirectory(resultsDirectory); File.WriteAllLines(Path.Combine(resultsDirectory, $"{ticks}.tsv"), lines); string json = JsonSerializer.Serialize(result.IndicesFromNew, new JsonSerializerOptions { WriteIndented = true }); File.WriteAllText(Path.Combine(resultsDirectory, $"{ticks}.json"), json); foreach (string line in lines) { columns = line.Split('\t'); // select $"{l.Index}\t{l.PropertyId}\t{l.RegexResult}\t{new DateTime(l.Ticks):yyyy-MM-dd_HH-mm-ss}\t{l.PropertyTicks}\t{l.RelativeDirectory}\t{l.FileName}" if (columns.Length != 7) continue; if (!int.TryParse(columns[1], out int propertyId)) continue; if (!zeros.Contains(propertyId)) debug.Add(line); else debug.Add(propertyId.ToString()); } File.WriteAllLines(Path.Combine(resultsDirectory, $"{ticks}-{fromPerpareForOld}"), debug); } return result; } private void SaveDiffFilesOrSaveLogAndMoveFiles(Property.Models.Configuration configuration) { if (_Log is null) throw new Exception($"{nameof(_Log)} is null!"); if (_AppSettings.MaxDegreeOfParallelism is null) throw new Exception($"{nameof(_AppSettings.MaxDegreeOfParallelism)} is null!"); if (_Configuration?.PropertyConfiguration is null) throw new Exception($"{nameof(_Configuration.PropertyConfiguration)} must be set!"); string aPropertySingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(A_Property), "{}"); _Log.Information(aPropertySingletonDirectory); _Log.Information("to"); _Log.Information(_Configuration.DiffPropertyDirectory); for (int y = 0; y < int.MaxValue; y++) { _Log.Information("Press \"Y\" key to continue or close console if compare not needed"); if (Console.ReadKey().Key == ConsoleKey.Y) break; } _Log.Information(". . ."); int loadLessThan = 7; string diffRootDirectory; ConsoleKey? consoleKey = null; List? duplicates = null; PropertyCompare.Models.PropertyCompare[] diffPropertyCompareCollection; if (string.IsNullOrEmpty(_Configuration.DiffPropertyDirectory)) diffRootDirectory = string.Empty; else { if (!_Configuration.DiffPropertyDirectory.EndsWith("{}")) throw new Exception("Invalid directory should end with {}!"); diffRootDirectory = Property.Models.Stateless.A_Property.GetDiffRootDirectory(_Configuration.DiffPropertyDirectory); } PropertyCompare.Models.PropertyCompareLogic propertyCompareLogic = new(_AppSettings.MaxDegreeOfParallelism.Value, _Configuration.PropertyConfiguration, _SpellingFindReplace, diffRootDirectory); if (string.IsNullOrEmpty(_Configuration.DiffPropertyDirectory) || !Directory.Exists(_Configuration.DiffPropertyDirectory)) diffPropertyCompareCollection = Array.Empty(); else { diffPropertyCompareCollection = propertyCompareLogic.Get(_Configuration.DiffPropertyDirectory, loadLessThan, duplicates, deleteExtension: false); if (!diffPropertyCompareCollection.Any()) throw new Exception("Invalid directory!"); } string aPropertyCollectionDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(configuration, nameof(A_Property), "[{}]"); PropertyCompare.Models.PropertyCompare[] propertyCompareCollection = propertyCompareLogic.Get(aPropertySingletonDirectory, loadLessThan, duplicates, deleteExtension: false); { long ticks = DateTime.Now.Ticks; string[] lines = (from l in propertyCompareCollection select l.GetSelect()).ToArray(); File.WriteAllLines(Path.Join(aPropertyCollectionDirectory, $". . . Ids - {ticks}.txt"), lines); string json = JsonSerializer.Serialize(propertyCompareCollection, new JsonSerializerOptions { WriteIndented = true }); File.WriteAllText(Path.Join(aPropertyCollectionDirectory, $". . . Ids - {ticks}.nosj"), json); } for (int x = 0; x < int.MaxValue; x++) { _Log.Information($"Press \"D\" key to {nameof(PropertyCompare.Models.PropertyCompareLogic.SaveDiffFiles)}"); _Log.Information($"Press \"M\" key to {nameof(PropertyCompare.Models.PropertyCompareLogic.SaveLogAndMoveFiles)}"); _Log.Information("Press \"End\" key when ready to skip"); consoleKey = Console.ReadKey().Key; if (consoleKey is ConsoleKey.D or ConsoleKey.M or ConsoleKey.End) break; } _Log.Information(". . ."); if (consoleKey.HasValue && consoleKey.Value == ConsoleKey.D) propertyCompareLogic.SaveDiffFiles(aPropertyCollectionDirectory, loadLessThan, propertyCompareCollection, diffPropertyCompareCollection); else if (consoleKey.HasValue && consoleKey.Value == ConsoleKey.M) { for (int x = 0; x < int.MaxValue; x++) { _Log.Information($"Press \"0 - {loadLessThan}\" key when ready to continue"); _Log.Information("Press \"End\" key when ready to skip"); consoleKey = Console.ReadKey().Key; if (consoleKey.Value is ConsoleKey.D0 or ConsoleKey.D1 or ConsoleKey.D2 or ConsoleKey.D3 or ConsoleKey.D4 or ConsoleKey.D5 or ConsoleKey.D6 or ConsoleKey.End) break; } _Log.Information(". . ."); int i = int.Parse(consoleKey.Value.ToString()[1..]); propertyCompareLogic.SaveLogAndMoveFiles(aPropertyCollectionDirectory, loadLessThan, propertyCompareCollection, diffPropertyCompareCollection, i); } } private void ChangeExtensionFromDeleteToJson(string aPropertySingletonDirectory) { if (_AppSettings.MaxDegreeOfParallelism is null) throw new Exception($"{nameof(_AppSettings.MaxDegreeOfParallelism)} is null!"); string searchPattern = "*.delete"; long ticks = DateTime.Now.Ticks; List topDirectories = new(); List<(int g, string sourceDirectory, string[] sourceDirectoryFiles, int r)> groupCollection = Property.Models.Stateless.A_Property.GetGroupCollection(aPropertySingletonDirectory, searchPattern, topDirectories); if (_AppSettings.MaxDegreeOfParallelism.Value < 2) ticks = LogDelta(ticks, nameof(Property.Models.Stateless.A_Property.GetGroupCollection)); foreach ((int g, string sourceDirectory, string[] sourceDirectoryFiles, int r) in groupCollection) { if (!topDirectories.Any()) continue; foreach (string sourceDirectoryFile in sourceDirectoryFiles) File.Move(sourceDirectoryFile, Path.ChangeExtension(sourceDirectoryFile, ".json")); } } private bool PossiblyRename(List topDirectories, List<(int g, string sourceDirectory, string[] sourceDirectoryFiles, int r)> groupCollection) { bool result = false; string replaceFile; string replaceDirectory; int remainingDirectories = 0; IEnumerable<(string Find, string Replace)>? found; foreach ((int g, string sourceDirectory, string[] sourceDirectoryFiles, int r) in groupCollection) { if (!topDirectories.Any()) continue; found = from l in _RenameFindReplace where sourceDirectory == l.Find select l; if (!found.Any()) continue; if (!result) result = true; replaceDirectory = found.First().Replace; if (!Directory.Exists(replaceDirectory)) Directory.Move(sourceDirectory, replaceDirectory); else { if (Directory.EnumerateDirectories(sourceDirectory).Any()) remainingDirectories += 1; else { foreach (string sourceDirectoryFile in sourceDirectoryFiles) { replaceFile = Path.Combine(replaceDirectory, Path.GetFileName(sourceDirectoryFile)); if (File.Exists(replaceFile)) { if (replaceFile.EndsWith(".jpg", ignoreCase: true, CultureInfo.CurrentCulture)) replaceFile = Path.Combine(replaceDirectory, Path.ChangeExtension(sourceDirectoryFile, ".jpeg")); else if (replaceFile.EndsWith(".jpeg", ignoreCase: true, CultureInfo.CurrentCulture)) replaceFile = Path.Combine(replaceDirectory, Path.ChangeExtension(sourceDirectoryFile, ".jpg")); } if (File.Exists(replaceFile)) continue; File.Move(sourceDirectoryFile, replaceFile); } } } } return result; } private bool PossiblyRenameB(List topDirectories, List<(int g, string sourceDirectory, string[] sourceDirectoryFiles, int r)> groupCollection) { bool result = false; string replaceFile; string replaceDirectory; IEnumerable<(string Find, string Replace)>? found; foreach ((int g, string sourceDirectory, string[] sourceDirectoryFiles, int r) in groupCollection) { if (!topDirectories.Any()) continue; found = from l in _RenameBFindReplace where sourceDirectory == l.Find select l; if (!found.Any()) continue; if (!result) result = true; replaceDirectory = found.First().Replace; if (!Directory.Exists(replaceDirectory)) _ = Directory.CreateDirectory(replaceDirectory); foreach (string sourceDirectoryFile in sourceDirectoryFiles) { replaceFile = Path.Combine(replaceDirectory, Path.GetFileName(sourceDirectoryFile)); if (File.Exists(replaceFile)) { if (replaceFile.EndsWith(".jpg", ignoreCase: true, CultureInfo.CurrentCulture)) replaceFile = Path.Combine(replaceDirectory, Path.ChangeExtension(sourceDirectoryFile, ".jpeg")); else if (replaceFile.EndsWith(".jpeg", ignoreCase: true, CultureInfo.CurrentCulture)) replaceFile = Path.Combine(replaceDirectory, Path.ChangeExtension(sourceDirectoryFile, ".jpg")); } if (File.Exists(replaceFile)) continue; File.Move(sourceDirectoryFile, replaceFile); } } return result; } private bool PossiblyRenameC(List topDirectories, List<(int g, string sourceDirectory, string[] sourceDirectoryFiles, int r)> groupCollection) { bool result = false; string replaceFile; string replaceDirectory; IEnumerable<(string Find, string Replace)>? found; foreach ((int g, string sourceDirectory, string[] sourceDirectoryFiles, int r) in groupCollection) { if (!topDirectories.Any()) continue; found = from l in _RenameCFindReplace where sourceDirectory == l.Find select l; if (!found.Any()) continue; if (!result) result = true; replaceDirectory = found.First().Replace; if (!Directory.Exists(replaceDirectory)) _ = Directory.CreateDirectory(replaceDirectory); foreach (string sourceDirectoryFile in sourceDirectoryFiles) { replaceFile = Path.Combine(replaceDirectory, Path.GetFileName(sourceDirectoryFile)); if (File.Exists(replaceFile)) { if (replaceFile.EndsWith(".jpg", ignoreCase: true, CultureInfo.CurrentCulture)) replaceFile = Path.Combine(replaceDirectory, Path.ChangeExtension(sourceDirectoryFile, ".jpeg")); else if (replaceFile.EndsWith(".jpeg", ignoreCase: true, CultureInfo.CurrentCulture)) replaceFile = Path.Combine(replaceDirectory, Path.ChangeExtension(sourceDirectoryFile, ".jpg")); } if (File.Exists(replaceFile)) continue; File.Move(sourceDirectoryFile, replaceFile); } } return result; } private bool PossiblyCorrect(List topDirectories, List<(int g, string sourceDirectory, string[] sourceDirectoryFiles, int r)> groupCollection) { if (_Configuration?.PropertyConfiguration is null) throw new Exception($"{nameof(_Configuration.PropertyConfiguration)} must be set!"); bool result = false; string corrected; string correctedMoveTo; string? correctedDirectory; string filteredSourceDirectoryFile; string[] filteredSourceDirectoryFiles; (string Find, string Replace) findReplace; IEnumerable<(string Find, string Replace)>? found; foreach ((int g, string sourceDirectory, string[] sourceDirectoryFiles, int r) in groupCollection) { if (!topDirectories.Any()) continue; filteredSourceDirectoryFiles = (from l in sourceDirectoryFiles where !_Configuration.PropertyConfiguration.IgnoreExtensions.Contains(Path.GetExtension(l)) select l).ToArray(); if (!filteredSourceDirectoryFiles.Any()) continue; for (int i = 0; i < filteredSourceDirectoryFiles.Length; i++) { found = null; for (int z = 0; z < int.MaxValue; z++) { filteredSourceDirectoryFile = filteredSourceDirectoryFiles[i]; found = from l in _SpellingFindReplace where filteredSourceDirectoryFile.Contains(l.Find) select l; if (!found.Any()) break; findReplace = found.First(); corrected = filteredSourceDirectoryFile.Replace(findReplace.Find, findReplace.Replace); correctedDirectory = Path.GetDirectoryName(corrected); if (string.IsNullOrEmpty(correctedDirectory)) break; correctedMoveTo = Path.Combine(correctedDirectory, Path.GetFileName(corrected)); if (File.Exists(correctedMoveTo)) break; if (!Directory.Exists(correctedDirectory)) _ = Directory.CreateDirectory(correctedDirectory); if (!result) result = true; File.Move(filteredSourceDirectoryFile, correctedMoveTo); filteredSourceDirectoryFiles[i] = corrected; } } } return result; } private List GetMissingVerifyToSeasonCollection(List _, List<(int g, string sourceDirectory, string[] sourceDirectoryFiles, int r)> groupCollection) { if (_Configuration?.PropertyConfiguration is null) throw new Exception($"{nameof(_Configuration.PropertyConfiguration)} must be set!"); List results = new(); string check; foreach ((int _, string sourceDirectory, string[] _, int _) in groupCollection) { if (sourceDirectory == _Configuration.PropertyConfiguration.RootDirectory) continue; check = sourceDirectory[(_Configuration.PropertyConfiguration.RootDirectory.Length + 1)..]; if (check[0] is '=' || check.StartsWith("zzz =")) { if (!_Configuration.PropertyConfiguration.VerifyToSeason.Contains(check)) results.Add(check); } } return results; } private void CreateWindowsShortcuts((long Ticks, string FilteredSourceDirectoryFile, string PropertyDirectory, int PropertyId)[] collection, bool keepAll) { if (_Log is null) throw new Exception($"{nameof(_Log)} is null!"); int z = 0; string fileName; WindowsShortcut windowsShortcut; foreach ((long ticks, string filteredSourceDirectoryFile, string propertyDirectory, int propertyId) in collection) { z += 1; if (z % 1000 == 0) _Log.Debug($"{z}) Loop {propertyDirectory}"); if (!keepAll) { fileName = Path.Combine(propertyDirectory, $"{propertyId}.lnk"); if (File.Exists(fileName)) continue; } else { fileName = string.Empty; for (short c = 65; c < short.MaxValue; c++) { if (c > 95) break; fileName = Path.Combine(propertyDirectory, $"{(char)c}", $"{propertyId}.lnk"); if (File.Exists(fileName)) continue; } } if (string.IsNullOrEmpty(fileName)) continue; windowsShortcut = new() { Path = filteredSourceDirectoryFile }; windowsShortcut.Save(fileName); windowsShortcut.Dispose(); } } private void ThirdPassToMove(PropertyLogic propertyLogic, Property.Models.Configuration configuration, string aPropertyContentCollectionDirectory, List topDirectories, List<(int g, string sourceDirectory, string[] sourceDirectoryFiles, int r)> groupCollection) { if (_Log is null) throw new Exception($"{nameof(_Log)} is null!"); if (_Configuration?.PropertyConfiguration is null) throw new Exception($"{nameof(_Configuration.PropertyConfiguration)} must be set!"); int stay = 0; string fileName; string id = " - Id"; A_Property? property; string? directoryName; ConsoleKey? consoleKey = null; DateTime dateTime = DateTime.Now; string filteredSourceDirectoryFile; List fileStayCollection = new(); List fileMoveCollection = new(); List distinctDirectories = new(); List> valueCollection = new(); List groupResultsCollection = propertyLogic.GetParallelWork(configuration, topDirectories, groupCollection, firstPass: false, filterOnFirstPass: false); foreach (Group group in groupResultsCollection) { for (int i = 0; i < group.PropertyCollection.Length; i++) { property = group.PropertyCollection[i]; if (property?.Id is null) continue; filteredSourceDirectoryFile = group.FilteredSourceDirectoryFiles[i]; valueCollection.Add(new(property.Id.Value, property.Indices)); if (!propertyLogic.IndicesFromNew.ContainsKey(property.Id.Value)) stay += 1; else if (!fileMoveCollection.Contains(filteredSourceDirectoryFile)) fileMoveCollection.Add(filteredSourceDirectoryFile); } } string[] lines = (from l in valueCollection select string.Concat(l.Key, '\t', string.Join('\t', l.Value))).ToArray(); if (!Directory.Exists(aPropertyContentCollectionDirectory)) _ = Directory.CreateDirectory(aPropertyContentCollectionDirectory); File.WriteAllLines(Path.Combine(aPropertyContentCollectionDirectory, $"{dateTime.Ticks}.tsv"), lines); string json = JsonSerializer.Serialize(valueCollection, new JsonSerializerOptions { WriteIndented = true }); File.WriteAllText(Path.Combine(aPropertyContentCollectionDirectory, $"{dateTime.Ticks}.json"), json); foreach (string fileMove in fileMoveCollection) { directoryName = Path.GetDirectoryName(string.Concat(_Configuration.PropertyConfiguration.RootDirectory, id, fileMove[_Configuration.PropertyConfiguration.RootDirectory.Length..])); if (string.IsNullOrEmpty(directoryName)) continue; if (!distinctDirectories.Contains(directoryName)) distinctDirectories.Add(directoryName); } foreach (string distinctDirectory in distinctDirectories) { if (!Directory.Exists(distinctDirectory)) _ = Directory.CreateDirectory(distinctDirectory); } _Log.Information($"{stay} file(s) are staying and {fileMoveCollection.Count} file(s) will be moved"); for (int y = 0; y < int.MaxValue; y++) { _Log.Information($"Press \"M\" key to {nameof(File.Move)}"); _Log.Information("Press \"End\" key when ready to skip or close console if compare not needed"); consoleKey = Console.ReadKey().Key; if (consoleKey is ConsoleKey.M or ConsoleKey.End) break; } _Log.Information(". . ."); if (consoleKey.HasValue && consoleKey.Value == ConsoleKey.M) { foreach (string fileMove in fileMoveCollection) { fileName = string.Concat(_Configuration.PropertyConfiguration.RootDirectory, id, fileMove[_Configuration.PropertyConfiguration.RootDirectory.Length..]); File.Move(fileMove, fileName); } for (int i = 1; i < 4; i++) _ = Property.Models.Stateless.IPath.DeleteEmptyDirectories(_Configuration.PropertyConfiguration.RootDirectory); } } private void FourthPassCreateWindowsShortcuts(PropertyLogic propertyLogic, Property.Models.Configuration configuration, List topDirectories, List<(int g, string sourceDirectory, string[] sourceDirectoryFiles, int r)> groupCollection, bool saveToCollection, bool keepAll) { if (_Log is null) throw new Exception($"{nameof(_Log)} is null!"); int stay = 0; A_Property? property; ConsoleKey? consoleKey = null; string filteredSourceDirectoryFile; List fileMoveCollection = new(); List> valueCollection = new(); (long Ticks, string FilteredSourceDirectoryFile, string PropertyDirectory, int PropertyId)[] collection; List groupResultsCollection = propertyLogic.GetParallelWork(configuration, topDirectories, groupCollection, firstPass: false, filterOnFirstPass: false); foreach (Group group in groupResultsCollection) { for (int i = 0; i < group.PropertyCollection.Length; i++) { property = group.PropertyCollection[i]; if (property?.Id is null) continue; filteredSourceDirectoryFile = group.FilteredSourceDirectoryFiles[i]; valueCollection.Add(new(property.Id.Value, property.Indices)); if (!propertyLogic.IndicesFromNew.ContainsKey(property.Id.Value)) stay += 1; else fileMoveCollection.Add(filteredSourceDirectoryFile); } } collection = propertyLogic.GetPropertyIds(configuration, groupResultsCollection, saveToCollection); _Log.Information($"{stay} file(s) are staying and {fileMoveCollection.Count} file(s) will be moved"); for (int x = 0; x < int.MaxValue; x++) { _Log.Information($"Press \"S\" key to {nameof(CreateWindowsShortcuts)}"); _Log.Information("Press \"End\" key when ready to skip or close console if compare not needed"); consoleKey = Console.ReadKey().Key; if (consoleKey is ConsoleKey.M or ConsoleKey.End) break; } _Log.Information(". . ."); if (consoleKey.HasValue && consoleKey.Value == ConsoleKey.S) CreateWindowsShortcuts(collection, keepAll); } }