using System.Collections.ObjectModel; namespace View_by_Distance.Shared.Models.Stateless.Methods; internal abstract partial class XDirectory { private static int GetCeilingAverage(List fileCollection) { List counts = []; foreach (string[] files in fileCollection) counts.Add(files.Length); int average = (int)Math.Ceiling(counts.Average()); return average; } private static List GetFilesCollection(List fileCollection, int ceilingAverage) { List results = []; 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 ReadOnlyCollection GetFilesCollection(string directory, string directorySearchFilter, string fileSearchFilter, bool useCeilingAverage) { List results = []; if (!fileSearchFilter.Contains('*')) fileSearchFilter = string.Concat('*', fileSearchFilter); if (!directorySearchFilter.Contains('*')) directorySearchFilter = string.Concat('*', directorySearchFilter); if (!Directory.Exists(directory)) _ = Directory.CreateDirectory(directory); results.Add(Directory.GetFiles(directory, fileSearchFilter, SearchOption.TopDirectoryOnly)); string[] directories = Directory.GetDirectories(directory, directorySearchFilter, SearchOption.TopDirectoryOnly); foreach (string innerDirectory in directories) { try { results.Add(Directory.GetFiles(innerDirectory, fileSearchFilter, SearchOption.AllDirectories)); } catch (UnauthorizedAccessException) { continue; } } int ceilingAverage = directory[^1] == '_' || results.Count == 0 ? 0 : GetCeilingAverage(results); if (useCeilingAverage) results = GetFilesCollection(results, ceilingAverage); return new(results); } internal static ReadOnlyCollection> GetFilePathCollections(Properties.IPropertyConfiguration propertyConfiguration, string directory, string directorySearchFilter, string fileSearchFilter, bool useCeilingAverage) { ReadOnlyCollection> results; ReadOnlyCollection filesCollection = GetFilesCollection(directory, directorySearchFilter, fileSearchFilter, useCeilingAverage); results = IDirectory.GetFilePathCollections(propertyConfiguration, filesCollection); return results; } internal static IReadOnlyDictionary> GetFilesKeyValuePairs(ReadOnlyCollection filesCollection) { Dictionary> results = []; string fileName; List? collection; foreach (string[] files in filesCollection) { foreach (string file in files) { fileName = Path.GetFileName(file); if (!results.TryGetValue(fileName, out collection)) { results.Add(fileName, []); if (!results.TryGetValue(fileName, out collection)) throw new Exception(); } collection.Add(file); } } return results; } internal static IReadOnlyDictionary> GetFilesKeyValuePairs(ReadOnlyCollection> filePathsCollection) { Dictionary> results = []; List? collection; foreach (ReadOnlyCollection filePaths in filePathsCollection) { foreach (FilePath filePath in filePaths) { if (!results.TryGetValue(filePath.Name, out collection)) { results.Add(filePath.Name, []); if (!results.TryGetValue(filePath.Name, out collection)) throw new Exception(); } collection.Add(filePath.FullName); } } return results; } internal static int LookForAbandoned(ReadOnlyCollection jsonFilesCollection, IReadOnlyDictionary> fileNamesToFiles, string extension) { string fileName; string fileNameWith; List? collection; string fileNameUpperExtension; int length = extension.Length; List renameCollection = []; foreach (string[] files in jsonFilesCollection) { foreach (string file in files) { fileNameWith = Path.GetFileName(file); if (fileNameWith.Length < length || !fileNameWith.EndsWith(extension)) throw new Exception(); fileName = fileNameWith[..^length]; if (!fileNamesToFiles.TryGetValue(fileName, out collection)) { fileNameUpperExtension = string.Concat(Path.GetFileNameWithoutExtension(fileName), Path.GetExtension(fileName).ToUpper()); if (fileName == fileNameUpperExtension || !fileNamesToFiles.TryGetValue(fileNameUpperExtension, out collection)) renameCollection.Add(file); } } } if (renameCollection.Count > 0) IDirectory.MoveFiles(renameCollection, "{}", "{abd}"); return renameCollection.Count; } private static bool GetIsNotUniqueAndNeedsReview(string file, List collection) { bool result = false; FileInfo possibleFileInfo; FileInfo fileInfo = new(file); foreach (string possible in collection) { if (possible == file) continue; possibleFileInfo = new(possible); if (possibleFileInfo.LastWriteTime != fileInfo.LastWriteTime) File.SetLastWriteTime(file, new DateTime[] { possibleFileInfo.LastWriteTime, fileInfo.LastWriteTime }.Max()); if (possibleFileInfo.LastWriteTime == fileInfo.LastWriteTime && possibleFileInfo.Length == fileInfo.Length) continue; if (!result) result = true; } return result; } private static string? GetMatch(string file, List collection) { string? result = null; FileInfo possibleFileInfo; List lengths = []; List matches = []; FileInfo fileInfo = new(file); List creationTimes = []; 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 || (matches.Count > 0 && lengths.Distinct().Count() == 1 && creationTimes.Distinct().Count() == 1)) result = matches.First(); return result; } internal static List GetFiles(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection> filePathsCollection, IReadOnlyDictionary> fileNamesToFiles, string extension, IReadOnlyDictionary> compareFileNamesToFiles) { List results = []; string? match; bool uniqueFileName; List? collection; bool? isNotUniqueAndNeedsReview; foreach (ReadOnlyCollection filePaths in filePathsCollection) { foreach (FilePath filePath in filePaths) { isNotUniqueAndNeedsReview = null; if (propertyConfiguration.IgnoreExtensions.Contains(filePath.ExtensionLowered)) continue; if (!fileNamesToFiles.TryGetValue(filePath.Name, out collection)) throw new Exception(); uniqueFileName = collection.Count == 1; if (!uniqueFileName) isNotUniqueAndNeedsReview = GetIsNotUniqueAndNeedsReview(filePath.FullName, collection); if (!compareFileNamesToFiles.TryGetValue(string.Concat(filePath.Name, extension), out collection)) results.Add(new(filePath.FullName, uniqueFileName, isNotUniqueAndNeedsReview, [], null)); else { if (collection.Count == 0) results.Add(new(filePath.FullName, uniqueFileName, isNotUniqueAndNeedsReview, collection, null)); else if (uniqueFileName && collection.Count == 1) results.Add(new(filePath.FullName, uniqueFileName, isNotUniqueAndNeedsReview, collection, collection.First())); else { match = GetMatch(filePath.FullName, collection); results.Add(new(filePath.FullName, uniqueFileName, isNotUniqueAndNeedsReview, collection, match)); } } } } return results; } private static void IsNotUniqueLoop(Properties.IPropertyConfiguration propertyConfiguration, string jsonGroupDirectory, string extension, FilePair filePair, List<(string, string)> rename) { int length = propertyConfiguration.RootDirectory.Length; foreach (string path in filePair.Collection) { if (filePair.Match is null || path != filePair.Match) continue; rename.Add(new(path, string.Concat(jsonGroupDirectory, filePair.Path[length..], extension))); } } internal static int MaybeMove(Properties.IPropertyConfiguration propertyConfiguration, List filePairs, string jsonGroupDirectory, string extension) { FileInfo? toFileInfo; FileInfo fromFileInfo; string checkDirectory; List<(string, string)> rename = []; foreach (FilePair filePair in filePairs) { if (filePair.IsUnique) continue; IsNotUniqueLoop(propertyConfiguration, jsonGroupDirectory, extension, filePair, 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, ".j"); } File.Move(from, checkDirectory); } return rename.Count; } internal static void MoveFiles(List files, string find, string replace) { string checkFile; string? checkDirectory; List directories = []; foreach (string file in files) { checkDirectory = Path.GetDirectoryName(file.Replace(find, replace)); if (string.IsNullOrEmpty(checkDirectory) || directories.Contains(checkDirectory)) continue; directories.Add(checkDirectory); } foreach (string directory in directories) { if (Directory.Exists(directory)) continue; _ = Directory.CreateDirectory(directory); } foreach (string file in files) { if (!File.Exists(file)) continue; checkFile = file.Replace(find, replace); if (File.Exists(checkFile)) { File.Delete(checkFile); continue; } File.Move(file, checkFile); } } private static FilePath[] GetSortedRecords(ReadOnlyCollection> filePathsCollection) { List results = []; foreach (ReadOnlyCollection filePaths in filePathsCollection) { foreach (FilePath filePath in filePaths) results.Add(filePath); } return (from l in results orderby l.CreationTicks, l.FullName.Length descending select l).ToArray(); } internal static ReadOnlyCollection> GetFilePathCollections(Properties.IPropertyConfiguration propertyConfiguration, ReadOnlyCollection filesCollection) { List> results = []; FilePath filePath; List filePaths; Models.FileHolder fileHolder; foreach (string[] files in filesCollection) { filePaths = []; foreach (string file in files) { fileHolder = IFileHolder.Get(file); if (propertyConfiguration.IgnoreExtensions.Contains(fileHolder.ExtensionLowered)) continue; filePath = FilePath.Get(propertyConfiguration, fileHolder, index: null); filePaths.Add(filePath); } results.Add(new(filePaths)); } return new(results); } internal static (string[], List<(FilePath, string)>) GetToDoCollection(Properties.IPropertyConfiguration propertyConfiguration, bool copyDuplicates, bool ifCanUseId, ReadOnlyCollection> filePathsCollection, IReadOnlyDictionary> fileGroups, Action? tick) { List<(FilePath, string)> results = []; string key; string paddedId; string checkFile; string directory; FileInfo fileInfo; FilePath filePath; int directoryIndex; string paddedIdFile; bool wrapped = false; string intelligentId; bool paddedCheck = false; string fileDirectoryName; List distinctIds = []; List distinct = []; Models.FileHolder fileHolder; List distinctDirectories = []; ReadOnlyCollection? directories; FilePath[] sortedRecords = GetSortedRecords(filePathsCollection); bool isOffsetDeterministicHashCode = IId.IsOffsetDeterministicHashCode(propertyConfiguration); for (int i = 0; i < sortedRecords.Length; i++) { tick?.Invoke(); filePath = sortedRecords[i]; if (filePath.Name.EndsWith("len") || filePath.ExtensionLowered == ".id" || filePath.ExtensionLowered == ".lsv" || filePath.DirectoryFullPath is null) continue; key = propertyConfiguration.ValidVideoFormatExtensions.Contains(filePath.ExtensionLowered) ? propertyConfiguration.ResultContentCollection : propertyConfiguration.ResultContent; if (!fileGroups.TryGetValue(key, out directories)) continue; (_, directoryIndex) = IPath.GetDirectoryNameAndIndex(propertyConfiguration, filePath); fileDirectoryName = Path.GetFileName(filePath.DirectoryFullPath); if (fileDirectoryName.Length < propertyConfiguration.ResultAllInOneSubdirectoryLength + 3 || !filePath.Name.StartsWith(fileDirectoryName)) { if (wrapped) continue; directory = directories[directoryIndex]; } else { if (!wrapped) wrapped = true; directory = Path.Combine(directories[directoryIndex], fileDirectoryName); } if (ifCanUseId && filePath.IsIntelligentIdFormat && filePath.Id is not null && filePath.DirectoryFullPath is not null) { paddedId = IId.GetPaddedId(propertyConfiguration, filePath.Id.Value, filePath.HasIgnoreKeyword, filePath.HasDateTimeOriginal, i); paddedIdFile = Path.Combine(filePath.DirectoryFullPath, $"{paddedId}{filePath.ExtensionLowered}"); if (!File.Exists(paddedIdFile)) { File.Move(filePath.FullName, paddedIdFile); fileInfo = new(paddedIdFile); fileHolder = Models.FileHolder.Get(fileInfo); filePath = FilePath.Get(propertyConfiguration, fileHolder, index: null); if (!paddedCheck) paddedCheck = true; } } if (filePath.IsIntelligentIdFormat || !ifCanUseId) checkFile = Path.Combine(directory, $"{filePath.NameWithoutExtension}{filePath.ExtensionLowered}"); else { if (filePath.Id is null) throw new NullReferenceException(nameof(filePath.Id)); intelligentId = IId.GetIntelligentId(propertyConfiguration, filePath.Id.Value, filePath.HasIgnoreKeyword, filePath.HasDateTimeOriginal); if (!isOffsetDeterministicHashCode) checkFile = Path.Combine(directory, $"{intelligentId}{filePath.ExtensionLowered}"); else { if (filePath.DirectoryFullPath is null) continue; paddedId = IId.GetPaddedId(propertyConfiguration, filePath.Id.Value, filePath.HasIgnoreKeyword, filePath.HasDateTimeOriginal, i); paddedIdFile = Path.Combine(filePath.DirectoryFullPath, $"{paddedId}{filePath.ExtensionLowered}"); if (File.Exists(paddedIdFile)) continue; File.Move(filePath.FullName, paddedIdFile); if (!paddedCheck) paddedCheck = true; continue; } } if ((filePath.Id is not null && distinctIds.Contains(filePath.Id.Value)) || distinct.Contains(checkFile)) { if (string.IsNullOrEmpty(filePath.DirectoryFullPath)) continue; if (!copyDuplicates) continue; for (int j = 1; j < int.MaxValue; j++) { fileInfo = new(checkFile); if (!fileInfo.Exists || filePath.Length == fileInfo.Length && filePath.LastWriteTicks == fileInfo.LastWriteTime.Ticks) checkFile = Path.Combine(directory, $"{filePath.NameWithoutExtension}.{j}dup{filePath.ExtensionLowered}"); else checkFile = Path.Combine(directory, $"{filePath.NameWithoutExtension}.{j}why{filePath.ExtensionLowered}"); if (filePath.Id is not null) { if (distinctIds.Contains(filePath.Id.Value)) continue; distinctIds.Add(filePath.Id.Value); } if (distinct.Contains(checkFile)) continue; distinct.Add(checkFile); results.Add(new(filePath, checkFile)); if (!distinctDirectories.Contains(directory)) distinctDirectories.Add(directory); break; } continue; } distinct.Add(checkFile); if (filePath.Id is not null) distinctIds.Add(filePath.Id.Value); results.Add(new(filePath, checkFile)); if (!distinctDirectories.Contains(directory)) distinctDirectories.Add(directory); } if (!isOffsetDeterministicHashCode) throw new Exception("Change Configuration Offset after creating iso file with images sorted!"); if (paddedCheck) throw new Exception("Maybe need to restart application!"); return (distinctDirectories.ToArray(), results); } internal static List CopyOrMove(List<(FilePath, string)> toDoCollection, bool move, bool moveBack, Action? tick) { List results = []; FileInfo fileInfo; foreach ((FilePath filePath, string to) in toDoCollection) { tick?.Invoke(); fileInfo = new(to); if (fileInfo.Exists) { if (filePath.Length == fileInfo.Length && filePath.LastWriteTicks == fileInfo.LastWriteTime.Ticks) continue; fileInfo.Delete(); } results.Add(filePath.NameWithoutExtension); try { if (move || moveBack) File.Move(filePath.FullName, to); else File.Copy(filePath.FullName, to); } catch (Exception) { } } return results; } }