2023-07-09 00:26:58 -07:00

443 lines
19 KiB
C#

namespace View_by_Distance.Shared.Models.Stateless.Methods;
internal abstract partial class XDirectory
{
private record SortedRecord(int? Id, Models.FileHolder FileHolder);
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);
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.Any() ? 0 : 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;
string fileNameWith;
List<string>? collection;
string fileNameUpperExtension;
int length = extension.Length;
List<string> renameCollection = new();
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.Any())
IDirectory.MoveFiles(renameCollection, "{}", "{abd}");
return renameCollection.Count;
}
private static bool GetIsNotUniqueAndNeedsReview(string file, List<string> 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<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 || (matches.Any() && 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;
bool? isNotUniqueAndNeedsReview;
foreach (string[] files in filesCollection)
{
foreach (string file in files)
{
isNotUniqueAndNeedsReview = null;
fileName = Path.GetFileName(file);
if (!fileNamesToFiles.TryGetValue(fileName, out collection))
throw new Exception();
uniqueFileName = collection.Count == 1;
if (!uniqueFileName)
isNotUniqueAndNeedsReview = GetIsNotUniqueAndNeedsReview(file, collection);
if (!compareFileNamesToFiles.TryGetValue(string.Concat(fileName, extension), out collection))
results.Add(new(file, uniqueFileName, isNotUniqueAndNeedsReview, new(), null));
else
{
if (!collection.Any())
results.Add(new(file, uniqueFileName, isNotUniqueAndNeedsReview, collection, null));
else if (uniqueFileName && collection.Count == 1)
results.Add(new(file, uniqueFileName, isNotUniqueAndNeedsReview, collection, collection.First()));
else
{
match = GetMatch(file, collection);
results.Add(new(file, uniqueFileName, isNotUniqueAndNeedsReview, collection, match));
}
}
}
}
return results;
}
private static void IsUniqueLoop(string resultAllInOne, string resultAllInOneDirectory, int resultAllInOneSubdirectoryLength, FilePair item, List<(string, string)> rename)
{
string fileName;
string directoryName;
foreach (string path in item.Collection)
{
if (path.Contains(resultAllInOne))
continue;
fileName = Path.GetFileName(path);
(directoryName, _) = IPath.GetDirectoryNameAndIndex(resultAllInOneSubdirectoryLength, fileName);
rename.Add(new(path, Path.Combine(resultAllInOneDirectory, directoryName, 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, int resultAllInOneSubdirectoryLength, 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, resultAllInOneSubdirectoryLength, 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);
}
return rename.Count;
}
internal static void MoveFiles(List<string> files, string find, string replace)
{
string checkFile;
string? checkDirectory;
List<string> directories = new();
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))
continue;
File.Move(file, checkFile);
}
}
private static (bool, SortedRecord[]) GetSortedRecords(List<string[]> filesCollection)
{
bool result = true;
List<SortedRecord> results = new();
int? id;
short? multiplier;
char negativeMarker;
int absoluteValueOfId;
Models.FileHolder fileHolder;
int offset = IDirectory.GetOffset();
int offsetLength = offset.ToString().Length;
int sortOrderOnlyLengthIndex = offsetLength + 3;
foreach (string[] files in filesCollection)
{
foreach (string file in files)
{
fileHolder = new Models.FileHolder(file);
if (!result)
multiplier = null;
else
{
if (fileHolder.NameWithoutExtension.Length < sortOrderOnlyLengthIndex)
{
result = false;
multiplier = null;
}
else
{
negativeMarker = fileHolder.NameWithoutExtension[sortOrderOnlyLengthIndex - 2];
if (negativeMarker == '7')
multiplier = 1;
else if (negativeMarker == '3')
multiplier = -1;
else
{
result = false;
multiplier = null;
}
}
}
if (!result)
id = null;
else if (!int.TryParse(fileHolder.NameWithoutExtension[sortOrderOnlyLengthIndex..], out absoluteValueOfId))
id = null;
else
id = absoluteValueOfId * multiplier;
results.Add(new(id, fileHolder));
}
}
return new(result, (from l in results orderby l.FileHolder.LastWriteTime, l.FileHolder.FullName.Length descending select l).ToArray());
}
internal static (string[], List<(Models.FileHolder, string)>) GetToDoCollection(Properties.IPropertyConfiguration propertyConfiguration, bool copyDuplicates, bool ifCanUseId, List<string[]> filesCollection, string[] directories, Action? tick)
{
List<(Models.FileHolder, string)> results = new();
string checkFile;
string directory;
FileInfo fileInfo;
int directoryIndex;
string directoryName;
bool wrapped = false;
List<int> distinctIds = new();
List<string> distinct = new();
List<string> distinctDirectories = new();
(bool all, SortedRecord[] sortedRecords) = GetSortedRecords(filesCollection);
foreach (SortedRecord sortedRecord in sortedRecords)
{
tick?.Invoke();
if (sortedRecord.FileHolder.Name.EndsWith("len") || sortedRecord.FileHolder.ExtensionLowered == ".id" || sortedRecord.FileHolder.ExtensionLowered == ".lsv" || sortedRecord.FileHolder.DirectoryName is null)
continue;
(_, directoryIndex) = IPath.GetDirectoryNameAndIndex(propertyConfiguration.ResultAllInOneSubdirectoryLength, sortedRecord.FileHolder.NameWithoutExtension);
directoryName = Path.GetFileName(sortedRecord.FileHolder.DirectoryName);
if (directoryName.Length < propertyConfiguration.ResultAllInOneSubdirectoryLength + 3 || !sortedRecord.FileHolder.Name.StartsWith(directoryName))
{
if (wrapped)
continue;
directory = directories[directoryIndex];
}
else
{
if (!wrapped)
wrapped = true;
directory = Path.Combine(directories[directoryIndex], directoryName);
}
if (all)
{
if (sortedRecord.Id is null || !sortedRecord.FileHolder.NameWithoutExtension.EndsWith(sortedRecord.Id.Value.ToString()[1..]))
throw new NotSupportedException();
}
if (all && ifCanUseId)
checkFile = Path.Combine(directory, $"{sortedRecord.Id}{sortedRecord.FileHolder.ExtensionLowered}");
else
checkFile = Path.Combine(directory, $"{sortedRecord.FileHolder.NameWithoutExtension}{sortedRecord.FileHolder.ExtensionLowered}");
if ((sortedRecord.Id is not null && distinctIds.Contains(sortedRecord.Id.Value)) || distinct.Contains(checkFile))
{
if (string.IsNullOrEmpty(sortedRecord.FileHolder.DirectoryName))
continue;
if (!copyDuplicates)
continue;
for (int i = 1; i < int.MaxValue; i++)
{
fileInfo = new(checkFile);
if (!fileInfo.Exists || sortedRecord.FileHolder.Length == fileInfo.Length && sortedRecord.FileHolder.LastWriteTime == fileInfo.LastWriteTime)
checkFile = Path.Combine(directory, $"{sortedRecord.FileHolder.NameWithoutExtension}.{i}dup{sortedRecord.FileHolder.ExtensionLowered}");
else
checkFile = Path.Combine(directory, $"{sortedRecord.FileHolder.NameWithoutExtension}.{i}why{sortedRecord.FileHolder.ExtensionLowered}");
if (sortedRecord.Id is not null)
{
if (distinctIds.Contains(sortedRecord.Id.Value))
continue;
distinctIds.Add(sortedRecord.Id.Value);
}
if (distinct.Contains(checkFile))
continue;
distinct.Add(checkFile);
results.Add(new(sortedRecord.FileHolder, checkFile));
if (!distinctDirectories.Contains(directory))
distinctDirectories.Add(directory);
break;
}
continue;
}
distinct.Add(checkFile);
if (sortedRecord.Id is not null)
distinctIds.Add(sortedRecord.Id.Value);
results.Add(new(sortedRecord.FileHolder, checkFile));
if (!distinctDirectories.Contains(directory))
distinctDirectories.Add(directory);
}
return (distinctDirectories.ToArray(), results);
}
internal static List<string> CopyOrMove(List<(Models.FileHolder, string)> toDoCollection, bool move, bool moveBack, Action? tick)
{
List<string> results = new();
FileInfo fileInfo;
foreach ((Models.FileHolder fileHolder, string to) in toDoCollection)
{
tick?.Invoke();
fileInfo = new(to);
if (fileInfo.Exists)
{
if (fileHolder.Length != fileInfo.Length || fileHolder.LastWriteTime != fileInfo.LastWriteTime)
fileInfo.Delete();
else
continue;
}
results.Add(fileHolder.NameWithoutExtension);
try
{
if (move || moveBack)
File.Move(fileHolder.FullName, to);
else
File.Copy(fileHolder.FullName, to);
}
catch (Exception) { }
}
return results;
}
}