using System.Text.Json; using View_by_Distance.Shared.Models; namespace View_by_Distance.Property.Models.Stateless; public class Container { public static (int t, List<(int g, string sourceDirectory, string[] sourceDirectoryFiles)>) GetGroupCollection(string rootDirectory, int maxImagesInDirectoryForTopLevelFirstPass, bool reverse, string searchPattern, List topDirectories) { int result = 0; List<(int g, string sourceDirectory, string[] sourceDirectoryFiles)> results = new(); string? parentDirectory; string[] subDirectories; string[] sourceDirectoryFiles; List fileCollections = new(); if (!topDirectories.Any()) { if (!Directory.Exists(rootDirectory)) _ = Directory.CreateDirectory(rootDirectory); topDirectories.AddRange(from l in Directory.GetDirectories(rootDirectory, "*", SearchOption.TopDirectoryOnly) 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])); fileCollections.RemoveAt(i); } } else if (g == 2) { 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])); 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); result += sourceDirectoryFiles.Length; if (!topDirectories.Contains(subDirectory)) results.Add(new(g, subDirectory, sourceDirectoryFiles)); } } else if (g == 1) { sourceDirectoryFiles = Directory.GetFiles(rootDirectory, searchPattern, SearchOption.TopDirectoryOnly); result += sourceDirectoryFiles.Length; if (sourceDirectoryFiles.Length > maxImagesInDirectoryForTopLevelFirstPass) fileCollections.Add(sourceDirectoryFiles); else results.Add(new(g, rootDirectory, sourceDirectoryFiles)); if (reverse) topDirectories.Reverse(); subDirectories = topDirectories.ToArray(); foreach (string subDirectory in subDirectories) { sourceDirectoryFiles = Directory.GetFiles(subDirectory, searchPattern, SearchOption.TopDirectoryOnly); result += sourceDirectoryFiles.Length; if (sourceDirectoryFiles.Length > maxImagesInDirectoryForTopLevelFirstPass) fileCollections.Add(sourceDirectoryFiles); else { if (sourceDirectoryFiles.Any() || Directory.GetDirectories(subDirectory, "*", SearchOption.TopDirectoryOnly).Any()) results.Add(new(g, subDirectory, sourceDirectoryFiles)); else if (searchPattern == "*" && subDirectory != rootDirectory) Directory.Delete(subDirectory); } } fileCollections.Reverse(); } else throw new Exception(); } return new(result, results); } public static (int t, List<(int g, string sourceDirectory, string[] sourceDirectoryFiles)>) GetGroupCollection(string rootDirectory, string searchPattern, List topDirectories) { (int t, List<(int g, string sourceDirectory, string[] sourceDirectoryFiles)>) results; int maxImagesInDirectoryForTopLevelFirstPass = 50; bool reverse = false; results = GetGroupCollection(rootDirectory, maxImagesInDirectoryForTopLevelFirstPass, reverse, searchPattern, topDirectories); return results; } private static (int j, List<(int g, string sourceDirectory, string[] sourceDirectoryFiles)>) GetJsonGroupCollection(Configuration configuration, A_Property propertyLogic, string rootDirectory) { (int j, List<(int g, string sourceDirectory, string[] sourceDirectoryFiles)>) results; string searchPattern = "*.json"; List topDirectories = new(); results = GetGroupCollection(rootDirectory, configuration.MaxImagesInDirectoryForTopLevelFirstPass, propertyLogic.Reverse, searchPattern, topDirectories); return results; } private static (int f, List<(int g, string sourceDirectory, FileHolder[] sourceDirectoryFiles)>) GetFileHolderGroupCollection(Configuration configuration, A_Property propertyLogic, string searchPattern, List topDirectories) { List<(int g, string sourceDirectory, FileHolder[] sourceDirectoryFiles)> results = new(); List<(int g, string sourceDirectory, string[] sourceDirectoryFiles)> collection; (int f, collection) = GetGroupCollection(configuration.RootDirectory, configuration.MaxImagesInDirectoryForTopLevelFirstPass, propertyLogic.Reverse, searchPattern, topDirectories); foreach ((int g, string sourceDirectory, string[] sourceDirectoryFiles) in collection) results.Add(new(g, sourceDirectory, (from l in sourceDirectoryFiles select new FileHolder(l)).ToArray())); return new(f, results); } private static void ParallelFor(List<(int, string, string[])> jsonCollection, int i, int length, List<(int, string, List<(string, Shared.Models.Property?)>)> results) { string key; string json; Shared.Models.Property? property; (int g, string sourceDirectory, string[] sourceDirectoryFiles) = 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)); } private static List<(int g, string sourceDirectory, List<(string sourceDirectoryFile, Shared.Models.Property? property)> collection)> GetCollection(string rootDirectory, List<(int g, string sourceDirectory, string[] SourceDirectoryFiles)> jsonCollection) { List<(int, string, List<(string, Shared.Models.Property?)>)> results = new(); int length = rootDirectory.Length; ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = Environment.ProcessorCount }; _ = Parallel.For(0, jsonCollection.Count, parallelOptions, (i, state) => ParallelFor(jsonCollection, i, length, results)); return results; } private static (int, Shared.Models.Container[]) GetContainers(Configuration configuration, string aPropertySingletonDirectory, List<(int, string, FileHolder[])> fileHolderGroupCollection, List<(int, string, List<(string, Shared.Models.Property?)>)> collectionFromJson) { int result = 0; Shared.Models.Container[] results; Item item; int length; int additional; string inferred; List items; string keyWithJson; string relativePath; FileHolder keyFileHolder; bool isValidImageFormatExtension; Shared.Models.Container container; List keySourceDirectories; Dictionary keyValuePairs = new(); Dictionary fileHolderKeyValuePairs = new(); length = configuration.RootDirectory.Length; foreach ((int g, string sourceDirectory, FileHolder[] sourceDirectoryFileHolderCollection) in fileHolderGroupCollection) { foreach (FileHolder sourceDirectoryFileHolder in sourceDirectoryFileHolderCollection) { relativePath = Shared.Models.Stateless.Methods.IPath.GetRelativePath(sourceDirectoryFileHolder.FullName, length, forceExtensionToLower: true); fileHolderKeyValuePairs.Add(relativePath, new(sourceDirectory, sourceDirectoryFileHolder)); } } length = aPropertySingletonDirectory.Length; foreach ((int g, string _, List<(string, Shared.Models.Property?)> collection) in collectionFromJson) { if (!collection.Any()) continue; items = new(); keySourceDirectories = new(); foreach ((string sourceDirectoryFile, Shared.Models.Property? property) in collection) { keyWithJson = Shared.Models.Stateless.Methods.IPath.GetRelativePath(sourceDirectoryFile, length, forceExtensionToLower: false); relativePath = keyWithJson[..^5]; if (!fileHolderKeyValuePairs.ContainsKey(relativePath)) { 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); item = new(sourceDirectoryFile, relativePath, keyFileHolder, isValidImageFormatExtension, property, true, null); items.Add(item); } else { keyFileHolder = fileHolderKeyValuePairs[relativePath].FileHolder; keySourceDirectories.Add(fileHolderKeyValuePairs[relativePath].SourceDirectory); if (!fileHolderKeyValuePairs.Remove(relativePath)) 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) item = new(sourceDirectoryFile, relativePath, keyFileHolder, isValidImageFormatExtension, property, false, null); else if (configuration.PropertiesChangedForProperty || property.LastWriteTime != keyFileHolder.LastWriteTime || property.FileSize != keyFileHolder.Length) item = new(sourceDirectoryFile, relativePath, keyFileHolder, isValidImageFormatExtension, property, false, true); else item = new(sourceDirectoryFile, relativePath, keyFileHolder, isValidImageFormatExtension, property, false, false); items.Add(item); } } if (items.Any()) { result += items.Count; if (keySourceDirectories.Distinct().Count() != 1) continue; container = new(g, items, keySourceDirectories[0]); keyValuePairs.Add(keySourceDirectories[0], container); } } length = configuration.RootDirectory.Length; foreach ((int g, string sourceDirectory, FileHolder[] sourceDirectoryFileHolderCollection) in fileHolderGroupCollection) { items = new(); foreach (FileHolder sourceDirectoryFileHolder in sourceDirectoryFileHolderCollection) { relativePath = Shared.Models.Stateless.Methods.IPath.GetRelativePath(sourceDirectoryFileHolder.FullName, length, forceExtensionToLower: true); if (!fileHolderKeyValuePairs.ContainsKey(relativePath)) continue; if (!fileHolderKeyValuePairs.Remove(relativePath)) throw new Exception(); if (sourceDirectoryFileHolder.ExtensionLowered is ".json") continue; isValidImageFormatExtension = configuration.ValidImageFormatExtensions.Contains(sourceDirectoryFileHolder.ExtensionLowered); item = new(sourceDirectoryFileHolder.FullName, relativePath, sourceDirectoryFileHolder, isValidImageFormatExtension, null, null, null); items.Add(item); } if (sourceDirectory == configuration.RootDirectory || items.Any()) { if (!keyValuePairs.ContainsKey(sourceDirectory)) { result += items.Count; container = new(g, items, sourceDirectory); keyValuePairs.Add(sourceDirectory, container); } else { container = keyValuePairs[sourceDirectory]; (items, additional) = Shared.Models.Stateless.Methods.IItem.GetMerged(container.Items, items); result += additional; container = new(container.G, items, container.SourceDirectory); keyValuePairs[sourceDirectory] = container; } } } if (fileHolderKeyValuePairs.Any()) throw new NotSupportedException("Unmapped left!"); results = (from l in keyValuePairs orderby l.Value.G, l.Value.Items.Count select l.Value).ToArray(); return new(result, results); } public static (int, int, int, Shared.Models.Container[]) GetContainers(Configuration configuration, A_Property propertyLogic) { Shared.Models.Container[] results; string searchPattern = "*"; List topDirectories = new(); List<(int g, string sourceDirectory, string[] sourceDirectoryFiles)> jsonCollection; List<(int g, string sourceDirectory, FileHolder[] sourceDirectoryFiles)> fileHolderGroupCollection; string aPropertySingletonDirectory = IResult.GetResultsDateGroupDirectory(configuration, nameof(A_Property), "{}"); List<(int g, string sourceDirectory, List<(string sourceDirectoryFile, Shared.Models.Property? property)> collection)> collectionFromJson; (int j, jsonCollection) = GetJsonGroupCollection(configuration, propertyLogic, aPropertySingletonDirectory); (int f, fileHolderGroupCollection) = GetFileHolderGroupCollection(configuration, propertyLogic, searchPattern, topDirectories); collectionFromJson = GetCollection(aPropertySingletonDirectory, jsonCollection); (int t, results) = GetContainers(configuration, aPropertySingletonDirectory, fileHolderGroupCollection, collectionFromJson); return (j, f, t, results); } }