using System.Text.Json; using View_by_Distance.Shared.Models; namespace View_by_Distance.Property.Models.Stateless; public class Container { public static List<(int g, string sourceDirectory, string[] sourceDirectoryFiles, int r)> GetGroupCollection(string rootDirectory, int maxImagesInDirectoryForTopLevelFirstPass, bool reverse, string searchPattern, List topDirectories) { List<(int g, string sourceDirectory, string[] sourceDirectoryFiles, int r)> results = new(); string? parentDirectory; string[] subDirectories; string[] sourceDirectoryFiles; List fileCollections = new(); if (!topDirectories.Any()) topDirectories.AddRange(from l in Directory.GetDirectories(rootDirectory, "*", SearchOption.TopDirectoryOnly) orderby Path.GetFileName(l)[..1], l select Path.GetFullPath(l)); for (int g = 1; g < 5; g++) { if (g == 4) { for (int i = fileCollections.Count - 1; i > -1; i--) { parentDirectory = Path.GetDirectoryName(fileCollections[i][0]); if (string.IsNullOrEmpty(parentDirectory)) continue; results.Add(new(g, parentDirectory, fileCollections[i], results.Count)); fileCollections.RemoveAt(i); } } else if (g == 2) { fileCollections = (from l in fileCollections orderby l.Length descending select l).ToList(); for (int i = fileCollections.Count - 1; i > -1; i--) { if (fileCollections[i].Length > maxImagesInDirectoryForTopLevelFirstPass * g) break; parentDirectory = Path.GetDirectoryName(fileCollections[i][0]); if (string.IsNullOrEmpty(parentDirectory)) continue; results.Add(new(g, parentDirectory, fileCollections[i], results.Count)); fileCollections.RemoveAt(i); } } else if (g == 3) { subDirectories = Directory.GetDirectories(rootDirectory, "*", SearchOption.AllDirectories); if (reverse) subDirectories = subDirectories.Reverse().ToArray(); foreach (string subDirectory in subDirectories) { sourceDirectoryFiles = Directory.GetFiles(subDirectory, "*", SearchOption.TopDirectoryOnly); if (!topDirectories.Contains(subDirectory)) results.Add(new(g, subDirectory, sourceDirectoryFiles, results.Count)); } } else if (g == 1) { sourceDirectoryFiles = Directory.GetFiles(rootDirectory, searchPattern, SearchOption.TopDirectoryOnly); if (sourceDirectoryFiles.Length > maxImagesInDirectoryForTopLevelFirstPass) fileCollections.Add(sourceDirectoryFiles); else results.Add(new(g, rootDirectory, sourceDirectoryFiles, results.Count)); if (reverse) topDirectories.Reverse(); subDirectories = topDirectories.ToArray(); foreach (string subDirectory in subDirectories) { sourceDirectoryFiles = Directory.GetFiles(subDirectory, searchPattern, SearchOption.TopDirectoryOnly); if (sourceDirectoryFiles.Length > maxImagesInDirectoryForTopLevelFirstPass) fileCollections.Add(sourceDirectoryFiles); else { if (sourceDirectoryFiles.Any() || Directory.GetDirectories(subDirectory, "*", SearchOption.TopDirectoryOnly).Any()) results.Add(new(g, subDirectory, sourceDirectoryFiles, results.Count)); else if (searchPattern == "*") { sourceDirectoryFiles = Directory.GetFiles(subDirectory, searchPattern, SearchOption.TopDirectoryOnly); foreach (string subFile in sourceDirectoryFiles) File.Delete(subFile); Directory.Delete(subDirectory); } } } fileCollections.Reverse(); } else throw new Exception(); } return results; } public static List<(int g, string sourceDirectory, string[] sourceDirectoryFiles, int r)> GetGroupCollection(string rootDirectory, string searchPattern, List topDirectories) { List<(int g, string sourceDirectory, string[] sourceDirectoryFiles, int r)> results; int maxImagesInDirectoryForTopLevelFirstPass = 50; bool reverse = false; results = GetGroupCollection(rootDirectory, maxImagesInDirectoryForTopLevelFirstPass, reverse, searchPattern, topDirectories); return results; } private static List<(int g, string sourceDirectory, string[] sourceDirectoryFiles, int r)> GetJsonGroupCollection(Configuration configuration, A_Property propertyLogic, string rootDirectory) { List<(int g, string sourceDirectory, string[] sourceDirectoryFiles, int r)> results; string searchPattern = "*.json"; List topDirectories = new(); results = GetGroupCollection(rootDirectory, configuration.MaxImagesInDirectoryForTopLevelFirstPass, propertyLogic.Reverse, searchPattern, topDirectories); return results; } private static List<(int g, string sourceDirectory, FileHolder[] sourceDirectoryFiles, int r)> GetFileHolderGroupCollection(Configuration configuration, A_Property propertyLogic, string searchPattern, List topDirectories) { List<(int g, string sourceDirectory, FileHolder[] sourceDirectoryFiles, int r)> results = new(); List<(int g, string sourceDirectory, string[] sourceDirectoryFiles, int r)>? collection = GetGroupCollection(configuration.RootDirectory, configuration.MaxImagesInDirectoryForTopLevelFirstPass, propertyLogic.Reverse, searchPattern, topDirectories); foreach ((int g, string sourceDirectory, string[] sourceDirectoryFiles, int r) in collection) results.Add(new(g, sourceDirectory, (from l in sourceDirectoryFiles select new FileHolder(l)).ToArray(), r)); return results; } private static void ParallelFor(List<(int, string, string[], int)> jsonCollection, int i, int length, List<(int, string, List<(string, Shared.Models.Property?)>, int)> results) { string key; string json; Shared.Models.Property? property; (int g, string sourceDirectory, string[] sourceDirectoryFiles, int r) = jsonCollection[i]; List<(string, Shared.Models.Property?)> collection = new(); foreach (string sourceDirectoryFile in sourceDirectoryFiles) { json = File.ReadAllText(sourceDirectoryFile); key = Shared.Models.Stateless.Methods.IPath.GetRelativePath(sourceDirectoryFile, length); property = JsonSerializer.Deserialize(json); collection.Add(new(sourceDirectoryFile, property)); } lock (results) results.Add(new(g, sourceDirectory, collection, r)); } private static List<(int g, string sourceDirectory, List<(string sourceDirectoryFile, Shared.Models.Property? property)> collection, int r)> GetCollection(string rootDirectory, List<(int g, string sourceDirectory, string[] SourceDirectoryFiles, int r)> jsonCollection) { List<(int, string, List<(string, Shared.Models.Property?)>, int)> results = new(); int length = rootDirectory.Length; ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = Environment.ProcessorCount }; _ = Parallel.For(0, jsonCollection.Count, parallelOptions, i => ParallelFor(jsonCollection, i, length, results)); return results; } private static List GetContainers(Configuration configuration, string aPropertySingletonDirectory, List<(int, string, FileHolder[], int)> fileHolderGroupCollection, List<(int, string, List<(string, Shared.Models.Property?)>, int)> collectionFromJson) { List results = new(); int length; string key; string inferred; List items; string relativePath; FileHolder keyFileHolder; Shared.Models.Container container; bool isValidImageFormatExtension; List keySourceDirectories; Dictionary fileHolderKeyValuePairs = new(); length = configuration.RootDirectory.Length; foreach ((int g, string sourceDirectory, FileHolder[] sourceDirectoryFileHolderCollection, int r) in fileHolderGroupCollection) { foreach (FileHolder sourceDirectoryFileHolder in sourceDirectoryFileHolderCollection) { relativePath = Shared.Models.Stateless.Methods.IPath.GetRelativePath(sourceDirectoryFileHolder.FullName, length); key = string.Concat(relativePath, ".json"); fileHolderKeyValuePairs.Add(key, new(sourceDirectory, sourceDirectoryFileHolder)); } } length = aPropertySingletonDirectory.Length; foreach ((int g, string _, List<(string, Shared.Models.Property?)> collection, int r) in collectionFromJson) { if (!collection.Any()) continue; items = new(); keySourceDirectories = new(); foreach ((string sourceDirectoryFile, Shared.Models.Property? property) in collection) { key = Shared.Models.Stateless.Methods.IPath.GetRelativePath(sourceDirectoryFile, length); relativePath = key[..^5]; if (!fileHolderKeyValuePairs.ContainsKey(key)) { inferred = string.Concat(configuration.RootDirectory, relativePath); keyFileHolder = new(inferred); if (keyFileHolder.ExtensionLowered is ".json") continue; keySourceDirectories.Add(string.Concat(keyFileHolder.DirectoryName)); isValidImageFormatExtension = configuration.ValidImageFormatExtensions.Contains(keyFileHolder.ExtensionLowered); items.Add(new(sourceDirectoryFile, relativePath, keyFileHolder, isValidImageFormatExtension, property, true, null)); } else { keyFileHolder = fileHolderKeyValuePairs[key].FileHolder; keySourceDirectories.Add(fileHolderKeyValuePairs[key].SourceDirectory); if (!fileHolderKeyValuePairs.Remove(key)) throw new Exception(); if (keyFileHolder.ExtensionLowered is ".json") continue; isValidImageFormatExtension = configuration.ValidImageFormatExtensions.Contains(keyFileHolder.ExtensionLowered); if (property?.Id is null || property?.Width is null || property?.Height is null) items.Add(new(sourceDirectoryFile, relativePath, keyFileHolder, isValidImageFormatExtension, property, false, null)); else if (configuration.PropertiesChangedForProperty || property.LastWriteTime != keyFileHolder.LastWriteTime || property.FileSize != keyFileHolder.Length) items.Add(new(sourceDirectoryFile, relativePath, keyFileHolder, isValidImageFormatExtension, property, false, true)); else items.Add(new(sourceDirectoryFile, relativePath, keyFileHolder, isValidImageFormatExtension, property, false, false)); } } if (items.Any()) { if (keySourceDirectories.Distinct().Count() != 1) continue; container = new(g, r, items, keySourceDirectories[0]); results.Add(container); } } length = configuration.RootDirectory.Length; foreach ((int g, string sourceDirectory, FileHolder[] sourceDirectoryFileHolderCollection, int r) in fileHolderGroupCollection) { items = new(); foreach (FileHolder sourceDirectoryFileHolder in sourceDirectoryFileHolderCollection) { relativePath = Shared.Models.Stateless.Methods.IPath.GetRelativePath(sourceDirectoryFileHolder.FullName, length); key = string.Concat(relativePath, ".json"); if (!fileHolderKeyValuePairs.ContainsKey(key)) continue; if (!fileHolderKeyValuePairs.Remove(key)) throw new Exception(); if (sourceDirectoryFileHolder.ExtensionLowered is ".json") continue; isValidImageFormatExtension = configuration.ValidImageFormatExtensions.Contains(sourceDirectoryFileHolder.ExtensionLowered); items.Add(new(relativePath, sourceDirectoryFileHolder.FullName, sourceDirectoryFileHolder, isValidImageFormatExtension, null, null, null)); } if (items.Any()) { container = new(g, r, items, sourceDirectory); results.Add(container); } } if (fileHolderKeyValuePairs.Any()) throw new Exception(); results = (from l in results orderby l.G, l.R select l).ToList(); return results; } public static List GetContainers(Configuration configuration, A_Property propertyLogic) { List results; string searchPattern = "*"; List topDirectories = new(); List<(int g, string sourceDirectory, string[] sourceDirectoryFiles, int r)> jsonCollection; List<(int g, string sourceDirectory, FileHolder[] sourceDirectoryFiles, int r)> fileHolderGroupCollection; string aPropertySingletonDirectory = IResult.GetResultsDateGroupDirectory(configuration, nameof(A_Property), "{}"); List<(int g, string sourceDirectory, List<(string sourceDirectoryFile, Shared.Models.Property? property)> collection, int r)> collectionFromJson; jsonCollection = GetJsonGroupCollection(configuration, propertyLogic, aPropertySingletonDirectory); fileHolderGroupCollection = GetFileHolderGroupCollection(configuration, propertyLogic, searchPattern, topDirectories); collectionFromJson = GetCollection(aPropertySingletonDirectory, jsonCollection); results = GetContainers(configuration, aPropertySingletonDirectory, fileHolderGroupCollection, collectionFromJson); return results; } }