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 MappedFile(long PersonKey, string PersonKeyFormatted, string? PersonDisplayDirectoryName, int? DirectoryNumber, FilePath FilePath); internal record Duplicate(long PersonKey, int Id, FilePath FilePath, float? Percent); internal record PersonKeyFormattedIdThenWholePercentages(string PersonKeyFormatted, string? PersonDisplayDirectoryName, bool? IsDefault, FilePath MappedFaceFilePath, int Id, int WholePercentages); internal static void SetSkipCollections(Configuration configuration, ReadOnlyCollection personContainers, string? a2PeopleSingletonDirectory, Dictionary> skipCollection, Dictionary> skipNotSkipCollection) { string checkFile; int? wholePercentages; List distinct = []; List distinctFiles = []; List 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(l => filePath.FullName.StartsWith(l))) { 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 void SetPersonCollections(Configuration configuration, ReadOnlyCollection personContainers, Dictionary personKeyFormattedToNewestPersonKeyFormatted, List 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 string GetMappingSegmentB(long ticks, long personKey, int? approximateYears, MappingFromItem mappingFromItem) { string result; PersonBirthday personBirthday = IPersonBirthday.GetPersonBirthday(personKey); result = GetMappingSegmentB(ticks, personBirthday, approximateYears, mappingFromItem.GetDateTimeOriginalThenMinimumDateTime(), 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 Mapping[] GetSelectedMappingCollection(ReadOnlyCollection items) { Mapping[] results; ReadOnlyCollection faces = GetFaces(items); results = GetSelectedMappingCollection(faces); return results; } internal static Mapping[] GetSelectedMappingCollection(ReadOnlyCollection faces) { Mapping[] results; IEnumerable 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 GetFaces(ReadOnlyCollection items) { List results = []; foreach (Item item in items) { if (item.Property?.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 new(results); } internal static string GetMappingSegmentB(long ticks, PersonBirthday personBirthday, int? approximateYears, MappingFromItem mappingFromItem) { string result = GetMappingSegmentB(ticks, personBirthday, approximateYears, mappingFromItem.GetDateTimeOriginalThenMinimumDateTime(), mappingFromItem.IsWrongYear); return result; } private static List GetDisplayDirectoryAllFiles(string fileNameExtension, string personBirthdayFormat, ReadOnlyCollection personContainers) { List results = []; string personKeyFormatted; List 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); results.Add(new(personContainer.Key.Value, personKeyFormatted, personContainer.DisplayDirectoryName, null, personContainer.DisplayDirectoryAllFilePaths[i])); } } return results; } private static void OpenPossibleDuplicates(Configuration configuration, List duplicates) { string personKeyFormatted; foreach (Duplicate duplicate in duplicates) { if (duplicate.Percent is null) continue; _ = Process.Start("explorer.exe", string.Concat("\"", duplicate.FilePath.DirectoryName, "\"")); 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.DirectoryName, "\"")); 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.DirectoryName, "\"")); personKeyFormatted = IPersonBirthday.GetFormatted(configuration.PersonBirthdayFormat, personKey); } } internal static string GetFacesDirectory(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string dFacesContentDirectory, FilePath filePath, MappingFromItem mappingFromItem) { string result; (string directoryName, _) = IPath.GetDirectoryNameAndIndex(propertyConfiguration, filePath); result = Path.Combine(dFacesContentDirectory, directoryName, mappingFromItem.ImageFileHolder.NameWithoutExtension); return result; } 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 (long, PersonContainer)[] GetDistinctCollection(Configuration configuration, IEnumerable personContainers, Dictionary> personKeyToPersonContainerCollection, Dictionary personKeyFormattedToPersonContainer) { (long, PersonContainer)[] results; const int zero = 0; List 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> 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; } private static Dictionary>> GetAll(Configuration configuration, ReadOnlyDictionary personKeyFormattedToPersonContainer, ReadOnlyCollection personKeyFormattedIdThenWholePercentagesCollection) { Dictionary>> results = []; PersonBirthday? personBirthday; PersonContainer? personContainer; List? personContainers; Dictionary>? idTo; if (personKeyFormattedIdThenWholePercentagesCollection.Count > 0) { 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)) throw new Exception(); 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; } private static ReadOnlyDictionary>> GetReadOnly(Dictionary>> idThenWholePercentagesToPersonContainerCollection) { Dictionary>> results = []; List distinct = []; List personContainers; Dictionary> keyValuePairs; foreach (KeyValuePair>> idTo in idThenWholePercentagesToPersonContainerCollection) { keyValuePairs = []; foreach (KeyValuePair> 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, new(personContainers)); } results.Add(idTo.Key, new(keyValuePairs)); } return new(results); } private static ReadOnlyDictionary> GetReadOnly(Dictionary> keyValuePairs) { Dictionary> results = []; foreach (KeyValuePair> keyValuePair in keyValuePairs) results.Add(keyValuePair.Key, new(keyValuePair.Value)); return new(results); } private static List GetNonSpecificPeopleCollection(Configuration configuration, long ticks, List personKeys, ReadOnlyDictionary personKeyToCount) { List results = []; bool check; long personKey; int? approximateYears = null; PersonBirthday personBirthday; PersonContainer personContainer; List 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 = new(approximateYears, [personBirthday], new(personDisplayDirectoryAllFilePaths), configuration.MappingDefaultName, personKey); results.Add(personContainer); if (results.Count > 99) break; } return results; } private static string? GetDisplayDirectoryName(Dictionary 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; } private static List GetMappedFiles(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, Configuration configuration, ReadOnlyCollection personContainers, List records) { List results = []; long personKey; string checkFile; FilePath filePath; FileHolder fileHolder; List distinct = []; PersonBirthday? personBirthday; 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; distinct.Add(record.MappedFaceFilePath.Name); personKey = personBirthday.Value.Ticks; results.Add(new(personKey, record.PersonKeyFormatted, record.PersonDisplayDirectoryName, record.DirectoryNumber, record.MappedFaceFilePath)); } 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(".dup") && !filePath.Name.EndsWith(".unk") && !filePath.Name.EndsWith(".abd")) continue; if (!File.Exists(filePath.Name)) 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(results[i].PersonKey, results[i].PersonKeyFormatted, results[i].PersonDisplayDirectoryName, results[i].DirectoryNumber, filePath); } return results; } private static void ParallelFor(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, Configuration configuration, Dictionary> skipCollection, List 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 (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; lock (locationContainers) locationContainers.Add(new(dateOnly, exifDirectory, mappedFile.DirectoryNumber, personDisplayDirectoryName, mappedFile.FilePath, fromDistanceContent, id.Value, null, mappedFile.PersonKey, rectangle, wholePercentages.Value)); } private static void LookForPossibleDuplicates(Configuration configuration, ReadOnlyCollection locationContainers) { string key; float? percent; float itemPercentagesArea; List delete = []; List duplicates = []; RectangleF? itemPercentagesRectangle; (FilePath FilePath, int WholePercentages) item; Dictionary distinct = []; foreach (LocationContainer locationContainer in locationContainers) { 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, 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); } } } 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.ImageFileHolder.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.ImageFileHolder.ExtensionLowered}{facesFileNameExtension}")); if (!faceFileHolder.Exists) saveContainer = null; else { string checkFile = Path.Combine(directory, $"{keyMapping.MappingFromLocation.DeterministicHashCodeKey}{keyMapping.MappingFromItem.ImageFileHolder.ExtensionLowered}{facesFileNameExtension}"); saveContainer = new(checkFile, directory, faceFileHolder); } } return (result, saveContainer); } private static IEnumerable<(string, string)> GetCollection(string[] yearDirectories) { foreach (string l in yearDirectories) yield return new(l, Path.GetFileName(l)); } 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 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 SetKeyValuePairsAndAddToCollections(Configuration configuration, ReadOnlyCollection personContainers, Dictionary personKeyToPersonContainer, ReadOnlyCollection personKeyFormattedIdThenWholePercentagesCollection, Dictionary personKeyToCount, Dictionary personKeyFormattedToPersonContainer, Dictionary> personKeyToPersonContainerCollection, List<(PersonKeyFormattedIdThenWholePercentages, PersonContainer)> possiblyNewPersonDisplayDirectoryNamesAndPersonContainer) { PersonBirthday? personBirthday; Dictionary>> 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) throw new NotSupportedException(); 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 = new(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)); } } } internal static ReadOnlyDictionary>> GetIdThenWholePercentagesToPersonContainers(Configuration configuration, ReadOnlyDictionary personKeyFormattedToPersonContainer, ReadOnlyCollection personKeyFormattedIdThenWholePercentagesCollection) { ReadOnlyDictionary>> results; Dictionary>> idThenWholePercentagesToPersonContainerCollection; idThenWholePercentagesToPersonContainerCollection = GetAll(configuration, personKeyFormattedToPersonContainer, personKeyFormattedIdThenWholePercentagesCollection); results = GetReadOnly(idThenWholePercentagesToPersonContainerCollection); return results; } internal static ReadOnlyCollection GetPersonKeyFormattedIdThenWholePercentages(Configuration configuration, long ticks, List records) { List results = []; int? wholePercentages; List wholePercentagesCollection; Dictionary> idToWholePercentagesCollection = []; 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); results.Add(new(record.PersonKeyFormatted, record.PersonDisplayDirectoryName, record.IsDefault, record.MappedFaceFilePath, record.MappedFaceFilePath.Id.Value, wholePercentages.Value)); } return new(results); } internal static List GetNotMappedPersonContainers(Configuration configuration, long ticks, ReadOnlyCollection personContainers, ReadOnlyDictionary personKeyToCount) { List results = []; List notMappedAndNotNamedPersonKeys = []; List notMappedAndWithNamedPersonKeys = []; List 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; } internal static void SetPersonKeyToPersonContainer(Configuration configuration, ReadOnlyCollection personContainers, ReadOnlyDictionary personKeyToCount, Dictionary personKeyToPersonContainer, ReadOnlyDictionary> 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? collection; displayDirectoryName = configuration.MappingDefaultName; foreach (KeyValuePair keyValuePair in personKeyToCount) { if (personKeyToPersonContainer.ContainsKey(keyValuePair.Key)) continue; personBirthday = IPersonBirthday.GetPersonBirthday(keyValuePair.Key); if (!personKeyToPersonContainerCollection.TryGetValue(keyValuePair.Key, out collection)) personContainer = new(approximateYears, personBirthday, displayDirectoryName, keyValuePair.Key); else personContainer = new(approximateYears, personBirthday, collection[zero].PersonDirectory, displayDirectoryName, keyValuePair.Key); personKeyToPersonContainer.Add(keyValuePair.Key, personContainer); } } } internal static void PossiblyRebuildPersonContainers(Configuration configuration, long ticks, string? a2PeopleSingletonDirectory, ReadOnlyDictionary readOnlyPersonKeyToCount, ReadOnlyCollection<(PersonKeyFormattedIdThenWholePercentages, PersonContainer)> possiblyNewPersonDisplayDirectoryNamesAndPersonContainer) { int count; long personKey; bool[] matches; string fileName; string checkFile; const int zero = 0; string personKeyFormatted; List 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 List GetLocationContainers(int maxDegreeOfParallelism, Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, Configuration configuration, long ticks, ReadOnlyCollection personContainers, Dictionary> skipCollection, List records) { List results = []; List 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 locationContainers = new(results.OrderBy(l => l.DirectoryNumber).ToArray()); LookForPossibleDuplicates(configuration, locationContainers); } return results; } internal static int CopyManualFiles(Configuration configuration, long ticks, ReadOnlyCollection personContainers, string eDistanceContentTicksDirectory) { int result = 0; string checkFile; string dateDirectory; string directoryName; string checkDirectory; string personKeyFormatted; List 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].DirectoryName); 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? 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.ImageFileHolder.Name}{extension}"); return result; } internal static string GetFacePartsDirectory(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string d2FacePartsContentDirectory, FilePath filePath, MappingFromItem mappingFromItem) { string result; (string directoryName, _) = IPath.GetDirectoryNameAndIndex(propertyConfiguration, filePath); result = Path.Combine(d2FacePartsContentDirectory, directoryName, mappingFromItem.ImageFileHolder.NameWithoutExtension); return result; } 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.ImageFileHolder.ExtensionLowered}.{sortingContainer.Sorting.DistancePermyriad}.lnk"); else shortcutFile = Path.Combine(directory, $"{sortingContainer.Source.MappingFromLocation.DeterministicHashCodeKey}{sortingContainer.Source.MappingFromItem.ImageFileHolder.ExtensionLowered}.{sortingContainer.Sorting.DistancePermyriad}.lnk"); result = new(directory, faceFileHolder, sortingContainer.Source.MappingFromItem.ResizedFileHolder, shortcutFile); return result; } 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.ImageFileHolder.Name}{facePartsFileNameExtension}"); saveContainer = !facePartsFileHolder.Exists ? null : new(checkFile, directory, facePartsFileHolder); checkFile = Path.Combine(directory, $"{mapping.MappingFromLocation.DeterministicHashCodeKey}{mapping.MappingFromItem.ImageFileHolder.ExtensionLowered}{facesFileNameExtension}"); return (new(checkFile, directory, faceFileHolder), saveContainer); } 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) { } } } internal static ReadOnlyDictionary> GetIdToPersonKeys(ReadOnlyDictionary> personKeyToIds) { Dictionary> results = []; List? collection; foreach (KeyValuePair> 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 new(results); } internal static ReadOnlyDictionary> GetIdToWholePercentagesToFace(ReadOnlyCollection mappingCollection) { Dictionary> results = []; Dictionary? keyValuePairs; foreach (Mapping mapping in mappingCollection) { 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); } 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 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; } internal static (string, bool, bool) Get(int? useFiltersCounter, bool saveIndividually, bool sortingContainersAny, string forceSingleImageHumanized, int? distancePermyriad, Mapping mapping) { string by; bool isByMapping; bool isBySorting; if (mapping.By is null) { isByMapping = false; isBySorting = !sortingContainersAny; by = $"{nameof(Shared.Models.Stateless.IMapLogic.Mapping)}Null"; } else { isByMapping = mapping.By == Shared.Models.Stateless.IMapLogic.Mapping; isBySorting = mapping.By == Shared.Models.Stateless.IMapLogic.Sorting; bool isDefaultName = mapping.MappingFromPerson is not null && IPerson.IsDefaultName(mapping.MappingFromPerson.DisplayDirectoryName); if (isBySorting && mapping.MappingFromPerson is null) by = saveIndividually ? nameof(Shared.Models.Stateless.IMapLogic.Individually) : $"{nameof(Shared.Models.Stateless.IMapLogic.Sorting)} Without Person{(distancePermyriad < 2000 ? "-A" : "-Z")}"; else if (isBySorting && useFiltersCounter.HasValue) by = $"{nameof(Shared.Models.Stateless.IMapLogic.Sorting)}{(!isDefaultName ? "-A" : "-Z")} Modified Filters - {useFiltersCounter.Value}"; else { by = $"{mapping.By.Value switch { Shared.Models.Stateless.IMapLogic.Mapping => nameof(Shared.Models.Stateless.IMapLogic.Mapping), Shared.Models.Stateless.IMapLogic.Sorting => saveIndividually ? nameof(Shared.Models.Stateless.IMapLogic.Individually) : nameof(Shared.Models.Stateless.IMapLogic.Sorting), Shared.Models.Stateless.IMapLogic.ForceSingleImage => forceSingleImageHumanized, _ => throw new NotImplementedException() }}{(!isDefaultName ? "-A" : "-Z")}"; } } return new(by, isByMapping, isBySorting); } internal static void CheckCollection(Shared.Models.Properties.IPropertyConfiguration propertyConfiguration, string? rootDirectoryParent) { string json; string fullPath; List>? 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>>(json); if (collection is null) throw new NullReferenceException(nameof(collection)); } } internal static ReadOnlyDictionary> ConvertSkip(Dictionary> skipCollection) { Dictionary> results = []; List? wholePercentagesCollection; foreach (KeyValuePair> 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 new(results); } internal static ReadOnlyDictionary> ConvertSkipNotSkip(Dictionary> skipNotSkipCollection) { Dictionary> results = []; List? wholePercentagesCollection; foreach (KeyValuePair> 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 new(results); } internal static ReadOnlyDictionary> ConvertLocationContainers(List locationContainers) { Dictionary> results = []; foreach (LocationContainer locationContainer in locationContainers) { if (!results.ContainsKey(locationContainer.Id)) results.Add(locationContainer.Id, []); results[locationContainer.Id].Add(locationContainer); } return new(results); } internal static bool? CanReMap(long[] jLinkResolvedPersonKeys, ReadOnlyDictionary>? wholePercentagesToPersonContainers, MappingFromLocation mappingFromLocation) { bool? result; ReadOnlyCollection? personContainers; if (wholePercentagesToPersonContainers is null) result = null; else { if (!wholePercentagesToPersonContainers.TryGetValue(mappingFromLocation.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; } }