IDirectory first pass

This commit is contained in:
2023-01-08 13:33:33 -07:00
parent 9b9573093f
commit 0ef5b668e8
27 changed files with 772 additions and 865 deletions

View File

@ -1,33 +1,10 @@
using System.Text.Json;
using System.Text.Json.Serialization;
namespace View_by_Distance.Shared.Models;
public class Container : Properties.IContainer
public record Container(string SourceDirectory, List<Item> Items)
{
protected readonly int _G;
protected readonly List<Item> _Items;
protected readonly string _SourceDirectory;
public int G => _G;
public List<Item> Items => _Items;
public string SourceDirectory => _SourceDirectory;
[JsonConstructor]
public Container(int g, List<Item> items, string sourceDirectory)
{
_G = g;
_Items = items;
_SourceDirectory = sourceDirectory;
}
public Container(int g, string sourceDirectory)
{
_G = g;
_Items = new();
_SourceDirectory = sourceDirectory;
}
public override string ToString()
{
string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true });

View File

@ -0,0 +1,3 @@
namespace View_by_Distance.Shared.Models;
public record FilePair(string Path, bool IsUnique, List<string> Collection, string? Match) { }

View File

@ -6,50 +6,47 @@ namespace View_by_Distance.Shared.Models;
public class Item : Properties.IItem
{
protected readonly bool? _Abandoned;
protected List<Face> _Faces;
protected readonly bool? _FileSizeChanged;
protected readonly FileHolder _ImageFileHolder;
protected bool? _IsUniqueFileName;
protected bool _IsValidImageFormatExtension;
protected bool? _LastWriteTimeChanged;
protected bool? _Moved;
protected readonly bool? _NoJson;
protected Property? _Property;
protected readonly string _RelativePath;
protected FileHolder? _ResizedFileHolder;
protected readonly FileHolder _SourceDirectoryFileHolder;
protected bool _ValidImageFormatExtension;
public bool? Abandoned => _Abandoned;
public List<Face> Faces => _Faces;
public bool? FileSizeChanged => _FileSizeChanged;
public FileHolder ImageFileHolder => _ImageFileHolder;
public bool? IsUniqueFileName => _IsUniqueFileName;
public bool IsValidImageFormatExtension => _IsValidImageFormatExtension;
public bool? LastWriteTimeChanged => _LastWriteTimeChanged;
public bool? Moved => _Moved;
public bool? NoJson => _NoJson;
public Property? Property => _Property;
public string RelativePath => _RelativePath;
public FileHolder? ResizedFileHolder => _ResizedFileHolder;
public FileHolder SourceDirectoryFileHolder => _SourceDirectoryFileHolder;
public bool ValidImageFormatExtension => _ValidImageFormatExtension;
[JsonConstructor]
public Item(bool? abandoned, List<Face> faces, bool? fileSizeChanged, FileHolder imageFileHolder, bool? lastWriteTimeChanged, bool? moved, bool? noJson, Property? property, string relativePath, FileHolder? resizedFileHolder, FileHolder sourceDirectoryFileHolder, bool validImageFormatExtension)
public Item(List<Face> faces, bool? fileSizeChanged, FileHolder imageFileHolder, bool? isUniqueFileName, bool isValidImageFormatExtension, bool? lastWriteTimeChanged, bool? moved, Property? property, string relativePath, FileHolder? resizedFileHolder, FileHolder sourceDirectoryFileHolder)
{
_Faces = faces;
_Moved = moved;
_NoJson = noJson;
_Property = property;
_Abandoned = abandoned;
_RelativePath = relativePath;
_FileSizeChanged = fileSizeChanged;
_ImageFileHolder = imageFileHolder;
_IsUniqueFileName = isUniqueFileName;
_IsValidImageFormatExtension = isValidImageFormatExtension;
_LastWriteTimeChanged = lastWriteTimeChanged;
_Moved = moved;
_Property = property;
_RelativePath = relativePath;
_ResizedFileHolder = resizedFileHolder;
_SourceDirectoryFileHolder = sourceDirectoryFileHolder;
_LastWriteTimeChanged = lastWriteTimeChanged;
_ValidImageFormatExtension = validImageFormatExtension;
}
public Item(FileHolder sourceDirectoryFileHolder, string relativePath, FileHolder imageFileInfo, bool validImageFormatExtension, Property? property, bool? abandoned, bool? fileSizeChanged, bool? lastWriteTimeChanged) :
this(abandoned, new(), fileSizeChanged, imageFileInfo, lastWriteTimeChanged, null, abandoned is null, property, relativePath, null, sourceDirectoryFileHolder, validImageFormatExtension)
public Item(FileHolder sourceDirectoryFileHolder, string relativePath, FileHolder imageFileInfo, bool? isUniqueFileName, bool isValidImageFormatExtension, Property? property, bool? abandoned, bool? fileSizeChanged, bool? lastWriteTimeChanged) :
this(new(), fileSizeChanged, imageFileInfo, isUniqueFileName, isValidImageFormatExtension, lastWriteTimeChanged, null, property, relativePath, null, sourceDirectoryFileHolder)
{
if (relativePath.EndsWith(".json"))
throw new ArgumentException("Can not be a *.json file!");
@ -58,7 +55,7 @@ public class Item : Properties.IItem
}
public Item(FileHolder sourceDirectoryFileHolder, string relativePath, bool isValidImageFormatExtension) :
this(sourceDirectoryFileHolder, relativePath, sourceDirectoryFileHolder, isValidImageFormatExtension, null, null, null, null)
this(sourceDirectoryFileHolder, relativePath, sourceDirectoryFileHolder, null, isValidImageFormatExtension, null, null, null, null)
{ }
public override string ToString()
@ -79,7 +76,7 @@ public class Item : Properties.IItem
_ResizedFileHolder = fileHolder;
}
public bool Any() => (_Abandoned.HasValue && _Abandoned.Value) || (_FileSizeChanged.HasValue && _FileSizeChanged.Value) || (_LastWriteTimeChanged.HasValue && _LastWriteTimeChanged.Value) || (_Moved.HasValue && _Moved.Value) || (_NoJson.HasValue && _NoJson.Value);
public bool Any() => !_SourceDirectoryFileHolder.Exists || (_FileSizeChanged.HasValue && _FileSizeChanged.Value) || (_LastWriteTimeChanged.HasValue && _LastWriteTimeChanged.Value) || (_Moved.HasValue && _Moved.Value);
public void Update(Property property) => _Property = property;

View File

@ -1,10 +0,0 @@
namespace View_by_Distance.Shared.Models.Properties;
public interface IContainer
{
public int G { get; }
public List<Item> Items { get; }
public string SourceDirectory { get; }
}

View File

@ -3,16 +3,15 @@ namespace View_by_Distance.Shared.Models.Properties;
public interface IItem
{
public bool? Abandoned { get; }
public bool? FileSizeChanged { get; }
public List<Face> Faces { get; }
public FileHolder ImageFileHolder { get; }
public bool? IsUniqueFileName { get; }
public bool IsValidImageFormatExtension { get; }
public bool? Moved { get; }
public bool? NoJson { get; }
public Property? Property { get; }
public string RelativePath { get; }
public FileHolder? ResizedFileHolder { get; }
public FileHolder SourceDirectoryFileHolder { get; }
public bool ValidImageFormatExtension { get; }
}

View File

@ -5,11 +5,13 @@ public interface IPropertyConfiguration
public string DateGroup { init; get; }
public string[] IgnoreExtensions { init; get; }
public bool PropertiesChangedForProperty { init; get; }
public string[] PropertyContentCollectionFiles { init; get; }
public string ResultAllInOne { init; get; }
public string ResultCollection { init; get; }
public string ResultContent { init; get; }
public string ResultSingleton { init; get; }
public string[] ValidImageFormatExtensions { init; get; }
public string[] VerifyToSeason { init; get; }
public string? ModelName { get; }
public int? NumberOfJitters { get; }

View File

@ -1,8 +1,12 @@
using System.Text.Json;
namespace View_by_Distance.Shared.Models.Stateless.Methods;
internal abstract class Container
{
private record FilePair(string Path, string? Directory, bool IsUnique, List<string> Collection, Models.Item Item) { }
internal static DateTime[] GetContainerDateTimes(Models.Item[] filteredItems)
{
DateTime[] results;
@ -26,8 +30,7 @@ internal abstract class Container
foreach (Models.Item item in container.Items)
{
if (item.ImageFileHolder is not null
&& (item.Abandoned is null || !item.Abandoned.Value)
&& item.ValidImageFormatExtension
&& item.IsValidImageFormatExtension
&& !propertyConfiguration.IgnoreExtensions.Contains(item.ImageFileHolder.ExtensionLowered))
results.Add(item);
}
@ -55,9 +58,7 @@ internal abstract class Container
internal static Models.Container[] SortContainers(Properties.IPropertyConfiguration propertyConfiguration, string[] ignoreRelativePaths, bool argZeroIsConfigurationRootDirectory, string argZero, Models.Container[] containers)
{
List<Models.Container> results = new();
Models.Item[] filteredItems;
bool isIgnoreRelativePath;
List<int> collection = new();
for (int i = 1; i < 3; i++)
{
foreach (Models.Container container in containers)
@ -66,30 +67,145 @@ internal abstract class Container
continue;
if (!argZeroIsConfigurationRootDirectory && !container.SourceDirectory.StartsWith(argZero))
continue;
filteredItems = GetFilterItems(propertyConfiguration, container);
if (!filteredItems.Any())
continue;
isIgnoreRelativePath = ignoreRelativePaths.Any(l => container.SourceDirectory.Contains(l)) && IsIgnoreRelativePath(propertyConfiguration, ignoreRelativePaths, container.SourceDirectory);
if (i == 1 && isIgnoreRelativePath)
continue;
if (i == 2 && !isIgnoreRelativePath)
continue;
foreach (Models.Item item in filteredItems)
{
if (item.Property?.Id is null)
continue;
if (collection.Contains(item.Property.Id.Value))
{
if (i == 1)
continue;
continue;
}
collection.Add(item.Property.Id.Value);
}
results.Add(container);
}
}
return results.ToArray();
}
internal static List<Models.FilePair> GetFilePairs(Properties.IPropertyConfiguration propertyConfiguration, string directorySearchFilter, string extension, string aPropertySingletonDirectory, List<string[]> filesCollection)
{
int renamed;
List<Models.FilePair>? filePairs = null;
List<string[]>? jsonFilesCollection = null;
IReadOnlyDictionary<string, List<string>>? compareFileNamesToFiles = null;
IReadOnlyDictionary<string, List<string>> fileNamesToFiles = IDirectory.GetFilesKeyValuePairs(filesCollection);
for (int i = 0; i < int.MaxValue; i++)
{
renamed = 0;
jsonFilesCollection = IDirectory.GetFilesCollection(aPropertySingletonDirectory, directorySearchFilter, extension);
compareFileNamesToFiles = IDirectory.GetFilesKeyValuePairs(jsonFilesCollection);
renamed += IDirectory.LookForAbandoned(jsonFilesCollection, fileNamesToFiles, extension);
filePairs = IDirectory.GetFiles(filesCollection, fileNamesToFiles, extension, compareFileNamesToFiles);
renamed += IDirectory.MaybeMove(propertyConfiguration.RootDirectory, propertyConfiguration.ResultAllInOne, filePairs, aPropertySingletonDirectory, extension);
if (renamed == 0)
break;
}
if (filePairs is null || jsonFilesCollection is null || compareFileNamesToFiles is null)
throw new NullReferenceException(nameof(filePairs));
return filePairs;
}
private static Models.Property? GetProperty(Models.FilePair filePair)
{
Models.Property? property;
if (filePair.Match is null)
property = null;
else
{
string json = File.ReadAllText(filePair.Match);
if (string.IsNullOrEmpty(json))
property = null;
else
property = JsonSerializer.Deserialize<Models.Property>(json);
}
return property;
}
private static void ParallelFor(Properties.IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory, string extension, int length, Models.FilePair filePair, List<FilePair> results)
{
char directory;
string fileName;
bool abandoned = false;
Models.FileHolder sourceDirectoryFileHolder;
Models.Property? property = GetProperty(filePair);
Models.FileHolder imageFileInfo = new(filePair.Path);
bool? fileSizeChanged = property is not null ? property.FileSize != imageFileInfo.Length : null;
string relativePath = IPath.GetRelativePath(filePair.Path, length, forceExtensionToLower: true);
bool isValidImageFormatExtension = propertyConfiguration.ValidImageFormatExtensions.Contains(imageFileInfo.ExtensionLowered);
bool? lastWriteTimeChanged = property is not null ? propertyConfiguration.PropertiesChangedForProperty || property.LastWriteTime != imageFileInfo.LastWriteTime : null;
if (filePair.Match is not null)
sourceDirectoryFileHolder = new(filePair.Match);
else if (!filePair.IsUnique)
sourceDirectoryFileHolder = new(Path.GetFullPath(string.Concat(aPropertySingletonDirectory, relativePath, extension)));
else
{
fileName = Path.GetFileName(filePair.Path);
directory = IDirectory.GetDirectory(fileName);
sourceDirectoryFileHolder = new(Path.Combine(aPropertySingletonDirectory, propertyConfiguration.ResultAllInOne, directory.ToString(), $"{fileName}{extension}"));
}
if (imageFileInfo.LastWriteTime is not null && sourceDirectoryFileHolder.CreationTime is not null && sourceDirectoryFileHolder.LastWriteTime is not null && imageFileInfo.LastWriteTime.Value != sourceDirectoryFileHolder.CreationTime.Value)
{
File.SetCreationTime(sourceDirectoryFileHolder.FullName, imageFileInfo.LastWriteTime.Value);
File.SetLastWriteTime(sourceDirectoryFileHolder.FullName, sourceDirectoryFileHolder.LastWriteTime.Value);
}
Models.Item item = new(sourceDirectoryFileHolder, relativePath, imageFileInfo, filePair.IsUnique, isValidImageFormatExtension, property, abandoned, fileSizeChanged, lastWriteTimeChanged);
lock (results)
results.Add(new(filePair.Path, imageFileInfo.DirectoryName, filePair.IsUnique, filePair.Collection, item));
}
private static List<FilePair> GetFilePairs(Properties.IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory, string extension, List<Models.FilePair> filePairs)
{
List<FilePair> results = new();
int length = propertyConfiguration.RootDirectory.Length;
int maxDegreeOfParallelism = Environment.ProcessorCount;
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism };
_ = Parallel.For(0, filePairs.Count, parallelOptions, (i, state) => ParallelFor(propertyConfiguration, aPropertySingletonDirectory, extension, length, filePairs[i], results));
return results;
}
internal static (int, Models.Container[]) GetContainers(Properties.IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory)
{
List<Models.Container> results = new();
string? directory;
List<Models.Item>? items;
Models.Container container;
const string extension = ".json";
const string fileSearchFilter = "*";
const string directorySearchFilter = "*";
Dictionary<string, List<Models.Item>> directoryToItems = new();
List<string[]> filesCollection = IDirectory.GetFilesCollection(propertyConfiguration.RootDirectory, directorySearchFilter, fileSearchFilter);
foreach (string[] files in filesCollection)
{
if (!files.Any())
continue;
directory = Path.GetDirectoryName(files.First());
if (directory is null)
continue;
if (!directoryToItems.TryGetValue(directory, out items))
{
directoryToItems.Add(directory, new());
if (!directoryToItems.TryGetValue(directory, out items))
throw new Exception();
}
}
List<Models.FilePair> filePairs = GetFilePairs(propertyConfiguration, directorySearchFilter, extension, aPropertySingletonDirectory, filesCollection);
List<FilePair> collection = GetFilePairs(propertyConfiguration, aPropertySingletonDirectory, extension, filePairs);
foreach (FilePair filePair in collection)
{
if (filePair.Directory is null)
continue;
if (!directoryToItems.TryGetValue(filePair.Directory, out items))
{
directoryToItems.Add(filePair.Directory, new());
if (!directoryToItems.TryGetValue(filePair.Directory, out items))
throw new Exception();
}
items.Add(filePair.Item);
}
foreach (KeyValuePair<string, List<Models.Item>> keyValuePair in directoryToItems)
{
if (!keyValuePair.Value.Any())
continue;
container = new(keyValuePair.Key, keyValuePair.Value);
results.Add(container);
}
return (collection.Count, results.ToArray());
}
}

View File

@ -42,90 +42,4 @@ internal abstract class FileHolder
}
}
internal static (int t, List<(int g, string sourceDirectory, string[] sourceDirectoryFiles)>) GetGroupCollection(string rootDirectory, int maxImagesInDirectoryForTopLevelFirstPass, bool reverse, string searchPattern, List<string> topDirectories)
{
int result = 0;
List<(int g, string sourceDirectory, string[] sourceDirectoryFiles)> results = new();
string? parentDirectory;
string[] subDirectories;
string[] sourceDirectoryFiles;
List<string[]> 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);
}
}

View File

@ -23,4 +23,14 @@ public interface IContainer
static Models.Container[] SortContainers(Properties.IPropertyConfiguration propertyConfiguration, string[] ignoreRelativePaths, bool argZeroIsConfigurationRootDirectory, string argZero, Models.Container[] containers) =>
Container.SortContainers(propertyConfiguration, ignoreRelativePaths, argZeroIsConfigurationRootDirectory, argZero, containers);
List<FilePair> TestStatic_GetFilePairs(Properties.IPropertyConfiguration propertyConfiguration, string directorySearchFilter, string extension, string aPropertySingletonDirectory, List<string[]> filesCollection) =>
Container.GetFilePairs(propertyConfiguration, directorySearchFilter, extension, aPropertySingletonDirectory, filesCollection);
static List<FilePair> GetFilePairs(Properties.IPropertyConfiguration propertyConfiguration, string directorySearchFilter, string extension, string aPropertySingletonDirectory, List<string[]> filesCollection) =>
Container.GetFilePairs(propertyConfiguration, directorySearchFilter, extension, aPropertySingletonDirectory, filesCollection);
(int, Models.Container[]) TestStatic_GetContainers(Properties.IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory) =>
GetContainers(propertyConfiguration, aPropertySingletonDirectory);
static (int, Models.Container[]) GetContainers(Properties.IPropertyConfiguration propertyConfiguration, string aPropertySingletonDirectory) =>
Container.GetContainers(propertyConfiguration, aPropertySingletonDirectory);
}

View File

@ -0,0 +1,39 @@
namespace View_by_Distance.Shared.Models.Stateless.Methods;
public interface IDirectory
{
char TestStatic_GetDirectory(string fileName) =>
GetDirectory(fileName);
static char GetDirectory(string fileName) => fileName.Split('-').Length > 2 ? '-' : fileName.Split('.')[0][^1];
int TestStatic_GetDirectory(char directory) =>
GetDirectory(directory);
static int GetDirectory(char directory) => directory == '-' ? 10 : int.Parse(directory.ToString());
List<string[]> TestStatic_GetFilesCollection(string directory, string directorySearchFilter, string fileSearchFilter) =>
GetFilesCollection(directory, directorySearchFilter, fileSearchFilter);
static List<string[]> GetFilesCollection(string directory, string directorySearchFilter, string fileSearchFilter) =>
XDirectory.GetFilesCollection(directory, directorySearchFilter, fileSearchFilter);
IReadOnlyDictionary<string, List<string>> TestStatic_GetFilesKeyValuePairs(List<string[]> filesCollection) =>
GetFilesKeyValuePairs(filesCollection);
static IReadOnlyDictionary<string, List<string>> GetFilesKeyValuePairs(List<string[]> filesCollection) =>
XDirectory.GetFilesKeyValuePairs(filesCollection);
int TestStatic_LookForAbandoned(List<string[]> jsonFilesCollection, IReadOnlyDictionary<string, List<string>> fileNamesToFiles, string extension) =>
LookForAbandoned(jsonFilesCollection, fileNamesToFiles, extension);
static int LookForAbandoned(List<string[]> jsonFilesCollection, IReadOnlyDictionary<string, List<string>> fileNamesToFiles, string extension) =>
XDirectory.LookForAbandoned(jsonFilesCollection, fileNamesToFiles, extension);
int TestStatic_MaybeMove(string directory, string resultAllInOne, List<FilePair> filePairs, string jsonGroupDirectory, string extension) =>
MaybeMove(directory, resultAllInOne, filePairs, jsonGroupDirectory, extension);
static int MaybeMove(string directory, string resultAllInOne, List<FilePair> filePairs, string jsonGroupDirectory, string extension) =>
XDirectory.MaybeMove(directory, resultAllInOne, filePairs, jsonGroupDirectory, extension);
List<FilePair> TestStatic_GetFiles(List<string[]> filesCollection, IReadOnlyDictionary<string, List<string>> fileNamesToFiles, string extension, IReadOnlyDictionary<string, List<string>> compareFileNamesToFiles) =>
GetFiles(filesCollection, fileNamesToFiles, extension, compareFileNamesToFiles);
static List<FilePair> GetFiles(List<string[]> filesCollection, IReadOnlyDictionary<string, List<string>> fileNamesToFiles, string extension, IReadOnlyDictionary<string, List<string>> compareFileNamesToFiles) =>
XDirectory.GetFiles(filesCollection, fileNamesToFiles, extension, compareFileNamesToFiles);
}

View File

@ -23,9 +23,4 @@ public interface IFileHolder
static Models.FileHolder Refresh(Models.FileHolder fileHolder) =>
new(fileHolder.FullName);
(int t, List<(int g, string sourceDirectory, string[] sourceDirectoryFiles)>) TestStatic_GetGroupCollection(string rootDirectory, int maxImagesInDirectoryForTopLevelFirstPass, bool reverse, string searchPattern, List<string> topDirectories) =>
GetGroupCollection(rootDirectory, maxImagesInDirectoryForTopLevelFirstPass, reverse, searchPattern, topDirectories);
static (int t, List<(int g, string sourceDirectory, string[] sourceDirectoryFiles)>) GetGroupCollection(string rootDirectory, int maxImagesInDirectoryForTopLevelFirstPass, bool reverse, string searchPattern, List<string> topDirectories) =>
FileHolder.GetGroupCollection(rootDirectory, maxImagesInDirectoryForTopLevelFirstPass, reverse, searchPattern, topDirectories);
}

View File

@ -0,0 +1,243 @@
namespace View_by_Distance.Shared.Models.Stateless.Methods;
internal abstract partial class XDirectory
{
private static int GetCeilingAverage(List<string[]> fileCollection)
{
List<int> counts = new();
foreach (string[] files in fileCollection)
counts.Add(files.Length);
int average = (int)Math.Ceiling(counts.Average());
return average;
}
private static List<string[]> GetFilesCollection(List<string[]> fileCollection, int ceilingAverage)
{
List<string[]> results = new();
foreach (string[] files in fileCollection)
{
if (files.Length < ceilingAverage)
results.Add(files);
}
foreach (string[] files in fileCollection)
{
if (files.Length >= ceilingAverage)
results.Add(files);
}
return results;
}
internal static List<string[]> GetFilesCollection(string directory, string directorySearchFilter, string fileSearchFilter)
{
List<string[]> results = new();
if (!fileSearchFilter.Contains('*'))
fileSearchFilter = string.Concat('*', fileSearchFilter);
if (!directorySearchFilter.Contains('*'))
directorySearchFilter = string.Concat('*', directorySearchFilter);
string[] directories = Directory.GetDirectories(directory, directorySearchFilter, SearchOption.TopDirectoryOnly);
foreach (string innerDirectory in directories)
results.Add(Directory.GetFiles(innerDirectory, fileSearchFilter, SearchOption.AllDirectories));
int ceilingAverage = GetCeilingAverage(results);
results = GetFilesCollection(results, ceilingAverage);
return results;
}
internal static IReadOnlyDictionary<string, List<string>> GetFilesKeyValuePairs(List<string[]> filesCollection)
{
Dictionary<string, List<string>> results = new();
string fileName;
List<string>? collection;
foreach (string[] files in filesCollection)
{
foreach (string file in files)
{
fileName = Path.GetFileName(file);
if (!results.TryGetValue(fileName, out collection))
{
results.Add(fileName, new());
if (!results.TryGetValue(fileName, out collection))
throw new Exception();
}
collection.Add(file);
}
}
return results;
}
internal static int LookForAbandoned(List<string[]> jsonFilesCollection, IReadOnlyDictionary<string, List<string>> fileNamesToFiles, string extension)
{
string fileName;
List<string>? collection;
int length = extension.Length;
List<(string, string)> rename = new();
foreach (string[] files in jsonFilesCollection)
{
foreach (string file in files)
{
fileName = Path.GetFileName(file);
if (fileName.Length < length || !fileName.EndsWith(extension))
throw new Exception();
if (!fileNamesToFiles.TryGetValue(fileName[..^length], out collection))
rename.Add(new(file, string.Concat(file, ".del")));
}
}
foreach ((string from, string to) in rename)
{
if (File.Exists(to))
continue;
File.Move(from, to);
}
return rename.Count;
}
private static void IsNotUniqueLoop(string file, List<string> collection)
{
TimeSpan timeSpan;
FileInfo possibleFileInfo;
FileInfo fileInfo = new(file);
foreach (string possible in collection)
{
possibleFileInfo = new(possible);
if (possibleFileInfo.LastWriteTime == fileInfo.LastWriteTime && possibleFileInfo.Length == fileInfo.Length)
continue;
timeSpan = new(possibleFileInfo.LastWriteTime.Ticks - fileInfo.LastWriteTime.Ticks);
if (timeSpan.TotalMinutes < 2 && possibleFileInfo.Length == fileInfo.Length)
{
File.SetLastWriteTime(file, new DateTime[] { possibleFileInfo.LastWriteTime, fileInfo.LastWriteTime }.Min());
continue;
}
throw new Exception();
}
}
private static string? GetMatch(string file, List<string> collection)
{
string? result = null;
FileInfo possibleFileInfo;
List<long> lengths = new();
List<string> matches = new();
FileInfo fileInfo = new(file);
List<DateTime> creationTimes = new();
foreach (string possible in collection)
{
possibleFileInfo = new(possible);
lengths.Add(possibleFileInfo.Length);
creationTimes.Add(possibleFileInfo.CreationTime);
if (possibleFileInfo.CreationTime != fileInfo.LastWriteTime)
continue;
matches.Add(possible);
}
if (matches.Count == 1 || (lengths.Distinct().Count() == 1 && creationTimes.Distinct().Count() == 1))
result = matches.First();
return result;
}
internal static List<FilePair> GetFiles(List<string[]> filesCollection, IReadOnlyDictionary<string, List<string>> fileNamesToFiles, string extension, IReadOnlyDictionary<string, List<string>> compareFileNamesToFiles)
{
List<FilePair> results = new();
string? match;
string fileName;
bool uniqueFileName;
List<string>? collection;
foreach (string[] files in filesCollection)
{
foreach (string file in files)
{
fileName = Path.GetFileName(file);
if (!fileNamesToFiles.TryGetValue(fileName, out collection))
throw new Exception();
uniqueFileName = collection.Count == 1;
if (!uniqueFileName)
IsNotUniqueLoop(file, collection);
if (!compareFileNamesToFiles.TryGetValue(string.Concat(fileName, extension), out collection))
results.Add(new(file, uniqueFileName, new(), null));
else
{
if (!collection.Any())
results.Add(new(file, uniqueFileName, collection, null));
else if (uniqueFileName && collection.Count == 1)
results.Add(new(file, uniqueFileName, collection, collection.First()));
else
{
match = GetMatch(file, collection);
results.Add(new(file, uniqueFileName, collection, match));
}
}
}
}
return results;
}
private static void IsUniqueLoop(string resultAllInOne, string resultAllInOneDirectory, FilePair item, List<(string, string)> rename)
{
char directory;
string fileName;
foreach (string path in item.Collection)
{
if (path.Contains(resultAllInOne))
continue;
fileName = Path.GetFileName(path);
directory = IDirectory.GetDirectory(fileName);
rename.Add(new(path, Path.Combine(resultAllInOneDirectory, directory.ToString(), fileName)));
}
}
private static void IsNotUniqueLoop(string directory, string resultAllInOne, string jsonGroupDirectory, string extension, FilePair item, List<(string, string)> rename)
{
int length = directory.Length;
foreach (string path in item.Collection)
{
if (!path.Contains(resultAllInOne))
continue;
if (item.Match is null || path != item.Match)
continue;
rename.Add(new(path, string.Concat(jsonGroupDirectory, item.Path[length..], extension)));
}
}
internal static int MaybeMove(string directory, string resultAllInOne, List<FilePair> filePairs, string jsonGroupDirectory, string extension)
{
FileInfo? toFileInfo;
FileInfo fromFileInfo;
string checkDirectory;
List<(string, string)> rename = new();
string resultAllInOneDirectory = Path.Combine(jsonGroupDirectory, resultAllInOne);
foreach (FilePair item in filePairs)
{
if (item.IsUnique)
IsUniqueLoop(resultAllInOne, resultAllInOneDirectory, item, rename);
else
IsNotUniqueLoop(directory, resultAllInOne, jsonGroupDirectory, extension, item, rename);
}
foreach ((string from, string to) in rename)
{
toFileInfo = null;
checkDirectory = to;
fromFileInfo = new(from);
if (!fromFileInfo.Exists)
continue;
for (int i = 0; i < int.MaxValue; i++)
{
toFileInfo = new(checkDirectory);
if (toFileInfo.Directory is null)
continue;
if (!toFileInfo.Directory.Exists)
_ = Directory.CreateDirectory(toFileInfo.Directory.FullName);
if (checkDirectory.Length > 199)
throw new Exception();
if (!toFileInfo.Exists)
break;
else if (fromFileInfo.Length == toFileInfo.Length && fromFileInfo.LastWriteTime == toFileInfo.LastWriteTime)
checkDirectory = string.Concat(checkDirectory, ".del");
else
checkDirectory = string.Concat(checkDirectory, ".i");
}
File.Move(from, checkDirectory);
}
_ = IPath.DeleteEmptyDirectories(jsonGroupDirectory);
return rename.Count;
}
}