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, state) => ParallelFor(jsonCollection, i, length, results)); return results; } private static Shared.Models.Container[] GetContainers(Configuration configuration, bool firstRun, string aPropertySingletonDirectory, List<(int, string, FileHolder[], int)> fileHolderGroupCollection, List<(int, string, List<(string, Shared.Models.Property?)>, int)> collectionFromJson) { Shared.Models.Container[] results; Item item; int length; int additional; string inferred; List items; string[] existing; 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, int r) 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, int r) 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()) { if (keySourceDirectories.Distinct().Count() != 1) continue; container = new(g, r, items, keySourceDirectories[0]); keyValuePairs.Add(keySourceDirectories[0], 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, 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); if (firstRun) item = new(sourceDirectoryFileHolder.FullName, relativePath, sourceDirectoryFileHolder, isValidImageFormatExtension, null, null, null); else if (!isValidImageFormatExtension) item = new(sourceDirectoryFileHolder.FullName, relativePath, sourceDirectoryFileHolder, isValidImageFormatExtension, null, null, null); else item = new(sourceDirectoryFileHolder.FullName, relativePath, sourceDirectoryFileHolder, isValidImageFormatExtension, null, null, null); items.Add(item); } if (items.Any()) { if (!keyValuePairs.ContainsKey(sourceDirectory)) { container = new(g, r, items, sourceDirectory); keyValuePairs.Add(sourceDirectory, container); } else { additional = 0; container = keyValuePairs[sourceDirectory]; length = items.Count; existing = (from l in container.Items select l.ImageFileHolder?.FullName).ToArray(); for (int i = 0; i < length; i++) { item = items[i]; if (item.ImageFileHolder is null || existing.Contains(item.ImageFileHolder.FullName)) continue; additional += 1; items.Add(item); } container = new(g, r + additional, items, sourceDirectory); keyValuePairs[sourceDirectory] = container; } } } if (!firstRun && fileHolderKeyValuePairs.Any()) throw new Exception(); KeyValuePair[] sortedKeyValuePairs = (from l in keyValuePairs orderby l.Value.G, l.Value.R select l).ToArray(); results = (from l in sortedKeyValuePairs select l.Value).ToArray(); return results; } public static Shared.Models.Container[] GetContainers(Configuration configuration, bool firstRun, A_Property propertyLogic) { Shared.Models.Container[] 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, firstRun, aPropertySingletonDirectory, fileHolderGroupCollection, collectionFromJson); return results; } }