487 lines
21 KiB
C#
487 lines
21 KiB
C#
namespace View_by_Distance.Shared.Models.Stateless.Methods;
|
|
|
|
internal abstract partial class XDirectory
|
|
{
|
|
|
|
private record SortedRecord(Models.FileHolder FileHolder, bool NameWithoutExtensionIsIdFormat, int? Id);
|
|
|
|
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, bool useCeilingAverage)
|
|
{
|
|
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);
|
|
if (useCeilingAverage)
|
|
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.Count > 0)
|
|
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.Count > 0 && 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.Count == 0)
|
|
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, ".j");
|
|
}
|
|
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);
|
|
}
|
|
}
|
|
|
|
internal static (bool, int?) GetId(short sortOrderOnlyLengthIndex, Models.FileHolder fileHolder)
|
|
{
|
|
int? id;
|
|
short? multiplier;
|
|
char negativeMarker;
|
|
int absoluteValueOfId;
|
|
bool nameWithoutExtensionIsIdFormat = IProperty.NameWithoutExtensionIsIdFormat(fileHolder);
|
|
bool nameWithoutExtensionIsPaddedIdFormat = IDirectory.NameWithoutExtensionIsPaddedIdFormat(fileHolder, sortOrderOnlyLengthIndex);
|
|
if (!nameWithoutExtensionIsIdFormat && !nameWithoutExtensionIsPaddedIdFormat)
|
|
id = null;
|
|
else if (nameWithoutExtensionIsIdFormat)
|
|
{
|
|
if (!int.TryParse(fileHolder.NameWithoutExtension, out absoluteValueOfId))
|
|
id = null;
|
|
else
|
|
id = absoluteValueOfId;
|
|
}
|
|
else
|
|
{
|
|
negativeMarker = fileHolder.NameWithoutExtension[sortOrderOnlyLengthIndex - 2];
|
|
if (negativeMarker == '7')
|
|
multiplier = 1;
|
|
else if (negativeMarker == '3')
|
|
multiplier = -1;
|
|
else
|
|
multiplier = null;
|
|
if (!int.TryParse(fileHolder.NameWithoutExtension[sortOrderOnlyLengthIndex..], out absoluteValueOfId))
|
|
id = null;
|
|
else
|
|
{
|
|
id = absoluteValueOfId * multiplier;
|
|
if (id is null || !fileHolder.NameWithoutExtension.EndsWith(id.Value.ToString()[1..]))
|
|
id = null;
|
|
}
|
|
}
|
|
return (nameWithoutExtensionIsIdFormat, id);
|
|
}
|
|
|
|
private static SortedRecord[] GetSortedRecords(int offset, List<string[]> filesCollection)
|
|
{
|
|
List<SortedRecord> results = new();
|
|
int? id;
|
|
Models.FileHolder fileHolder;
|
|
bool nameWithoutExtensionIsIdFormat;
|
|
short sortOrderOnlyLengthIndex = IDirectory.GetSortOrderOnlyLengthIndex(offset);
|
|
foreach (string[] files in filesCollection)
|
|
{
|
|
foreach (string file in files)
|
|
{
|
|
fileHolder = new(file);
|
|
(nameWithoutExtensionIsIdFormat, id) = GetId(sortOrderOnlyLengthIndex, fileHolder);
|
|
results.Add(new(fileHolder, nameWithoutExtensionIsIdFormat, id));
|
|
}
|
|
}
|
|
return (from l in results orderby l.FileHolder.CreationTime, l.FileHolder.FullName.Length descending select l).ToArray();
|
|
}
|
|
|
|
internal static (string[], List<(Models.FileHolder, string?, string)>) GetToDoCollection(Properties.IPropertyConfiguration propertyConfiguration, bool copyDuplicates, bool ifCanUseId, List<string[]> filesCollection, string[] directories, Action? tick)
|
|
{
|
|
List<(Models.FileHolder, string?, string)> results = new();
|
|
string paddedId;
|
|
string checkFile;
|
|
string directory;
|
|
FileInfo fileInfo;
|
|
int directoryIndex;
|
|
string paddedIdFile;
|
|
bool wrapped = false;
|
|
string directoryName;
|
|
bool paddedCheck = false;
|
|
string fileDirectoryName;
|
|
SortedRecord sortedRecord;
|
|
string? alternateCheckFile;
|
|
string? alternateDirectory;
|
|
Models.FileHolder fileHolder;
|
|
List<int> distinctIds = new();
|
|
List<string> distinct = new();
|
|
List<string> distinctDirectories = new();
|
|
int intMinValueLength = int.MinValue.ToString().Length;
|
|
SortedRecord[] sortedRecords = GetSortedRecords(propertyConfiguration.Offset, filesCollection);
|
|
string? alternateResultAllInOne = !propertyConfiguration.ResultAllInOne.Contains(' ') ? null : propertyConfiguration.ResultAllInOne.Replace(' ', '-');
|
|
for (int i = 0; i < sortedRecords.Length; i++)
|
|
{
|
|
tick?.Invoke();
|
|
sortedRecord = sortedRecords[i];
|
|
fileHolder = sortedRecord.FileHolder;
|
|
if (fileHolder.Name.EndsWith("len") || fileHolder.ExtensionLowered == ".id" || fileHolder.ExtensionLowered == ".lsv" || fileHolder.DirectoryName is null)
|
|
continue;
|
|
(directoryName, directoryIndex) = IPath.GetDirectoryNameAndIndex(propertyConfiguration.ResultAllInOneSubdirectoryLength, fileHolder.NameWithoutExtension);
|
|
fileDirectoryName = Path.GetFileName(fileHolder.DirectoryName);
|
|
if (fileDirectoryName.Length < propertyConfiguration.ResultAllInOneSubdirectoryLength + 3 || !fileHolder.Name.StartsWith(fileDirectoryName))
|
|
{
|
|
if (wrapped)
|
|
continue;
|
|
directory = directories[directoryIndex];
|
|
if (alternateResultAllInOne is null)
|
|
alternateDirectory = null;
|
|
else
|
|
alternateDirectory = Path.Combine(Path.GetDirectoryName(Path.GetDirectoryName(directory)) ?? directory, alternateResultAllInOne, directoryName);
|
|
}
|
|
else
|
|
{
|
|
if (!wrapped)
|
|
wrapped = true;
|
|
alternateDirectory = null;
|
|
directory = Path.Combine(directories[directoryIndex], fileDirectoryName);
|
|
}
|
|
if (ifCanUseId && sortedRecord.NameWithoutExtensionIsIdFormat && sortedRecord.Id is not null && fileHolder.DirectoryName is not null)
|
|
{
|
|
paddedId = IDirectory.GetPaddedId(intMinValueLength, propertyConfiguration.Offset + i, sortedRecord.Id.Value);
|
|
paddedIdFile = Path.Combine(fileHolder.DirectoryName, $"{paddedId}{fileHolder.ExtensionLowered}");
|
|
if (!File.Exists(paddedIdFile))
|
|
{
|
|
File.Move(fileHolder.FullName, paddedIdFile);
|
|
fileHolder = new(paddedIdFile);
|
|
if (!paddedCheck)
|
|
paddedCheck = true;
|
|
}
|
|
}
|
|
if (ifCanUseId)
|
|
checkFile = Path.Combine(directory, $"{sortedRecord.Id}{fileHolder.ExtensionLowered}");
|
|
else
|
|
checkFile = Path.Combine(directory, $"{fileHolder.NameWithoutExtension}{fileHolder.ExtensionLowered}");
|
|
if ((sortedRecord.Id is not null && distinctIds.Contains(sortedRecord.Id.Value)) || distinct.Contains(checkFile))
|
|
{
|
|
if (string.IsNullOrEmpty(fileHolder.DirectoryName))
|
|
continue;
|
|
if (!copyDuplicates)
|
|
continue;
|
|
alternateDirectory = null;
|
|
for (int j = 1; j < int.MaxValue; j++)
|
|
{
|
|
fileInfo = new(checkFile);
|
|
if (!fileInfo.Exists || fileHolder.Length == fileInfo.Length && fileHolder.LastWriteTime == fileInfo.LastWriteTime)
|
|
checkFile = Path.Combine(directory, $"{fileHolder.NameWithoutExtension}.{j}dup{fileHolder.ExtensionLowered}");
|
|
else
|
|
checkFile = Path.Combine(directory, $"{fileHolder.NameWithoutExtension}.{j}why{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;
|
|
alternateCheckFile = null;
|
|
distinct.Add(checkFile);
|
|
results.Add(new(fileHolder, alternateCheckFile, checkFile));
|
|
if (!distinctDirectories.Contains(directory))
|
|
distinctDirectories.Add(directory);
|
|
break;
|
|
}
|
|
continue;
|
|
}
|
|
distinct.Add(checkFile);
|
|
if (sortedRecord.Id is not null)
|
|
distinctIds.Add(sortedRecord.Id.Value);
|
|
if (string.IsNullOrEmpty(alternateDirectory))
|
|
alternateCheckFile = null;
|
|
else
|
|
{
|
|
alternateCheckFile = Path.Combine(alternateDirectory, $"{sortedRecord.Id}{fileHolder.ExtensionLowered}.tsv");
|
|
if (!distinctDirectories.Contains(alternateDirectory))
|
|
distinctDirectories.Add(alternateDirectory);
|
|
}
|
|
results.Add(new(fileHolder, alternateCheckFile, checkFile));
|
|
if (!distinctDirectories.Contains(directory))
|
|
distinctDirectories.Add(directory);
|
|
}
|
|
if (paddedCheck)
|
|
throw new Exception("Maybe need to restart application!");
|
|
return (distinctDirectories.ToArray(), results);
|
|
}
|
|
|
|
internal static List<string> CopyOrMove(List<(Models.FileHolder, string?, string)> toDoCollection, bool move, bool moveBack, Action? tick)
|
|
{
|
|
List<string> results = new();
|
|
FileInfo fileInfo;
|
|
foreach ((Models.FileHolder fileHolder, string? alternateFile, string to) in toDoCollection)
|
|
{
|
|
tick?.Invoke();
|
|
fileInfo = new(to);
|
|
if (!fileInfo.Exists && alternateFile is not null)
|
|
_ = XPath.WriteAllText(alternateFile, fileHolder.FullName, updateDateWhenMatches: false, compareBeforeWrite: true, updateToWhenMatches: null);
|
|
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;
|
|
}
|
|
|
|
} |