Changed GetDimensions to handle a stream at the end and one exit Switched to using Action? over IDlibDotNet for Tick method Switched to using AsReadOnly over new() Moved Meta Base to Shared
1370 lines
75 KiB
C#
1370 lines
75 KiB
C#
using ShellProgressBar;
|
|
using System.Collections.ObjectModel;
|
|
using System.Diagnostics;
|
|
using System.Drawing;
|
|
using System.Globalization;
|
|
using System.Text.Json;
|
|
using View_by_Distance.Shared.Models;
|
|
using View_by_Distance.Shared.Models.Stateless.Methods;
|
|
using WindowsShortcutFactory;
|
|
|
|
namespace View_by_Distance.Map.Models.Stateless;
|
|
|
|
internal abstract class MapLogic
|
|
{
|
|
|
|
internal record Duplicate(long PersonKey,
|
|
int Id,
|
|
FilePath FilePath,
|
|
float? Percent);
|
|
|
|
internal record MappedFile(long PersonKey,
|
|
string PersonKeyFormatted,
|
|
string? PersonDisplayDirectoryName,
|
|
int? DirectoryNumber,
|
|
FilePath FilePath);
|
|
|
|
internal record PersonKeyFormattedIdThenWholePercentages(string PersonKeyFormatted,
|
|
string? PersonDisplayDirectoryName,
|
|
bool? IsDefault,
|
|
int? LinksCount,
|
|
FilePath MappedFaceFilePath,
|
|
int Id,
|
|
int WholePercentages);
|
|
|
|
private static ReadOnlyDictionary<int, ReadOnlyDictionary<int, ReadOnlyCollection<PersonContainer>>> GetReadOnly(Dictionary<int, Dictionary<int, List<PersonContainer>>> idThenWholePercentagesToPersonContainerCollection)
|
|
{
|
|
Dictionary<int, ReadOnlyDictionary<int, ReadOnlyCollection<PersonContainer>>> results = [];
|
|
List<long> distinct = [];
|
|
List<PersonContainer> personContainers;
|
|
Dictionary<int, ReadOnlyCollection<PersonContainer>> keyValuePairs;
|
|
foreach (KeyValuePair<int, Dictionary<int, List<PersonContainer>>> idTo in idThenWholePercentagesToPersonContainerCollection)
|
|
{
|
|
keyValuePairs = [];
|
|
foreach (KeyValuePair<int, List<PersonContainer>> wholePercentagesTo in idThenWholePercentagesToPersonContainerCollection[idTo.Key])
|
|
{
|
|
distinct.Clear();
|
|
personContainers = [];
|
|
foreach (PersonContainer personContainer in wholePercentagesTo.Value)
|
|
{
|
|
if (personContainer.Key is null)
|
|
throw new Exception();
|
|
if (distinct.Contains(personContainer.Key.Value))
|
|
continue;
|
|
personContainers.Add(personContainer);
|
|
}
|
|
keyValuePairs.Add(wholePercentagesTo.Key, personContainers.AsReadOnly());
|
|
}
|
|
results.Add(idTo.Key, keyValuePairs.AsReadOnly());
|
|
}
|
|
return results.AsReadOnly();
|
|
}
|
|
|
|
internal static (string, bool, bool) Get(int? useFiltersCounter, bool saveIndividually, bool sortingContainersAny, string forceSingleImageHumanized, int? distancePermyriad, int? by, string? displayDirectoryName)
|
|
{
|
|
string byValue;
|
|
bool isByMapping;
|
|
bool isBySorting;
|
|
if (by is null)
|
|
{
|
|
isByMapping = false;
|
|
isBySorting = !sortingContainersAny;
|
|
byValue = $"{nameof(Shared.Models.Stateless.IMapLogic.Mapping)}Null";
|
|
}
|
|
else
|
|
{
|
|
isByMapping = by == Shared.Models.Stateless.IMapLogic.Mapping;
|
|
isBySorting = by == Shared.Models.Stateless.IMapLogic.Sorting;
|
|
bool isDefaultName = displayDirectoryName is not null && IPerson.IsDefaultName(displayDirectoryName);
|
|
if (isBySorting && displayDirectoryName is null)
|
|
byValue = saveIndividually ? nameof(Shared.Models.Stateless.IMapLogic.Individually) : $"{nameof(Shared.Models.Stateless.IMapLogic.Sorting)} Without Person{(distancePermyriad < 2000 ? "-A" : "-Z")}";
|
|
else if (isBySorting && useFiltersCounter.HasValue)
|
|
byValue = $"{nameof(Shared.Models.Stateless.IMapLogic.Sorting)}{(!isDefaultName ? "-A" : "-Z")} Modified Filters - {useFiltersCounter.Value}";
|
|
else
|
|
byValue = Methods.IMapLogic.Get(saveIndividually, forceSingleImageHumanized, by.Value, isDefaultName);
|
|
}
|
|
return new(byValue, isByMapping, isBySorting);
|
|
}
|
|
|
|
internal static (string, bool, bool) Get(int? useFiltersCounter, bool saveIndividually, bool sortingContainersAny, string forceSingleImageHumanized, int? distancePermyriad, long? personKey, string? displayDirectoryName) =>
|
|
Get(useFiltersCounter, saveIndividually, sortingContainersAny, forceSingleImageHumanized, distancePermyriad, personKey is null ? null : Shared.Models.Stateless.IMapLogic.Mapping, displayDirectoryName);
|
|
|
|
internal static Mapping[] GetSelectedMappingCollection(ReadOnlyCollection<Item> items)
|
|
{
|
|
Mapping[] results;
|
|
ReadOnlyCollection<Face> faces = GetFaces(items);
|
|
results = GetSelectedMappingCollection(faces);
|
|
return results;
|
|
}
|
|
|
|
internal static Mapping[] GetSelectedMappingCollection(ReadOnlyCollection<Face> faces)
|
|
{
|
|
Mapping[] results;
|
|
IEnumerable<Mapping> collection = from l in faces orderby l.Mapping?.MappingFromItem.Id select l.Mapping;
|
|
results = (from l in collection where l is not null select l).ToArray();
|
|
return results;
|
|
}
|
|
|
|
internal static ReadOnlyCollection<Face> GetFaces(ReadOnlyCollection<Item> items)
|
|
{
|
|
List<Face> results = [];
|
|
foreach (Item item in items)
|
|
{
|
|
if (item.ExifDirectory?.FilePath?.Id is null || item.ResizedFileHolder is null)
|
|
continue;
|
|
foreach (Face face in item.Faces)
|
|
{
|
|
if (face.FaceEncoding is null || face.Location is null || face.OutputResolution is null)
|
|
continue;
|
|
results.Add(face);
|
|
}
|
|
}
|
|
return results.AsReadOnly();
|
|
}
|
|
|
|
internal static void SaveMappingShortcuts(string mappingDirectory)
|
|
{
|
|
string? shortcutFileName;
|
|
string[] yearDirectories;
|
|
string personKeyFormatted;
|
|
string[] personNameDirectories;
|
|
WindowsShortcut windowsShortcut;
|
|
string personDisplayDirectoryName;
|
|
(string, string)[] yearDirectoryNameCheck;
|
|
List<(string, string)> yearDirectoryNames = [];
|
|
string[] personKeyDirectories = Directory.GetDirectories(mappingDirectory, "*", SearchOption.TopDirectoryOnly);
|
|
foreach (string personKeyDirectory in personKeyDirectories)
|
|
{
|
|
windowsShortcut = new();
|
|
shortcutFileName = null;
|
|
yearDirectoryNames.Clear();
|
|
personKeyFormatted = Path.GetFileName(personKeyDirectory);
|
|
yearDirectories = Directory.GetDirectories(personKeyDirectory, "*", SearchOption.TopDirectoryOnly);
|
|
yearDirectoryNames.AddRange(GetCollection(yearDirectories));
|
|
yearDirectoryNameCheck = (from l in yearDirectoryNames where l.Item2.Contains('^') select l).OrderByDescending(l => l.Item2).ToArray();
|
|
if (yearDirectoryNameCheck.Length == 0)
|
|
yearDirectoryNameCheck = (from l in yearDirectoryNames where l.Item2.Contains('~') select l).OrderByDescending(l => l.Item2).ToArray();
|
|
if (yearDirectoryNameCheck.Length == 0)
|
|
yearDirectoryNameCheck = (from l in yearDirectoryNames where l.Item2.Contains('=') select l).OrderByDescending(l => l.Item2).ToArray();
|
|
if (yearDirectoryNameCheck.Length == 0)
|
|
yearDirectoryNameCheck = (from l in yearDirectoryNames select l).OrderByDescending(l => l).ToArray();
|
|
if (yearDirectoryNameCheck.Length == 0)
|
|
continue;
|
|
foreach ((string yearDirectory, string yearDirectoryName) in yearDirectoryNameCheck)
|
|
{
|
|
personNameDirectories = Directory.GetDirectories(yearDirectory, "*", SearchOption.TopDirectoryOnly);
|
|
foreach (string personNameDirectory in personNameDirectories)
|
|
{
|
|
personDisplayDirectoryName = Path.GetFileName(personNameDirectory).Split('-')[0];
|
|
if (personDisplayDirectoryName is null)
|
|
continue;
|
|
windowsShortcut.Path = yearDirectory;
|
|
windowsShortcut.Description = yearDirectoryName;
|
|
shortcutFileName = Path.Combine(mappingDirectory, $"{personDisplayDirectoryName} [{windowsShortcut.Description}].lnk");
|
|
break;
|
|
}
|
|
if (shortcutFileName is not null)
|
|
{
|
|
if (!File.Exists(shortcutFileName))
|
|
break;
|
|
}
|
|
}
|
|
if (shortcutFileName is null || windowsShortcut.Path is null || windowsShortcut.Description is null)
|
|
continue;
|
|
try
|
|
{
|
|
windowsShortcut.Save(shortcutFileName);
|
|
windowsShortcut.Dispose();
|
|
}
|
|
catch (Exception)
|
|
{ }
|
|
}
|
|
}
|
|
|
|
private static IEnumerable<(string, string)> GetCollection(string[] yearDirectories)
|
|
{
|
|
foreach (string l in yearDirectories)
|
|
yield return new(l, Path.GetFileName(l));
|
|
}
|
|
|
|
internal static ReadOnlyDictionary<int, List<int>> ConvertSkip(Dictionary<int, List<(string, int)>> skipCollection)
|
|
{
|
|
Dictionary<int, List<int>> results = [];
|
|
List<int>? wholePercentagesCollection;
|
|
foreach (KeyValuePair<int, List<(string, int)>> keyValuePair in skipCollection)
|
|
{
|
|
if (!results.TryGetValue(keyValuePair.Key, out wholePercentagesCollection))
|
|
{
|
|
results.Add(keyValuePair.Key, []);
|
|
if (!results.TryGetValue(keyValuePair.Key, out wholePercentagesCollection))
|
|
throw new Exception();
|
|
}
|
|
foreach ((string _, int wholePercentage) in keyValuePair.Value)
|
|
wholePercentagesCollection.Add(wholePercentage);
|
|
}
|
|
return results.AsReadOnly();
|
|
}
|
|
|
|
internal static ReadOnlyDictionary<int, List<long>> GetIdToPersonKeys(ReadOnlyDictionary<long, List<int>> personKeyToIds)
|
|
{
|
|
Dictionary<int, List<long>> results = [];
|
|
List<long>? collection;
|
|
foreach (KeyValuePair<long, List<int>> keyValuePair in personKeyToIds)
|
|
{
|
|
foreach (int id in keyValuePair.Value)
|
|
{
|
|
if (!results.TryGetValue(id, out collection))
|
|
{
|
|
results.Add(id, []);
|
|
if (!results.TryGetValue(id, out collection))
|
|
throw new Exception();
|
|
}
|
|
if (collection.Contains(keyValuePair.Key))
|
|
continue;
|
|
collection.Add(keyValuePair.Key);
|
|
}
|
|
}
|
|
return results.AsReadOnly();
|
|
}
|
|
|
|
internal static SaveContainer GetDebugSaveContainer(SortingContainer sortingContainer, string directory, Mapping keyMapping)
|
|
{
|
|
SaveContainer result;
|
|
string shortcutFile;
|
|
if (sortingContainer?.Source.MappingFromLocation is null)
|
|
throw new NullReferenceException(nameof(sortingContainer.Source.MappingFromLocation));
|
|
FileHolder faceFileHolder = IFileHolder.Get($"C:/{sortingContainer.Sorting.Id}.{sortingContainer.Sorting.WholePercentages}");
|
|
if (keyMapping.MappingFromPerson is not null && keyMapping.MappingFromLocation is not null)
|
|
shortcutFile = Path.Combine(directory, $"{keyMapping.MappingFromLocation.DeterministicHashCodeKey}{keyMapping.MappingFromItem.FilePath.ExtensionLowered}.{sortingContainer.Sorting.DistancePermyriad}.lnk");
|
|
else
|
|
shortcutFile = Path.Combine(directory, $"{sortingContainer.Source.MappingFromLocation.DeterministicHashCodeKey}{sortingContainer.Source.MappingFromItem.FilePath.ExtensionLowered}.{sortingContainer.Sorting.DistancePermyriad}.lnk");
|
|
result = new(directory, faceFileHolder, sortingContainer.Source.MappingFromItem.ResizedFileHolder, shortcutFile);
|
|
return result;
|
|
}
|
|
|
|
internal static string GetMappingSegmentB(long ticks, long personKey, int? approximateYears, MappingFromItem mappingFromItem)
|
|
{
|
|
string result;
|
|
DateTime dateTime = mappingFromItem.GetDateTimeOriginalThenMinimumDateTime();
|
|
PersonBirthday personBirthday = IPersonBirthday.GetPersonBirthday(personKey);
|
|
result = GetMappingSegmentB(ticks, personBirthday, approximateYears, dateTime, mappingFromItem.IsWrongYear);
|
|
return result;
|
|
}
|
|
|
|
internal static string GetMappingSegmentB(long ticks, PersonBirthday personBirthday, int? approximateYears, MappingFromItem mappingFromItem)
|
|
{
|
|
string result;
|
|
DateTime dateTime = mappingFromItem.GetDateTimeOriginalThenMinimumDateTime();
|
|
result = GetMappingSegmentB(ticks, personBirthday, approximateYears, dateTime, mappingFromItem.IsWrongYear);
|
|
return result;
|
|
}
|
|
|
|
private static string GetMappingSegmentB(long ticks, PersonBirthday personBirthday, int? approximateYears, DateTime dateTimeOriginalThenMinimumDateTime, bool? isWrongYear)
|
|
{
|
|
string result = GetMappingSegmentB(ticks, personBirthday, approximateYears, dateTimeOriginalThenMinimumDateTime.Ticks, isWrongYear);
|
|
return result;
|
|
}
|
|
|
|
private static string GetMappingSegmentB(long ticks, PersonBirthday personBirthday, int? approximateYears, long dateTimeOriginalThenMinimumDateTimeTicks, bool? isWrongYear)
|
|
{
|
|
int years;
|
|
string result;
|
|
TimeSpan? timeSpan = IPersonBirthday.GetTimeSpan(dateTimeOriginalThenMinimumDateTimeTicks, isWrongYear, personBirthday);
|
|
if (timeSpan.HasValue && timeSpan.Value.Ticks < 0)
|
|
result = "!---";
|
|
else if (timeSpan.HasValue)
|
|
{
|
|
(years, _) = IPersonBirthday.GetAge(dateTimeOriginalThenMinimumDateTimeTicks, personBirthday);
|
|
result = $"^{years:000}";
|
|
}
|
|
else if (approximateYears.HasValue)
|
|
{
|
|
DateTime dateTime = new(ticks);
|
|
(years, _) = IAge.GetAge(dateTimeOriginalThenMinimumDateTimeTicks, dateTime.AddYears(-approximateYears.Value));
|
|
result = $"~{years:000}";
|
|
}
|
|
else
|
|
{
|
|
string isWrongYearFlag = IItem.GetWrongYearFlag(isWrongYear);
|
|
result = $"{isWrongYearFlag}{new DateTime(dateTimeOriginalThenMinimumDateTimeTicks):yyyy}";
|
|
}
|
|
return result;
|
|
}
|
|
|
|
internal static ReadOnlyDictionary<int, List<int>> ConvertSkipNotSkip(Dictionary<int, List<(string, int)>> skipNotSkipCollection)
|
|
{
|
|
Dictionary<int, List<int>> results = [];
|
|
List<int>? wholePercentagesCollection;
|
|
foreach (KeyValuePair<int, List<(string, int)>> keyValuePair in skipNotSkipCollection)
|
|
{
|
|
if (!results.TryGetValue(keyValuePair.Key, out wholePercentagesCollection))
|
|
{
|
|
results.Add(keyValuePair.Key, []);
|
|
if (!results.TryGetValue(keyValuePair.Key, out wholePercentagesCollection))
|
|
throw new Exception();
|
|
}
|
|
foreach ((string _, int wholePercentage) in keyValuePair.Value)
|
|
wholePercentagesCollection.Add(wholePercentage);
|
|
}
|
|
return results.AsReadOnly();
|
|
}
|
|
|
|
internal static ReadOnlyDictionary<int, List<LocationContainer>> ConvertLocationContainers(List<LocationContainer> locationContainers)
|
|
{
|
|
Dictionary<int, List<LocationContainer>> results = [];
|
|
foreach (LocationContainer locationContainer in locationContainers)
|
|
{
|
|
if (!results.ContainsKey(locationContainer.Id))
|
|
results.Add(locationContainer.Id, []);
|
|
results[locationContainer.Id].Add(locationContainer);
|
|
}
|
|
return results.AsReadOnly();
|
|
}
|
|
|
|
internal static void CheckCollection(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string? rootDirectoryParent)
|
|
{
|
|
string json;
|
|
string fullPath;
|
|
List<KeyValuePair<int, int[]>>? collection;
|
|
foreach (string propertyContentCollectionFile in propertyConfiguration.PropertyContentCollectionFiles)
|
|
{
|
|
fullPath = Path.GetFullPath(string.Concat(rootDirectoryParent, propertyContentCollectionFile));
|
|
if (fullPath.Contains(propertyConfiguration.RootDirectory))
|
|
continue;
|
|
if (!File.Exists(fullPath))
|
|
continue;
|
|
json = File.ReadAllText(fullPath);
|
|
collection = JsonSerializer.Deserialize<List<KeyValuePair<int, int[]>>>(json);
|
|
if (collection is null)
|
|
throw new NullReferenceException(nameof(collection));
|
|
}
|
|
}
|
|
|
|
internal static string? GetFacePartsContentCollectionFile(string extension, string d2FacePartsContentCollectionDirectory, MappingFromItem mappingFromItem)
|
|
{
|
|
string? result;
|
|
string? directoryName = Path.GetDirectoryName(mappingFromItem.RelativePath);
|
|
if (directoryName is null)
|
|
result = null;
|
|
else
|
|
result = Path.Combine($"{d2FacePartsContentCollectionDirectory}{directoryName}", $"{mappingFromItem.FilePath.Name}{extension}");
|
|
return result;
|
|
}
|
|
|
|
internal static string GetResizeContentDirectory(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string cContentDirectory, FilePath filePath)
|
|
{
|
|
string result;
|
|
CombinedEnumAndIndex cei = IPath.GetCombinedEnumAndIndex(propertyConfiguration, filePath);
|
|
result = Path.Combine(cContentDirectory, cei.Combined);
|
|
return result;
|
|
}
|
|
|
|
internal static ReadOnlyDictionary<int, ReadOnlyDictionary<int, Mapping>> GetIdToWholePercentagesToFace(ReadOnlyCollection<Mapping> distinctValidImageMappingCollection)
|
|
{
|
|
Dictionary<int, Dictionary<int, Mapping>> results = [];
|
|
Dictionary<int, Mapping>? keyValuePairs;
|
|
foreach (Mapping mapping in distinctValidImageMappingCollection)
|
|
{
|
|
if (mapping.MappingFromLocation is null)
|
|
continue;
|
|
if (!results.TryGetValue(mapping.MappingFromItem.Id, out keyValuePairs))
|
|
{
|
|
results.Add(mapping.MappingFromItem.Id, []);
|
|
if (!results.TryGetValue(mapping.MappingFromItem.Id, out keyValuePairs))
|
|
throw new Exception();
|
|
}
|
|
if (keyValuePairs.ContainsKey(mapping.MappingFromLocation.WholePercentages))
|
|
continue;
|
|
keyValuePairs.Add(mapping.MappingFromLocation.WholePercentages, mapping);
|
|
}
|
|
return GetReadOnly(results);
|
|
}
|
|
|
|
private static ReadOnlyDictionary<int, ReadOnlyDictionary<int, Mapping>> GetReadOnly(Dictionary<int, Dictionary<int, Mapping>> keyValuePairs)
|
|
{
|
|
Dictionary<int, ReadOnlyDictionary<int, Mapping>> results = [];
|
|
foreach (KeyValuePair<int, Dictionary<int, Mapping>> keyValuePair in keyValuePairs)
|
|
results.Add(keyValuePair.Key, keyValuePair.Value.AsReadOnly());
|
|
return results.AsReadOnly();
|
|
}
|
|
|
|
internal static int CopyManualFiles(Configuration configuration, long ticks, ReadOnlyCollection<PersonContainer> personContainers, string eDistanceContentTicksDirectory)
|
|
{
|
|
int result = 0;
|
|
string checkFile;
|
|
string dateDirectory;
|
|
string directoryName;
|
|
string checkDirectory;
|
|
string personKeyFormatted;
|
|
List<string> distinct = [];
|
|
PersonBirthday personBirthday;
|
|
DateTime dateTime = new(ticks);
|
|
string by = nameof(Shared.Models.Stateless.IMapLogic.ManualCopy);
|
|
foreach (PersonContainer personContainer in personContainers)
|
|
{
|
|
if (personContainer.Key is null)
|
|
continue;
|
|
for (int i = personContainer.DisplayDirectoryAllFilePaths.Count - 1; i > -1; i--)
|
|
{
|
|
if (personContainer.DisplayDirectoryAllFilePaths[i].ExtensionLowered != configuration.FacesFileNameExtension)
|
|
continue;
|
|
if (distinct.Contains(personContainer.DisplayDirectoryAllFilePaths[i].Name))
|
|
continue;
|
|
distinct.Add(personContainer.DisplayDirectoryAllFilePaths[i].Name);
|
|
directoryName = Path.GetFileName(personContainer.DisplayDirectoryAllFilePaths[i].DirectoryFullPath);
|
|
if (directoryName != personContainer.DisplayDirectoryName)
|
|
continue;
|
|
personBirthday = IPersonBirthday.GetPersonBirthday(personContainer.Key.Value);
|
|
personKeyFormatted = IPersonBirthday.GetFormatted(configuration.PersonBirthdayFormat, personBirthday);
|
|
dateDirectory = Path.Combine(eDistanceContentTicksDirectory, by, personKeyFormatted, dateTime.ToString("yyyy"));
|
|
checkDirectory = Path.Combine(dateDirectory, personContainer.DisplayDirectoryName);
|
|
if (!Directory.Exists(checkDirectory))
|
|
_ = Directory.CreateDirectory(checkDirectory);
|
|
checkFile = Path.Combine(dateDirectory, personContainer.DisplayDirectoryAllFilePaths[i].Name);
|
|
if (File.Exists(checkFile))
|
|
continue;
|
|
File.Move(personContainer.DisplayDirectoryAllFilePaths[i].FullName, checkFile);
|
|
throw new NotImplementedException("readonly null?");
|
|
// personContainer.DisplayDirectoryAllFilePaths[i] = null;
|
|
// result++;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
internal static string GetFacePartsDirectoryX(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string d2FacePartsContentDirectory, FilePath filePath)
|
|
{
|
|
string result;
|
|
CombinedEnumAndIndex cei = IPath.GetCombinedEnumAndIndex(propertyConfiguration, filePath);
|
|
result = Path.Combine(d2FacePartsContentDirectory, cei.Combined, filePath.NameWithoutExtension);
|
|
MoveIf(filePath.NameWithoutExtension, cei, d2FacePartsContentDirectory, result);
|
|
return result;
|
|
}
|
|
|
|
private static void MoveIf(string fileName, CombinedEnumAndIndex cei, string directory, string fullFileName)
|
|
{
|
|
string[] segments = directory.Split(cei.Combined);
|
|
string? checkDirectory = segments.Length == 1 ?
|
|
Path.Combine(segments[0], $"{cei.Combined[2..]}") :
|
|
segments.Length == 2 ?
|
|
$"{segments[0]}{cei.Combined[2..]}{segments[1]}" :
|
|
null;
|
|
if (checkDirectory is not null && Directory.Exists(checkDirectory))
|
|
{
|
|
string checkFile = Path.Combine(checkDirectory, fileName);
|
|
if (File.Exists(checkFile))
|
|
File.Move(checkFile, fullFileName);
|
|
}
|
|
}
|
|
|
|
internal static bool? CanReMap(long[] jLinkResolvedPersonKeys, ReadOnlyDictionary<int, ReadOnlyCollection<PersonContainer>>? wholePercentagesToPersonContainers, int wholePercentages)
|
|
{
|
|
bool? result;
|
|
ReadOnlyCollection<PersonContainer>? personContainers;
|
|
if (wholePercentagesToPersonContainers is null)
|
|
result = null;
|
|
else
|
|
{
|
|
if (!wholePercentagesToPersonContainers.TryGetValue(wholePercentages, out personContainers))
|
|
result = null;
|
|
else
|
|
{
|
|
result = false;
|
|
foreach (PersonContainer personContainer in personContainers)
|
|
{
|
|
if (!IPerson.IsDefaultName(personContainer) || personContainer.Key is null || !IPersonBirthday.IsCounterPersonYear(new DateTime(personContainer.Key.Value).Year) || jLinkResolvedPersonKeys.Contains(personContainer.Key.Value))
|
|
continue;
|
|
result = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
internal static ReadOnlyCollection<PersonKeyFormattedIdThenWholePercentages> GetPersonKeyFormattedIdThenWholePercentages(Configuration configuration, long ticks, List<Record> records)
|
|
{
|
|
List<PersonKeyFormattedIdThenWholePercentages> results = [];
|
|
int? wholePercentages;
|
|
List<int> wholePercentagesCollection;
|
|
Dictionary<int, List<int>> idToWholePercentagesCollection = [];
|
|
PersonKeyFormattedIdThenWholePercentages personKeyFormattedIdThenWholePercentages;
|
|
int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds);
|
|
string message = $") {records.Count:000} join from ticks Director(ies) - C - {totalSeconds} total second(s)";
|
|
ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
|
|
using ProgressBar progressBar = new(records.Count, message, options);
|
|
foreach (Record record in records)
|
|
{
|
|
progressBar.Tick();
|
|
if (record.MappedFaceFilePath.Id is null)
|
|
continue;
|
|
wholePercentages = IMapping.GetWholePercentages(configuration.FacesFileNameExtension, record.MappedFaceFilePath);
|
|
if (wholePercentages is null)
|
|
continue;
|
|
if (!idToWholePercentagesCollection.ContainsKey(record.MappedFaceFilePath.Id.Value))
|
|
idToWholePercentagesCollection.Add(record.MappedFaceFilePath.Id.Value, []);
|
|
wholePercentagesCollection = idToWholePercentagesCollection[record.MappedFaceFilePath.Id.Value];
|
|
wholePercentagesCollection.Add(wholePercentages.Value);
|
|
idToWholePercentagesCollection[record.MappedFaceFilePath.Id.Value].Add(wholePercentages.Value);
|
|
personKeyFormattedIdThenWholePercentages = new(PersonKeyFormatted: record.PersonKeyFormatted,
|
|
PersonDisplayDirectoryName: record.PersonDisplayDirectoryName,
|
|
IsDefault: record.IsDefault,
|
|
LinksCount: record.LinksCount,
|
|
MappedFaceFilePath: record.MappedFaceFilePath,
|
|
Id: record.MappedFaceFilePath.Id.Value,
|
|
WholePercentages: wholePercentages.Value);
|
|
results.Add(personKeyFormattedIdThenWholePercentages);
|
|
}
|
|
return results.AsReadOnly();
|
|
}
|
|
|
|
internal static (string, bool, bool) Get(int? useFiltersCounter, bool saveIndividually, bool sortingContainersAny, string forceSingleImageHumanized, int? distancePermyriad, Mapping mapping) =>
|
|
Get(useFiltersCounter, saveIndividually, sortingContainersAny, forceSingleImageHumanized, distancePermyriad, mapping.By, mapping.MappingFromPerson?.DisplayDirectoryName);
|
|
|
|
internal static string GetFacesDirectory(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string dFacesContentDirectory, FilePath filePath, MappingFromItem mappingFromItem)
|
|
{
|
|
string result;
|
|
CombinedEnumAndIndex cei = IPath.GetCombinedEnumAndIndex(propertyConfiguration, filePath);
|
|
result = Path.Combine(dFacesContentDirectory, cei.Combined, mappingFromItem.FilePath.NameWithoutExtension);
|
|
MoveIf(mappingFromItem.FilePath.NameWithoutExtension, cei, dFacesContentDirectory, result);
|
|
return result;
|
|
}
|
|
|
|
internal static string GetFacePartsDirectory(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string d2FacePartsContentDirectory, FilePath filePath, MappingFromItem mappingFromItem)
|
|
{
|
|
string result;
|
|
CombinedEnumAndIndex cei = IPath.GetCombinedEnumAndIndex(propertyConfiguration, filePath);
|
|
result = Path.Combine(d2FacePartsContentDirectory, cei.Combined, mappingFromItem.FilePath.NameWithoutExtension);
|
|
MoveIf(mappingFromItem.FilePath.NameWithoutExtension, cei, d2FacePartsContentDirectory, result);
|
|
return result;
|
|
}
|
|
|
|
internal static List<PersonContainer> GetNotMappedPersonContainers(Configuration configuration, long ticks, ReadOnlyCollection<PersonContainer> personContainers, ReadOnlyDictionary<long, int> personKeyToCount)
|
|
{
|
|
List<PersonContainer> results = [];
|
|
List<PersonContainer> notMappedAndNotNamedPersonKeys = [];
|
|
List<PersonContainer> notMappedAndWithNamedPersonKeys = [];
|
|
List<long> personKeys = IPersonContainer.GetPersonKeys(personContainers);
|
|
foreach (PersonContainer personContainer in personContainers)
|
|
{
|
|
if (personContainer.Key is null || personContainer.Birthdays is null || personContainer.Birthdays.Length == 0)
|
|
continue;
|
|
if (personKeys.Contains(personContainer.Key.Value))
|
|
continue;
|
|
if (personKeyToCount.ContainsKey(personContainer.Key.Value))
|
|
continue;
|
|
if (string.IsNullOrEmpty(personContainer.DisplayDirectoryName) || personContainer.DisplayDirectoryName == configuration.MappingDefaultName)
|
|
notMappedAndNotNamedPersonKeys.Add(personContainer);
|
|
else
|
|
notMappedAndWithNamedPersonKeys.Add(personContainer);
|
|
}
|
|
results.AddRange(notMappedAndNotNamedPersonKeys);
|
|
if (results.Count == 0)
|
|
results.AddRange(GetNonSpecificPeopleCollection(configuration, ticks, personKeys, personKeyToCount));
|
|
return results;
|
|
}
|
|
|
|
private static List<PersonContainer> GetNonSpecificPeopleCollection(Configuration configuration, long ticks, List<long> personKeys, ReadOnlyDictionary<long, int> personKeyToCount)
|
|
{
|
|
List<PersonContainer> results = [];
|
|
bool check;
|
|
long personKey;
|
|
int? approximateYears = null;
|
|
PersonBirthday personBirthday;
|
|
PersonContainer personContainer;
|
|
List<FilePath> personDisplayDirectoryAllFilePaths = [];
|
|
DateTime incrementDate = new(configuration.PersonBirthdayFirstYear, 1, 1);
|
|
long oneHour = new DateTime(1, 1, 1, 1, 0, 0).Ticks - new DateTime(1, 1, 1).Ticks;
|
|
for (int i = 0; i < int.MaxValue; i++)
|
|
{
|
|
check = false;
|
|
personKey = incrementDate.Ticks;
|
|
incrementDate = incrementDate.AddDays(1);
|
|
if (incrementDate.Ticks > ticks)
|
|
break;
|
|
if (personKeys.Contains(personKey))
|
|
continue;
|
|
if (personKeyToCount.ContainsKey(personKey))
|
|
continue;
|
|
for (int j = 1; j < 24; j++)
|
|
{
|
|
if (personKeys.Contains(personKey + (oneHour * j)))
|
|
{
|
|
check = true;
|
|
break;
|
|
}
|
|
if (personKeyToCount.ContainsKey(personKey + (oneHour * j)))
|
|
{
|
|
check = true;
|
|
break;
|
|
}
|
|
}
|
|
if (check)
|
|
continue;
|
|
personBirthday = IPersonBirthday.GetPersonBirthday(personKey + (oneHour * 2));
|
|
personContainer = PersonContainer.Get(approximateYears, [personBirthday], personDisplayDirectoryAllFilePaths.AsReadOnly(), configuration.MappingDefaultName, personKey);
|
|
results.Add(personContainer);
|
|
if (results.Count > 99)
|
|
break;
|
|
}
|
|
return results;
|
|
}
|
|
|
|
internal static (SaveContainer, SaveContainer?) GetContainers(string facesFileNameExtension, string facePartsFileNameExtension, string directory, FileHolder faceFileHolder, FileHolder facePartsFileHolder, Mapping mapping)
|
|
{
|
|
string checkFile;
|
|
SaveContainer? saveContainer;
|
|
if (mapping.MappingFromLocation is null)
|
|
throw new NullReferenceException(nameof(mapping.MappingFromLocation));
|
|
checkFile = Path.Combine(directory, $"{mapping.MappingFromItem.FilePath.Name}{facePartsFileNameExtension}");
|
|
saveContainer = !facePartsFileHolder.Exists ? null : new(checkFile, directory, facePartsFileHolder);
|
|
checkFile = Path.Combine(directory, $"{mapping.MappingFromLocation.DeterministicHashCodeKey}{mapping.MappingFromItem.FilePath.ExtensionLowered}{facesFileNameExtension}");
|
|
return (new(checkFile, directory, faceFileHolder), saveContainer);
|
|
}
|
|
|
|
internal static List<MappedFile> GetMappedFiles(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, Configuration configuration, ReadOnlyCollection<PersonContainer> personContainers, List<Record> records)
|
|
{
|
|
List<MappedFile> results = [];
|
|
long personKey;
|
|
string checkFile;
|
|
FilePath filePath;
|
|
FileHolder fileHolder;
|
|
MappedFile mappedFile;
|
|
List<string> distinct = [];
|
|
PersonBirthday? personBirthday;
|
|
PersonContainer? personContainer;
|
|
string? personDisplayDirectoryName;
|
|
ReadOnlyDictionary<long, PersonContainer> keyValuePairs = PersonContainer.Extract(personContainers);
|
|
results.AddRange(GetDisplayDirectoryAllFiles(configuration.FacesFileNameExtension, configuration.PersonBirthdayFormat, personContainers));
|
|
foreach (Record record in records)
|
|
{
|
|
personBirthday = IPersonBirthday.GetPersonBirthday(configuration.PersonBirthdayFormat, record.PersonKeyFormatted);
|
|
if (personBirthday is null)
|
|
continue;
|
|
if (distinct.Contains(record.MappedFaceFilePath.Name))
|
|
continue;
|
|
personKey = personBirthday.Value.Ticks;
|
|
distinct.Add(record.MappedFaceFilePath.Name);
|
|
if (!keyValuePairs.TryGetValue(personKey, out personContainer))
|
|
personDisplayDirectoryName = record.PersonDisplayDirectoryName;
|
|
else
|
|
personDisplayDirectoryName = personContainer.DisplayDirectoryName;
|
|
mappedFile = new(PersonKey: personKey,
|
|
PersonKeyFormatted: record.PersonKeyFormatted,
|
|
PersonDisplayDirectoryName: personDisplayDirectoryName,
|
|
DirectoryNumber: record.DirectoryNumber,
|
|
FilePath: record.MappedFaceFilePath);
|
|
results.Add(mappedFile);
|
|
}
|
|
for (int i = results.Count - 1; i > -1; i--)
|
|
{
|
|
filePath = results[i].FilePath;
|
|
if (filePath.Name.EndsWith(".old"))
|
|
{
|
|
results.RemoveAt(i);
|
|
continue;
|
|
}
|
|
if (!filePath.Name.EndsWith(".abd") && !filePath.Name.EndsWith(".brt") && !filePath.Name.EndsWith(".dup") && !filePath.Name.EndsWith(".unk"))
|
|
continue;
|
|
if (!File.Exists(filePath.FullName))
|
|
continue;
|
|
checkFile = filePath.FullName[..^4];
|
|
if (File.Exists(checkFile))
|
|
continue;
|
|
File.Move(filePath.FullName, checkFile);
|
|
fileHolder = IFileHolder.Get(checkFile);
|
|
filePath = FilePath.Get(propertyConfiguration, fileHolder, index: null);
|
|
results[i] = new(PersonKey: results[i].PersonKey,
|
|
PersonKeyFormatted: results[i].PersonKeyFormatted,
|
|
PersonDisplayDirectoryName: results[i].PersonDisplayDirectoryName,
|
|
DirectoryNumber: results[i].DirectoryNumber,
|
|
FilePath: filePath);
|
|
}
|
|
return results;
|
|
}
|
|
|
|
private static List<MappedFile> GetDisplayDirectoryAllFiles(string fileNameExtension, string personBirthdayFormat, ReadOnlyCollection<PersonContainer> personContainers)
|
|
{
|
|
List<MappedFile> results = [];
|
|
MappedFile mappedFile;
|
|
string personKeyFormatted;
|
|
List<string> distinct = [];
|
|
foreach (PersonContainer personContainer in personContainers)
|
|
{
|
|
if (personContainer.Key is null)
|
|
continue;
|
|
for (int i = personContainer.DisplayDirectoryAllFilePaths.Count - 1; i > -1; i--)
|
|
{
|
|
if (personContainer.DisplayDirectoryAllFilePaths[i].ExtensionLowered != fileNameExtension)
|
|
continue;
|
|
if (distinct.Contains(personContainer.DisplayDirectoryAllFilePaths[i].Name))
|
|
continue;
|
|
distinct.Add(personContainer.DisplayDirectoryAllFilePaths[i].Name);
|
|
personKeyFormatted = IPersonBirthday.GetFormatted(personBirthdayFormat, personContainer.Key.Value);
|
|
mappedFile = new(PersonKey: personContainer.Key.Value,
|
|
PersonKeyFormatted: personKeyFormatted,
|
|
PersonDisplayDirectoryName: personContainer.DisplayDirectoryName,
|
|
DirectoryNumber: null,
|
|
FilePath: personContainer.DisplayDirectoryAllFilePaths[i]);
|
|
results.Add(mappedFile);
|
|
}
|
|
}
|
|
return results;
|
|
}
|
|
|
|
internal static List<(string, long)> GetJLinkDirectories(string genealogicalDataCommunicationFile, string[] jLinks, string personBirthdayFormat, char[] personCharacters, string a2PeopleSingletonDirectory, string a2PeopleContentDirectory)
|
|
{
|
|
List<(string, long)> results;
|
|
string[] files;
|
|
string? foundPath;
|
|
int totalFiles = 0;
|
|
string checkDirectory;
|
|
WindowsShortcut windowsShortcut;
|
|
List<string> resolvedDirectories = [];
|
|
if (string.IsNullOrEmpty(genealogicalDataCommunicationFile))
|
|
results = GetDirectoryAndTicksCollection(jLinks, personBirthdayFormat, a2PeopleContentDirectory);
|
|
else
|
|
results = GetGenealogicalDataCommunicationDirectories(genealogicalDataCommunicationFile, jLinks, personBirthdayFormat);
|
|
if (results.Count == 0 || results.Count < jLinks.Length)
|
|
{
|
|
List<(string, string, string)> a2PeopleSingletonDirectories = [];
|
|
foreach (string directory in Directory.GetDirectories(a2PeopleSingletonDirectory, "*", SearchOption.AllDirectories))
|
|
a2PeopleSingletonDirectories.Add((directory, Path.GetFileName(directory), Path.GetFileName(directory).Split(personCharacters).First()));
|
|
foreach (string directoryName in jLinks)
|
|
{
|
|
checkDirectory = Path.Combine(a2PeopleContentDirectory, directoryName);
|
|
if (!Directory.Exists(checkDirectory))
|
|
continue;
|
|
files = Directory.GetFiles(checkDirectory, "*.lnk", SearchOption.TopDirectoryOnly);
|
|
totalFiles += files.Length;
|
|
foreach (string file in files)
|
|
{
|
|
windowsShortcut = WindowsShortcut.Load(file);
|
|
if (windowsShortcut.Path is null)
|
|
continue;
|
|
if (Directory.Exists(windowsShortcut.Path))
|
|
resolvedDirectories.Add(windowsShortcut.Path);
|
|
else
|
|
{
|
|
foundPath = TryToFind(personCharacters, a2PeopleSingletonDirectory, a2PeopleSingletonDirectories, file, windowsShortcut.Path);
|
|
if (string.IsNullOrEmpty(foundPath))
|
|
continue;
|
|
resolvedDirectories.Add(foundPath);
|
|
}
|
|
}
|
|
}
|
|
if (totalFiles == resolvedDirectories.Count)
|
|
results = GetJLinkResolvedDirectories(personBirthdayFormat, resolvedDirectories);
|
|
else
|
|
{
|
|
resolvedDirectories.Clear();
|
|
results = [];
|
|
}
|
|
}
|
|
return results;
|
|
}
|
|
|
|
private static List<(string, long)> GetDirectoryAndTicksCollection(string[] jLinks, string personBirthdayFormat, string? rootDirectory)
|
|
{
|
|
List<(string, long)> results = [];
|
|
string directory;
|
|
DateTime dateTime;
|
|
string[] personKeyDirectories;
|
|
string[] personDisplayDirectoryNames;
|
|
string personKeyFormattedDirectoryName;
|
|
foreach (string jLink in jLinks)
|
|
{
|
|
if (rootDirectory is null)
|
|
continue;
|
|
directory = Path.Combine(rootDirectory, jLink);
|
|
if (!Directory.Exists(directory))
|
|
continue;
|
|
personDisplayDirectoryNames = Directory.GetDirectories(directory, "*", SearchOption.TopDirectoryOnly);
|
|
foreach (string personDisplayDirectoryName in personDisplayDirectoryNames)
|
|
{
|
|
personKeyDirectories = Directory.GetDirectories(personDisplayDirectoryName, "*", SearchOption.TopDirectoryOnly);
|
|
foreach (string personKeyFormattedDirectory in personKeyDirectories)
|
|
{
|
|
personKeyFormattedDirectoryName = Path.GetFileName(personKeyFormattedDirectory);
|
|
if (personKeyFormattedDirectoryName.Length != personBirthdayFormat.Length || !DateTime.TryParseExact(personKeyFormattedDirectoryName, personBirthdayFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime))
|
|
continue;
|
|
results.Add((directory, dateTime.Ticks));
|
|
}
|
|
}
|
|
}
|
|
return results;
|
|
}
|
|
|
|
private static List<(string, long)> GetGenealogicalDataCommunicationDirectories(string genealogicalDataCommunicationFile, string[] jLinks, string personBirthdayFormat)
|
|
{
|
|
List<(string, long)> results;
|
|
string? genealogicalDataCommunicationDirectory = Path.GetDirectoryName(genealogicalDataCommunicationFile);
|
|
results = GetDirectoryAndTicksCollection(jLinks, personBirthdayFormat, genealogicalDataCommunicationDirectory);
|
|
return results;
|
|
}
|
|
|
|
private static string? TryToFind(char[] personCharacters, string a2PeopleSingletonDirectory, List<(string Directory, string DirectoryName, string DirectoryNameSplitFirst)> a2PeopleSingletonDirectories, string file, string path)
|
|
{
|
|
string? result;
|
|
string? pathName = Path.GetFileName(path);
|
|
string? group = Path.GetDirectoryName(path);
|
|
string? groupName = Path.GetFileName(group);
|
|
if (pathName is null || group is null || groupName is null)
|
|
result = null;
|
|
else
|
|
{
|
|
string[] matches;
|
|
matches = (from l in a2PeopleSingletonDirectories where l.DirectoryName == pathName select l.Directory).ToArray();
|
|
if (matches.Length == 1)
|
|
result = matches.First();
|
|
else
|
|
{
|
|
string pathNameSplitFirst = pathName.Split(personCharacters).First();
|
|
matches = (from l in a2PeopleSingletonDirectories where l.DirectoryNameSplitFirst == pathNameSplitFirst select l.Directory).ToArray();
|
|
if (matches.Length == 1)
|
|
result = matches.First();
|
|
else
|
|
{
|
|
string checkDirectory = Path.Combine(a2PeopleSingletonDirectory, groupName, pathName);
|
|
if (!Directory.Exists(checkDirectory))
|
|
result = null;
|
|
else
|
|
result = checkDirectory;
|
|
}
|
|
}
|
|
if (!string.IsNullOrEmpty(result))
|
|
{
|
|
try
|
|
{
|
|
WindowsShortcut windowsShortcut;
|
|
windowsShortcut = new() { Path = result };
|
|
windowsShortcut.Save(file);
|
|
windowsShortcut.Dispose();
|
|
}
|
|
catch (Exception)
|
|
{ }
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private static List<(string, long)> GetJLinkResolvedDirectories(string personBirthdayFormat, List<string> resolvedDirectories)
|
|
{
|
|
List<(string, long)> results = [];
|
|
DateTime dateTime;
|
|
string directoryName;
|
|
string[] directories;
|
|
foreach (string resolvedDirectory in resolvedDirectories)
|
|
{
|
|
directories = Directory.GetDirectories(resolvedDirectory, "*", SearchOption.TopDirectoryOnly);
|
|
foreach (string directory in directories)
|
|
{
|
|
directoryName = Path.GetFileName(directory);
|
|
if (directoryName.Length != personBirthdayFormat.Length || !DateTime.TryParseExact(directoryName, personBirthdayFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime))
|
|
continue;
|
|
results.Add((resolvedDirectory, dateTime.Ticks));
|
|
}
|
|
}
|
|
if (results.Count != resolvedDirectories.Count)
|
|
results.Clear();
|
|
return results;
|
|
}
|
|
|
|
internal static void SetPersonCollectionsAfterSetSkipCollections(Configuration configuration, ReadOnlyCollection<PersonContainer> personContainers, Dictionary<string, string> personKeyFormattedToNewestPersonKeyFormatted, List<string> personKeyFormattedCollection)
|
|
{
|
|
string personKeyFormatted;
|
|
string newestPersonKeyFormatted;
|
|
foreach (PersonContainer personContainer in personContainers)
|
|
{
|
|
if (personContainer.Key is null || personContainer.Birthdays is null || personContainer.Birthdays.Length == 0)
|
|
continue;
|
|
foreach (PersonBirthday personBirthday in personContainer.Birthdays)
|
|
{
|
|
personKeyFormatted = IPersonBirthday.GetFormatted(configuration.PersonBirthdayFormat, personBirthday);
|
|
personKeyFormattedCollection.Add(personKeyFormatted);
|
|
if (personContainer.Birthdays.Length < 1)
|
|
continue;
|
|
newestPersonKeyFormatted = IPersonBirthday.GetFormatted(configuration.PersonBirthdayFormat, personContainer.Key.Value);
|
|
_ = personKeyFormattedToNewestPersonKeyFormatted.TryAdd(personKeyFormatted, newestPersonKeyFormatted);
|
|
}
|
|
}
|
|
}
|
|
|
|
internal static void SetSkipCollections(Configuration configuration, ReadOnlyCollection<PersonContainer> personContainers, string? a2PeopleSingletonDirectory, Dictionary<int, List<(string, int)>> skipCollection, Dictionary<int, List<(string, int)>> skipNotSkipCollection)
|
|
{
|
|
string checkFile;
|
|
int? wholePercentages;
|
|
List<FilePath> distinct = [];
|
|
List<string> distinctFiles = [];
|
|
List<string> distinctFileName = [];
|
|
bool skipNotSkipDirectoriesAny = configuration.SkipNotSkipDirectories.Length > 0;
|
|
string[] checkDirectories = (from l in configuration.SkipNotSkipDirectories select Path.GetFullPath($"{a2PeopleSingletonDirectory}{l}")).ToArray();
|
|
foreach (PersonContainer personContainer in personContainers)
|
|
{
|
|
foreach (FilePath personDisplayDirectoryAllFilePath in personContainer.DisplayDirectoryAllFilePaths)
|
|
{
|
|
if (personDisplayDirectoryAllFilePath.ExtensionLowered != configuration.FacesFileNameExtension)
|
|
continue;
|
|
if (distinctFiles.Contains(personDisplayDirectoryAllFilePath.FullName))
|
|
continue;
|
|
distinctFiles.Add(personDisplayDirectoryAllFilePath.FullName);
|
|
distinct.Add(personDisplayDirectoryAllFilePath);
|
|
}
|
|
}
|
|
foreach (FilePath filePath in distinct)
|
|
{
|
|
if (distinctFileName.Contains(filePath.Name))
|
|
{
|
|
checkFile = $"{filePath.FullName}.dup";
|
|
if (File.Exists(checkFile))
|
|
continue;
|
|
File.Move(filePath.FullName, checkFile);
|
|
continue;
|
|
}
|
|
if (filePath.Id is null)
|
|
continue;
|
|
wholePercentages = IMapping.GetWholePercentages(configuration.FacesFileNameExtension, filePath);
|
|
if (wholePercentages is null)
|
|
continue;
|
|
if (!skipNotSkipDirectoriesAny || !checkDirectories.Any(filePath.FullName.StartsWith))
|
|
{
|
|
if (!skipCollection.ContainsKey(filePath.Id.Value))
|
|
skipCollection.Add(filePath.Id.Value, []);
|
|
skipCollection[filePath.Id.Value].Add((filePath.FullName, wholePercentages.Value));
|
|
}
|
|
else
|
|
{
|
|
if (!skipNotSkipCollection.ContainsKey(filePath.Id.Value))
|
|
skipNotSkipCollection.Add(filePath.Id.Value, []);
|
|
skipNotSkipCollection[filePath.Id.Value].Add((filePath.FullName, wholePercentages.Value));
|
|
}
|
|
}
|
|
}
|
|
|
|
internal static (SaveContainer?, SaveContainer?) GetContainers(string facesFileNameExtension, string facePartsFileNameExtension, Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string dFacesContentDirectory, string d2FacePartsContentCollectionDirectory, string directory, Mapping keyMapping)
|
|
{
|
|
SaveContainer? result;
|
|
SaveContainer? saveContainer;
|
|
if (keyMapping.MappingFromLocation is null)
|
|
(result, saveContainer) = (null, null);
|
|
else
|
|
{
|
|
string? facePartsContentCollectionFile = GetFacePartsContentCollectionFile(facePartsFileNameExtension, d2FacePartsContentCollectionDirectory, keyMapping.MappingFromItem);
|
|
if (facePartsContentCollectionFile is null || !File.Exists(facePartsContentCollectionFile))
|
|
result = null;
|
|
else
|
|
{
|
|
string checkFile = Path.Combine(directory, $"{keyMapping.MappingFromItem.FilePath.Name}{facePartsFileNameExtension}");
|
|
result = new(checkFile, directory, IFileHolder.Get(facePartsContentCollectionFile));
|
|
}
|
|
string facesDirectory = GetFacesDirectory(propertyConfiguration, dFacesContentDirectory, keyMapping.FilePath, keyMapping.MappingFromItem);
|
|
FileHolder faceFileHolder = IFileHolder.Get(Path.Combine(facesDirectory, $"{keyMapping.MappingFromLocation.DeterministicHashCodeKey}{keyMapping.MappingFromItem.FilePath.ExtensionLowered}{facesFileNameExtension}"));
|
|
if (!faceFileHolder.Exists)
|
|
saveContainer = null;
|
|
else
|
|
{
|
|
string checkFile = Path.Combine(directory, $"{keyMapping.MappingFromLocation.DeterministicHashCodeKey}{keyMapping.MappingFromItem.FilePath.ExtensionLowered}{facesFileNameExtension}");
|
|
saveContainer = new(checkFile, directory, faceFileHolder);
|
|
}
|
|
}
|
|
return (result, saveContainer);
|
|
}
|
|
|
|
internal static void PossiblyRebuildPersonContainers(Configuration configuration, long ticks, string? a2PeopleSingletonDirectory, ReadOnlyDictionary<long, int> readOnlyPersonKeyToCount, ReadOnlyCollection<(PersonKeyFormattedIdThenWholePercentages, PersonContainer)> possiblyNewPersonDisplayDirectoryNamesAndPersonContainer)
|
|
{
|
|
int count;
|
|
long personKey;
|
|
bool[] matches;
|
|
string fileName;
|
|
string checkFile;
|
|
const int zero = 0;
|
|
string personKeyFormatted;
|
|
List<string> distinct = [];
|
|
FilePath[] deleteCollection;
|
|
PersonBirthday personBirthday;
|
|
string personDisplayDirectory;
|
|
DateTime dateTime = new(ticks);
|
|
string personKeyFormattedDirectory;
|
|
foreach ((PersonKeyFormattedIdThenWholePercentages personKeyFormattedIdThenWholePercentages, PersonContainer personContainer) in possiblyNewPersonDisplayDirectoryNamesAndPersonContainer)
|
|
{
|
|
if (distinct.Contains(personKeyFormattedIdThenWholePercentages.PersonKeyFormatted))
|
|
continue;
|
|
if (a2PeopleSingletonDirectory is null || personContainer.Key is null || personContainer.Birthdays is null || personContainer.PersonDirectory is null || personContainer.Birthdays.Length == 0)
|
|
continue;
|
|
fileName = $"{Path.GetFileName(personKeyFormattedIdThenWholePercentages.MappedFaceFilePath.FullName)}{configuration.FacesHiddenFileNameExtension}";
|
|
personBirthday = personContainer.Birthdays[zero];
|
|
personKey = personBirthday.Value.Ticks;
|
|
personKeyFormatted = IPersonBirthday.GetFormatted(configuration.PersonBirthdayFormat, personBirthday);
|
|
personDisplayDirectory = Path.Combine(a2PeopleSingletonDirectory, personContainer.PersonDirectory.Char.ToString(), personContainer.PersonDirectory.Group, personContainer.DisplayDirectoryName);
|
|
personKeyFormattedDirectory = Path.GetFullPath(Path.Combine(personDisplayDirectory, personKeyFormatted));
|
|
deleteCollection = (from l in personContainer.DisplayDirectoryAllFilePaths where l.FullName.StartsWith(personKeyFormattedDirectory) select l).ToArray();
|
|
if (personContainer.DisplayDirectoryAllFilePaths.Count != 0 && deleteCollection.Length == 0)
|
|
throw new NotSupportedException();
|
|
if (!Directory.Exists(personKeyFormattedDirectory))
|
|
_ = Directory.CreateDirectory(personKeyFormattedDirectory);
|
|
_ = readOnlyPersonKeyToCount.TryGetValue(personKey, out count);
|
|
_ = Directory.CreateDirectory(Path.Combine(personDisplayDirectory, count.ToString("0000")));
|
|
Directory.SetLastWriteTime(personDisplayDirectory, dateTime.AddMinutes(count));
|
|
matches = (from l in personContainer.DisplayDirectoryAllFilePaths where l.FullName.EndsWith(fileName) select true).ToArray();
|
|
if (matches.Length > 0)
|
|
continue;
|
|
matches = (from l in personContainer.DisplayDirectoryAllFilePaths where l.FullName.EndsWith(configuration.FacesHiddenFileNameExtension) select true).ToArray();
|
|
if (matches.Length > 0)
|
|
continue;
|
|
if (!File.Exists(personKeyFormattedIdThenWholePercentages.MappedFaceFilePath.FullName))
|
|
continue;
|
|
checkFile = Path.Combine(personKeyFormattedDirectory, $"{Path.GetFileName(personKeyFormattedIdThenWholePercentages.MappedFaceFilePath.FullName)}{configuration.FacesHiddenFileNameExtension}");
|
|
if (File.Exists(checkFile))
|
|
continue;
|
|
File.Copy(personKeyFormattedIdThenWholePercentages.MappedFaceFilePath.FullName, checkFile);
|
|
foreach (FilePath delete in deleteCollection)
|
|
{
|
|
if (delete.ExtensionLowered == ".lnk")
|
|
continue;
|
|
if (!File.Exists(delete.FullName))
|
|
continue;
|
|
File.Delete(delete.FullName);
|
|
}
|
|
Directory.SetLastWriteTime(personDisplayDirectory, DateTime.Now);
|
|
distinct.Add(personKeyFormattedIdThenWholePercentages.PersonKeyFormatted);
|
|
}
|
|
}
|
|
|
|
internal static void SetPersonKeyToPersonContainer(Configuration configuration, ReadOnlyCollection<PersonContainer> personContainers, ReadOnlyDictionary<long, int> personKeyToCount, Dictionary<long, PersonContainer> personKeyToPersonContainer, ReadOnlyDictionary<long, List<PersonContainer>> personKeyToPersonContainerCollection)
|
|
{
|
|
string? displayDirectoryName;
|
|
foreach (PersonContainer personContainer in personContainers)
|
|
{
|
|
if (personContainer.Key is null || !personKeyToCount.ContainsKey(personContainer.Key.Value))
|
|
continue;
|
|
displayDirectoryName = GetDisplayDirectoryName(personKeyToPersonContainer, personContainer.Key.Value);
|
|
if (displayDirectoryName is not null && (displayDirectoryName == personContainer.DisplayDirectoryName || (displayDirectoryName[0] == personContainer.DisplayDirectoryName[0] && (displayDirectoryName.Length == 1 || personContainer.DisplayDirectoryName.Length == 1))))
|
|
continue;
|
|
personKeyToPersonContainer.Add(personContainer.Key.Value, personContainer);
|
|
}
|
|
if (personKeyToCount.Count > 0)
|
|
{
|
|
const int zero = 0;
|
|
int? approximateYears = null;
|
|
PersonBirthday? personBirthday;
|
|
PersonContainer personContainer;
|
|
List<PersonContainer>? collection;
|
|
displayDirectoryName = configuration.MappingDefaultName;
|
|
foreach (KeyValuePair<long, int> keyValuePair in personKeyToCount)
|
|
{
|
|
if (personKeyToPersonContainer.ContainsKey(keyValuePair.Key))
|
|
continue;
|
|
personBirthday = IPersonBirthday.GetPersonBirthday(keyValuePair.Key);
|
|
if (!personKeyToPersonContainerCollection.TryGetValue(keyValuePair.Key, out collection))
|
|
personContainer = PersonContainer.Get(approximateYears, personBirthday, displayDirectoryName, keyValuePair.Key);
|
|
else
|
|
personContainer = PersonContainer.Get(approximateYears, personBirthday, collection[zero].PersonDirectory, displayDirectoryName, keyValuePair.Key);
|
|
personKeyToPersonContainer.Add(keyValuePair.Key, personContainer);
|
|
}
|
|
}
|
|
}
|
|
|
|
private static string? GetDisplayDirectoryName(Dictionary<long, PersonContainer> personKeyToPersonContainer, long key)
|
|
{
|
|
string? result = null;
|
|
if (personKeyToPersonContainer.TryGetValue(key, out PersonContainer? personContainer))
|
|
{
|
|
result = personContainer.DisplayDirectoryName;
|
|
if (string.IsNullOrEmpty(result))
|
|
throw new NotSupportedException();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
internal static List<LocationContainer> GetLocationContainers(int maxDegreeOfParallelism, Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, Configuration configuration, long ticks, ReadOnlyCollection<PersonContainer> personContainers, ReadOnlyDictionary<int, List<(string, int)>> skipCollection, List<Record> records)
|
|
{
|
|
List<LocationContainer> results = [];
|
|
List<MappedFile> mappedFiles = GetMappedFiles(propertyConfiguration, configuration, personContainers, records);
|
|
if (mappedFiles.Count > 0 && (configuration.DistanceMoveUnableToMatch || configuration.DistanceRenameToMatch))
|
|
{
|
|
int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds);
|
|
string message = $") Building Mapped Face Files Collection - {totalSeconds} total second(s)";
|
|
ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = maxDegreeOfParallelism };
|
|
ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
|
|
using ProgressBar progressBar = new(mappedFiles.Count, message, options);
|
|
_ = Parallel.For(0, mappedFiles.Count, parallelOptions, (i, state) =>
|
|
{
|
|
progressBar.Tick();
|
|
ParallelFor(propertyConfiguration, configuration, skipCollection, results, mappedFiles[i]);
|
|
});
|
|
}
|
|
if (string.IsNullOrEmpty(configuration.LocationContainerDebugDirectory))
|
|
{
|
|
ReadOnlyCollection<LocationContainer> locationContainers = results.OrderBy(l => l.DirectoryNumber).ToArray().AsReadOnly();
|
|
LookForPossibleDuplicates(configuration, locationContainers);
|
|
}
|
|
return results;
|
|
}
|
|
|
|
private static void ParallelFor(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, Configuration configuration, ReadOnlyDictionary<int, List<(string, int)>> skipCollection, List<LocationContainer> locationContainers, MappedFile mappedFile)
|
|
{
|
|
int? id;
|
|
string checkFile;
|
|
DateOnly dateOnly;
|
|
FilePath filePath;
|
|
string[] fileMatches;
|
|
FileHolder fileHolder;
|
|
int? wholePercentages;
|
|
const string lnk = ".lnk";
|
|
ExifDirectory? exifDirectory;
|
|
string personDisplayDirectoryName;
|
|
const bool fromDistanceContent = true;
|
|
List<(string File, int WholePercentages)>? wholePercentagesCollection;
|
|
if (!mappedFile.FilePath.Name.EndsWith(lnk))
|
|
{
|
|
if (mappedFile.FilePath.Id is null)
|
|
return;
|
|
id = mappedFile.FilePath.Id;
|
|
wholePercentages = IMapping.GetWholePercentages(configuration.FacesFileNameExtension, mappedFile.FilePath);
|
|
}
|
|
else
|
|
{
|
|
fileHolder = IFileHolder.Get(mappedFile.FilePath.FullName[..^4]);
|
|
filePath = FilePath.Get(propertyConfiguration, fileHolder, index: null);
|
|
if (filePath.Id is null)
|
|
return;
|
|
id = filePath.Id;
|
|
wholePercentages = IMapping.GetWholePercentages(configuration.FacesFileNameExtension, filePath);
|
|
}
|
|
if (wholePercentages is null)
|
|
return;
|
|
if (configuration.LinkedAlpha is null && string.IsNullOrEmpty(configuration.LocationContainerDebugDirectory) && skipCollection.TryGetValue(id.Value, out wholePercentagesCollection))
|
|
{
|
|
fileMatches = (from l in wholePercentagesCollection where l.WholePercentages == wholePercentages select l.File).ToArray();
|
|
foreach (string fileMatch in fileMatches)
|
|
{
|
|
if (string.IsNullOrEmpty(fileMatch) || !File.Exists(fileMatch))
|
|
continue;
|
|
checkFile = $"{fileMatch}.dup";
|
|
if (File.Exists(checkFile))
|
|
continue;
|
|
File.Move(fileMatch, checkFile);
|
|
continue;
|
|
}
|
|
}
|
|
dateOnly = DateOnly.FromDateTime(new DateTime(mappedFile.FilePath.CreationTicks));
|
|
if (mappedFile.FilePath.Name.EndsWith(lnk) || (!configuration.DistanceMoveUnableToMatch && !configuration.DistanceRenameToMatch) || !File.Exists(mappedFile.FilePath.FullName))
|
|
exifDirectory = null;
|
|
else
|
|
exifDirectory = Metadata.Models.Stateless.Methods.IMetadata.GetExifDirectory(mappedFile.FilePath);
|
|
RectangleF? rectangle = ILocation.GetPercentagesRectangle(configuration.LocationDigits, wholePercentages.Value);
|
|
personDisplayDirectoryName = mappedFile.PersonDisplayDirectoryName is null ? configuration.MappingDefaultName : mappedFile.PersonDisplayDirectoryName;
|
|
LocationContainer locationContainer = new(dateOnly,
|
|
exifDirectory,
|
|
mappedFile.DirectoryNumber,
|
|
personDisplayDirectoryName,
|
|
null,
|
|
null,
|
|
mappedFile.FilePath,
|
|
fromDistanceContent,
|
|
id.Value,
|
|
null,
|
|
null,
|
|
mappedFile.PersonKey,
|
|
rectangle,
|
|
wholePercentages.Value);
|
|
lock (locationContainers)
|
|
locationContainers.Add(locationContainer);
|
|
}
|
|
|
|
private static void LookForPossibleDuplicates(Configuration configuration, ReadOnlyCollection<LocationContainer> locationContainers)
|
|
{
|
|
string key;
|
|
float? percent;
|
|
float itemPercentagesArea;
|
|
List<FilePath> delete = [];
|
|
List<Duplicate> duplicates = [];
|
|
RectangleF? itemPercentagesRectangle;
|
|
(FilePath FilePath, int WholePercentages) item;
|
|
Dictionary<string, (FilePath, int)> distinct = [];
|
|
foreach (LocationContainer locationContainer in locationContainers)
|
|
{
|
|
if (locationContainer.PersonKey is null)
|
|
continue;
|
|
key = string.Concat(locationContainer.PersonKey, locationContainer.Id);
|
|
if (distinct.TryGetValue(key, out item))
|
|
{
|
|
if (item.WholePercentages == locationContainer.WholePercentages)
|
|
continue;
|
|
itemPercentagesRectangle = ILocation.GetPercentagesRectangle(configuration.LocationDigits, item.WholePercentages);
|
|
if (itemPercentagesRectangle is null || locationContainer.Rectangle is null)
|
|
percent = null;
|
|
else
|
|
{
|
|
itemPercentagesArea = itemPercentagesRectangle.Value.Width * itemPercentagesRectangle.Value.Height;
|
|
percent = ILocation.GetIntersectPercent(itemPercentagesRectangle.Value, itemPercentagesArea, locationContainer.Rectangle.Value);
|
|
}
|
|
delete.Add(item.FilePath);
|
|
delete.Add(locationContainer.FilePath);
|
|
duplicates.Add(new(locationContainer.PersonKey.Value, locationContainer.Id, locationContainer.FilePath, percent));
|
|
continue;
|
|
}
|
|
distinct.Add(key, new(locationContainer.FilePath, locationContainer.WholePercentages));
|
|
}
|
|
if (!configuration.DeletePossibleDuplicates && duplicates.Count > 0)
|
|
OpenPossibleDuplicates(configuration, duplicates);
|
|
else
|
|
{
|
|
if (delete.Count > 8)
|
|
throw new Exception("Something maybe wrong!");
|
|
foreach (FilePath filePath in delete)
|
|
{
|
|
if (File.Exists(filePath.FullName))
|
|
File.Delete(filePath.FullName);
|
|
}
|
|
}
|
|
}
|
|
|
|
private static void OpenPossibleDuplicates(Configuration configuration, List<Duplicate> duplicates)
|
|
{
|
|
string personKeyFormatted;
|
|
foreach (Duplicate duplicate in duplicates)
|
|
{
|
|
if (duplicate.Percent is null)
|
|
continue;
|
|
_ = Process.Start("explorer.exe", string.Concat("\"", duplicate.FilePath.DirectoryFullPath, "\""));
|
|
personKeyFormatted = IPersonBirthday.GetFormatted(configuration.PersonBirthdayFormat, duplicate.PersonKey);
|
|
}
|
|
foreach ((long personKey, int id, FilePath filePath, float? percent) in duplicates)
|
|
{
|
|
if (percent is not null && percent.Value == 0)
|
|
continue;
|
|
_ = Process.Start("explorer.exe", string.Concat("\"", filePath.DirectoryFullPath, "\""));
|
|
personKeyFormatted = IPersonBirthday.GetFormatted(configuration.PersonBirthdayFormat, personKey);
|
|
}
|
|
foreach ((long personKey, int id, FilePath filePath, float? percent) in duplicates)
|
|
{
|
|
if (percent is not null && percent.Value > 0)
|
|
continue;
|
|
_ = Process.Start("explorer.exe", string.Concat("\"", filePath.DirectoryFullPath, "\""));
|
|
personKeyFormatted = IPersonBirthday.GetFormatted(configuration.PersonBirthdayFormat, personKey);
|
|
}
|
|
}
|
|
|
|
internal static ReadOnlyDictionary<int, ReadOnlyDictionary<int, ReadOnlyCollection<PersonContainer>>> GetIdThenWholePercentagesToPersonContainers(Configuration configuration, Dictionary<int, List<(string, int)>> skipCollection, ReadOnlyDictionary<string, PersonContainer> personKeyFormattedToPersonContainer, ReadOnlyCollection<PersonKeyFormattedIdThenWholePercentages> personKeyFormattedIdThenWholePercentagesCollection)
|
|
{
|
|
ReadOnlyDictionary<int, ReadOnlyDictionary<int, ReadOnlyCollection<PersonContainer>>> results;
|
|
Dictionary<int, Dictionary<int, List<PersonContainer>>> idThenWholePercentagesToPersonContainerCollection;
|
|
idThenWholePercentagesToPersonContainerCollection = GetAll(configuration, skipCollection, personKeyFormattedToPersonContainer, personKeyFormattedIdThenWholePercentagesCollection);
|
|
results = GetReadOnly(idThenWholePercentagesToPersonContainerCollection);
|
|
return results;
|
|
}
|
|
|
|
private static Dictionary<int, Dictionary<int, List<PersonContainer>>> GetAll(Configuration configuration, Dictionary<int, List<(string, int)>> skipCollection, ReadOnlyDictionary<string, PersonContainer> personKeyFormattedToPersonContainer, ReadOnlyCollection<PersonKeyFormattedIdThenWholePercentages> personKeyFormattedIdThenWholePercentagesCollection)
|
|
{
|
|
Dictionary<int, Dictionary<int, List<PersonContainer>>> results = [];
|
|
PersonBirthday? personBirthday;
|
|
PersonContainer? personContainer;
|
|
List<PersonContainer>? personContainers;
|
|
Dictionary<int, List<PersonContainer>>? idTo;
|
|
int? linkedAlphaCheck = string.IsNullOrEmpty(configuration.LinkedAlpha) ? null : configuration.LinkedAlpha[0] - 65;
|
|
if (personKeyFormattedIdThenWholePercentagesCollection.Count > 0)
|
|
{
|
|
foreach (PersonKeyFormattedIdThenWholePercentages personKeyFormattedIdThenWholePercentages in personKeyFormattedIdThenWholePercentagesCollection)
|
|
{
|
|
personBirthday = IPersonBirthday.GetPersonBirthday(configuration.PersonBirthdayFormat, personKeyFormattedIdThenWholePercentages.PersonKeyFormatted);
|
|
if (personBirthday is null)
|
|
throw new Exception();
|
|
if (linkedAlphaCheck is not null && personKeyFormattedIdThenWholePercentages.LinksCount is not null && personKeyFormattedIdThenWholePercentages.LinksCount.Value < linkedAlphaCheck.Value)
|
|
{
|
|
if (!skipCollection.ContainsKey(personKeyFormattedIdThenWholePercentages.Id))
|
|
skipCollection.Add(personKeyFormattedIdThenWholePercentages.Id, []);
|
|
skipCollection[personKeyFormattedIdThenWholePercentages.Id].Add((personKeyFormattedIdThenWholePercentages.MappedFaceFilePath.FullName, personKeyFormattedIdThenWholePercentages.WholePercentages));
|
|
continue;
|
|
}
|
|
if (!personKeyFormattedToPersonContainer.TryGetValue(personKeyFormattedIdThenWholePercentages.PersonKeyFormatted, out personContainer))
|
|
continue;
|
|
if (!results.TryGetValue(personKeyFormattedIdThenWholePercentages.Id, out idTo))
|
|
{
|
|
results.Add(personKeyFormattedIdThenWholePercentages.Id, []);
|
|
if (!results.TryGetValue(personKeyFormattedIdThenWholePercentages.Id, out idTo))
|
|
throw new Exception();
|
|
}
|
|
if (!idTo.TryGetValue(personKeyFormattedIdThenWholePercentages.WholePercentages, out personContainers))
|
|
{
|
|
idTo.Add(personKeyFormattedIdThenWholePercentages.WholePercentages, []);
|
|
if (!idTo.TryGetValue(personKeyFormattedIdThenWholePercentages.WholePercentages, out personContainers))
|
|
throw new Exception();
|
|
}
|
|
personContainers.Add(personContainer);
|
|
}
|
|
}
|
|
return results;
|
|
}
|
|
|
|
internal static void SetKeyValuePairsAndAddToCollections(Configuration configuration, ReadOnlyCollection<PersonContainer> personContainers, Dictionary<long, PersonContainer> personKeyToPersonContainer, ReadOnlyCollection<PersonKeyFormattedIdThenWholePercentages> personKeyFormattedIdThenWholePercentagesCollection, Dictionary<long, int> personKeyToCount, Dictionary<string, PersonContainer> personKeyFormattedToPersonContainer, Dictionary<long, List<PersonContainer>> personKeyToPersonContainerCollection, List<(PersonKeyFormattedIdThenWholePercentages, PersonContainer)> possiblyNewPersonDisplayDirectoryNamesAndPersonContainer)
|
|
{
|
|
PersonBirthday? personBirthday;
|
|
Dictionary<int, Dictionary<int, List<PersonContainer>>> idThenWholePercentagesToPersonContainers = [];
|
|
(long, PersonContainer)[] collection = GetDistinctCollection(configuration, personContainers, personKeyToPersonContainerCollection, personKeyFormattedToPersonContainer);
|
|
foreach ((long personKey, PersonContainer personContainer) in collection)
|
|
personKeyToPersonContainer.Add(personKey, personContainer);
|
|
if (personKeyFormattedIdThenWholePercentagesCollection.Count > 0)
|
|
{
|
|
string group;
|
|
char[] matches;
|
|
char status, sex, first;
|
|
PersonDirectory personDirectory;
|
|
PersonContainer? personContainer;
|
|
string personDisplayDirectoryName;
|
|
foreach (PersonKeyFormattedIdThenWholePercentages personKeyFormattedIdThenWholePercentages in personKeyFormattedIdThenWholePercentagesCollection)
|
|
{
|
|
personBirthday = IPersonBirthday.GetPersonBirthday(configuration.PersonBirthdayFormat, personKeyFormattedIdThenWholePercentages.PersonKeyFormatted);
|
|
if (personBirthday is null)
|
|
throw new Exception();
|
|
if (!personKeyFormattedToPersonContainer.TryGetValue(personKeyFormattedIdThenWholePercentages.PersonKeyFormatted, out personContainer))
|
|
{
|
|
personDisplayDirectoryName = personKeyFormattedIdThenWholePercentages.PersonDisplayDirectoryName is null ? configuration.MappingDefaultName : personKeyFormattedIdThenWholePercentages.PersonDisplayDirectoryName;
|
|
matches = configuration.PersonCharacters.Where(l => personDisplayDirectoryName.Contains(l)).ToArray();
|
|
if (matches.Length == 0)
|
|
continue;
|
|
group = IPerson.GetHourGroup(personKeyFormattedIdThenWholePercentages.PersonDisplayDirectoryName, personBirthday.Value.Hour);
|
|
(status, sex, first) = IPerson.GetPersonHour(personKeyFormattedIdThenWholePercentages.PersonDisplayDirectoryName, personBirthday.Value.Hour);
|
|
personDirectory = new(matches.First(), group, status, sex, first);
|
|
personContainer = PersonContainer.Get(configuration.PersonCharacters.ToArray(), personBirthday, personDisplayDirectoryName, personDirectory);
|
|
personKeyFormattedToPersonContainer.Add(personKeyFormattedIdThenWholePercentages.PersonKeyFormatted, personContainer);
|
|
}
|
|
if (personContainer.Key is null)
|
|
throw new Exception();
|
|
_ = personKeyToCount.TryAdd(personContainer.Key.Value, 0);
|
|
personKeyToCount[personContainer.Key.Value]++;
|
|
possiblyNewPersonDisplayDirectoryNamesAndPersonContainer.Add(new(personKeyFormattedIdThenWholePercentages, personContainer));
|
|
}
|
|
}
|
|
}
|
|
|
|
private static (long, PersonContainer)[] GetDistinctCollection(Configuration configuration, IEnumerable<PersonContainer> personContainers, Dictionary<long, List<PersonContainer>> personKeyToPersonContainerCollection, Dictionary<string, PersonContainer> personKeyFormattedToPersonContainer)
|
|
{
|
|
(long, PersonContainer)[] results;
|
|
const int zero = 0;
|
|
List<string> errors = [];
|
|
string newestPersonKeyFormatted;
|
|
List<(long PersonKey, PersonContainer PersonContainer)> collection = [];
|
|
foreach (PersonContainer personContainer in personContainers)
|
|
{
|
|
if (personContainer.Key is null)
|
|
continue;
|
|
if (!personKeyToPersonContainerCollection.ContainsKey(personContainer.Key.Value))
|
|
personKeyToPersonContainerCollection.Add(personContainer.Key.Value, []);
|
|
personKeyToPersonContainerCollection[personContainer.Key.Value].Add(personContainer);
|
|
newestPersonKeyFormatted = IPersonBirthday.GetFormatted(configuration.PersonBirthdayFormat, personContainer.Key.Value);
|
|
_ = personKeyFormattedToPersonContainer.TryAdd(newestPersonKeyFormatted, personContainer);
|
|
}
|
|
foreach (KeyValuePair<long, List<PersonContainer>> keyValuePair in personKeyToPersonContainerCollection)
|
|
{
|
|
if (keyValuePair.Value.Count != 1 && (from l in keyValuePair.Value select l.DisplayDirectoryName).Distinct().Count() != 1)
|
|
errors.Add(keyValuePair.Value[zero].DisplayDirectoryName);
|
|
collection.Add(new(keyValuePair.Key, keyValuePair.Value[zero]));
|
|
}
|
|
if (errors.Count > 0)
|
|
throw new Exception(string.Join(Environment.NewLine, errors));
|
|
results = (from l in collection orderby l.PersonKey descending select (l.PersonKey, l.PersonContainer)).ToArray();
|
|
return results;
|
|
}
|
|
|
|
} |