using System.Collections.ObjectModel; namespace View_by_Distance.Shared.Models.Stateless.Methods; internal abstract class PersonContainer { private static string[] GetFiles(string personDisplayDirectory, bool isDefaultName) { List results = new(); string[] files; string extension; string checkFile; string directoryName; List distinct = new(); string fileNameWithoutExtension; string personDisplayDirectoryName = Path.GetFileName(personDisplayDirectory); results.AddRange(Directory.GetFiles(personDisplayDirectory, "*", SearchOption.TopDirectoryOnly)); string[] directories = Directory.GetDirectories(personDisplayDirectory, "*", SearchOption.TopDirectoryOnly); foreach (string directory in directories) { directoryName = Path.GetFileName(directory); files = Directory.GetFiles(directory, "*", SearchOption.TopDirectoryOnly); foreach (string file in files) { extension = Path.GetExtension(file); if (extension is not ".json" and not ".pged") { results.Add(file); continue; } fileNameWithoutExtension = Path.GetFileNameWithoutExtension(file); if (string.IsNullOrEmpty(fileNameWithoutExtension) || string.IsNullOrEmpty(personDisplayDirectoryName)) continue; else if (fileNameWithoutExtension.Length == 1 && fileNameWithoutExtension[0] == personDisplayDirectoryName[0]) { if (distinct.Contains(file)) throw new NotSupportedException($"Move / Delete <{file}>"); distinct.Add(file); } else if (fileNameWithoutExtension != directoryName && !isDefaultName) { checkFile = Path.Combine(directory, $"{fileNameWithoutExtension}{extension}"); if (!File.Exists(checkFile)) { File.Move(file, checkFile); results.Add(checkFile); } else { checkFile = Path.Combine(directory, $"{fileNameWithoutExtension}.txt"); if (File.Exists(checkFile)) File.Delete(checkFile); File.Move(file, checkFile); } continue; } results.Add(file); } } return results.ToArray(); } private static string[] GetFiles(string facesFileNameExtension, string personDisplayDirectory, bool isDefaultName) { string[] results; int? id; string checkFile; int? wholePercentages; string? checkDirectory; string[] files = Directory.GetFiles(personDisplayDirectory, "*", SearchOption.TopDirectoryOnly); foreach (string file in files) { if (file.EndsWith(".lnk")) continue; (id, wholePercentages) = IMapping.GetConverted(facesFileNameExtension, file); if (id is not null && wholePercentages is not null) continue; checkDirectory = Path.GetDirectoryName(file); if (string.IsNullOrEmpty(checkDirectory)) continue; checkDirectory = Path.Combine(checkDirectory, "_ Invalid"); if (!Directory.Exists(checkDirectory)) _ = Directory.CreateDirectory(checkDirectory); checkFile = Path.Combine(checkDirectory, Path.GetFileName(file)); if (File.Exists(checkFile)) File.Delete(file); else File.Move(file, checkFile); } results = GetFiles(personDisplayDirectory, isDefaultName); return results; } private static List GetPersonContainersCollections(string mappingDefaultName, string facesFileNameExtension, char[] personCharacters, ReadOnlyDictionary individuals, PersonDirectory personDirectory, char numberSign, string personDisplayDirectory, string personDisplayDirectoryName, bool isDefaultName, int? approximateYears, List<(string PersonKeyFormatted, Models.PersonBirthday PersonBirthday)> collection) { List results = new(); long personKey; const int zero = 0; Models.Person person; string[]? individualsLines; Models.PersonContainer personContainer; Models.PersonBirthday[] orderedPersonBirthdays; string[] personDisplayDirectoryAllFiles = GetFiles(facesFileNameExtension, personDisplayDirectory, isDefaultName); foreach ((string personKeyFormatted, Models.PersonBirthday personBirthday) in collection) { _ = individuals.TryGetValue(personKeyFormatted, out individualsLines); orderedPersonBirthdays = (from l in collection where !l.PersonKeyFormatted.Contains(numberSign) orderby l.PersonBirthday.Value.Ticks descending select l.PersonBirthday).ToArray(); if (!orderedPersonBirthdays.Any()) personKey = collection[zero].PersonBirthday.Value.Ticks; else { if (personKeyFormatted.Contains(numberSign)) continue; personKey = orderedPersonBirthdays[zero].Value.Ticks; } person = IPerson.GetPerson(mappingDefaultName, personCharacters, personDisplayDirectoryName, personDisplayDirectoryAllFiles, personKey); personContainer = new(approximateYears, orderedPersonBirthdays, personDisplayDirectoryAllFiles, personDisplayDirectoryName, individualsLines, personKey, person, personDirectory); results.Add(personContainer); } return results; } internal static string? VerifyAge(char numberSign, string personDisplayDirectory, string? minusOne, string personDisplayDirectoryName, int? approximateYears, List<(string PersonKeyFormatted, Models.PersonBirthday PersonBirthday)> collection) { string? result; if (approximateYears is null) throw new NotSupportedException(); if (!collection.Any()) throw new NotSupportedException(); const int zero = 0; int? updateApproximateYears; DateTime dateTime = DateTime.Now; Models.PersonBirthday[] orderedPersonBirthdays = (from l in collection where !l.PersonKeyFormatted.Contains(numberSign) orderby l.PersonBirthday.Value.Ticks descending select l.PersonBirthday).ToArray(); TimeSpan timeSpan = new(orderedPersonBirthdays[zero].Value.Ticks - dateTime.AddYears(-approximateYears.Value).Ticks); if (timeSpan.TotalDays < -366) updateApproximateYears = approximateYears.Value + 1; else if (timeSpan.TotalDays > 1) updateApproximateYears = approximateYears.Value - 1; else updateApproximateYears = null; if (minusOne is null || updateApproximateYears is null) result = null; else { result = Path.Combine(minusOne, $"{personDisplayDirectoryName.Split('^')[0]}^{updateApproximateYears}"); if (Directory.Exists(result)) result = null; else Directory.Move(personDisplayDirectory, result); } return result; } private static (List, List) GetPersonContainersGroup(string mappingDefaultName, string personBirthdayFormat, string facesFileNameExtension, char[] personCharacters, ReadOnlyDictionary individuals, PersonDirectory personDirectory, string[] personDisplayDirectories) { List results = new(); string? minusOne; bool isDefaultName; int? approximateYears; char numberSign = '#'; List changes = new(); string[] personKeyDirectories; string? personDisplayDirectoryName; Models.PersonContainer personContainer; string[] personDisplayDirectoryAllFiles; List personContainers; List<(string, Models.PersonBirthday)> collection; foreach (string personDisplayDirectory in personDisplayDirectories) { personDisplayDirectoryName = Path.GetFileName(personDisplayDirectory); if (string.IsNullOrEmpty(personDisplayDirectoryName)) continue; isDefaultName = IPerson.IsDefaultName(mappingDefaultName, personDisplayDirectoryName); approximateYears = Age.GetApproximateYears(personCharacters, personDisplayDirectoryName); personKeyDirectories = Directory.GetDirectories(personDisplayDirectory, "*", SearchOption.TopDirectoryOnly); collection = PersonBirthday.GetPersonBirthdays(personBirthdayFormat, personKeyDirectories, personDisplayDirectory, personDisplayDirectoryName); if (personDisplayDirectoryName.Contains('^')) { minusOne = Path.GetDirectoryName(personDisplayDirectory); if (minusOne is null) continue; changes.Add(VerifyAge(numberSign, personDisplayDirectory, minusOne, personDisplayDirectoryName, approximateYears, collection)); } if (changes.Any(l => l is not null)) continue; if (collection.Any()) { personContainers = GetPersonContainersCollections(mappingDefaultName, facesFileNameExtension, personCharacters, individuals, personDirectory, numberSign, personDisplayDirectory, personDisplayDirectoryName, isDefaultName, approximateYears, collection); results.AddRange(personContainers); } else { personDisplayDirectoryAllFiles = GetFiles(facesFileNameExtension, personDisplayDirectory, isDefaultName); personContainer = new(approximateYears, personDisplayDirectoryAllFiles, personDisplayDirectoryName, personDirectory); results.Add(personContainer); } } return new(changes, results); } private static (List, List) GetPersonContainersInnerGroups(string mappingDefaultName, string personBirthdayFormat, string facesFileNameExtension, char[] personCharacters, ReadOnlyDictionary individuals, string groupDirectory, string groupDirectoryName) { List results = new(); string[] segments; const int zero = 0; List changes; string innerGroupDirectoryName; PersonDirectory personDirectory; List allChanges = new(); string[] personDisplayDirectories; const char exclamationPoint = '!'; char @char = groupDirectoryName[zero]; List collection; string[] innerGroupDirectories = Directory.GetDirectories(groupDirectory, "*", SearchOption.TopDirectoryOnly); if (@char == exclamationPoint) { personDirectory = new(@char, "Ignore", 'U', 'U', 'U'); (changes, collection) = GetPersonContainersGroup(mappingDefaultName, personBirthdayFormat, facesFileNameExtension, personCharacters, individuals, personDirectory, innerGroupDirectories); allChanges.AddRange(changes); results.AddRange(collection); } else { foreach (string innerGroupDirectory in innerGroupDirectories) { innerGroupDirectoryName = Path.GetFileName(innerGroupDirectory); segments = innerGroupDirectoryName.Split('-'); if (!segments.Any()) throw new NotSupportedException("Misplaced directory!"); if (segments.Length != 3) continue; if (segments[zero] is not "Alive" and not "Dead" and not "Unknown") continue; if (segments[1] is not "Male" and not "Female" and not "Unknown") continue; if (segments[2] is not "Yes" and not "No" and not "Unknown") continue; personDirectory = new(@char, innerGroupDirectoryName, segments[zero][zero], segments[1][zero], segments[2][zero]); personDisplayDirectories = Directory.GetDirectories(innerGroupDirectory, "*", SearchOption.TopDirectoryOnly); (changes, collection) = GetPersonContainersGroup(mappingDefaultName, personBirthdayFormat, facesFileNameExtension, personCharacters, individuals, personDirectory, personDisplayDirectories); allChanges.AddRange(changes); results.AddRange(collection); } } return new(allChanges, results); } private static List GetPersonContainersGroups(string mappingDefaultName, string personBirthdayFormat, string facesFileNameExtension, char[] personCharacters, ReadOnlyDictionary individuals, string[] groupDirectories) { List results; const int zero = 0; List changes; string groupDirectoryName; List allChanges = new(); List collection; List personContainers = new(); foreach (string groupDirectory in groupDirectories) { groupDirectoryName = Path.GetFileName(groupDirectory); if (!personCharacters.Contains(groupDirectoryName[zero])) continue; (changes, collection) = GetPersonContainersInnerGroups(mappingDefaultName, personBirthdayFormat, facesFileNameExtension, personCharacters, individuals, groupDirectory, groupDirectoryName); allChanges.AddRange(changes); personContainers.AddRange(collection); } if (allChanges.Any(l => l is not null)) throw new NotImplementedException($"A directory was changed restart to look for more! {string.Join(Environment.NewLine, (from l in allChanges where l is not null select l).ToArray())}"); results = (from l in personContainers orderby l.Key is not null, l.Key select l).ToList(); return results; } internal static List GetPersonContainers(Properties.IStorage storage, string mappingDefaultName, string personBirthdayFormat, char[] personCharacters, string facesFileNameExtension, ReadOnlyDictionary individuals) { List results; string a2PeopleSingletonDirectory = Path.Combine(storage.PeopleRootDirectory, "{}"); if (!Directory.Exists(a2PeopleSingletonDirectory)) _ = Directory.CreateDirectory(a2PeopleSingletonDirectory); string a2PeopleSingletonDirectoryChar; foreach (char personCharacter in personCharacters) { a2PeopleSingletonDirectoryChar = Path.Combine(a2PeopleSingletonDirectory, personCharacter.ToString()); if (!Directory.Exists(a2PeopleSingletonDirectoryChar)) _ = Directory.CreateDirectory(a2PeopleSingletonDirectoryChar); } string[] groupDirectories = Directory.GetDirectories(a2PeopleSingletonDirectory, "*", SearchOption.TopDirectoryOnly); if (!groupDirectories.Any()) results = new(); else results = GetPersonContainersGroups(mappingDefaultName, personBirthdayFormat, facesFileNameExtension, personCharacters, individuals, groupDirectories); return results; } internal static List<(long?, string)> GetDisplay(string personBirthdayFormat, Models.PersonContainer personContainer) { List<(long?, string)> results = new(); string personKeyFormatted; Models.PersonContainer pc = personContainer; if (pc.Person is null || pc.Key is null || pc.Birthdays is null || !pc.Birthdays.Any()) results.Add(new(pc.Key, string.Concat('\t', pc.Key, '\t', pc.ApproximateYears, '\t', pc.DisplayDirectoryName))); else { foreach (Models.PersonBirthday personBirthday in pc.Birthdays) { personKeyFormatted = IPersonBirthday.GetFormatted(personBirthdayFormat, personBirthday); results.Add(new(pc.Key, string.Concat(personKeyFormatted, '\t', pc.Key, '\t', pc.ApproximateYears, '\t', pc.DisplayDirectoryName))); } } return results; } internal static List GetPersonKeys(IEnumerable personContainers) { List results = new(); long personKey; foreach (Models.PersonContainer personContainer in personContainers) { if (personContainer.Person is null || personContainer.Key is null || personContainer.Birthdays is null || !personContainer.Birthdays.Any()) continue; foreach (Models.PersonBirthday personBirthday in personContainer.Birthdays) { personKey = personBirthday.Value.Ticks; results.Add(personKey); } } return results; } internal static List GetNonSpecificPeopleCollection(string mappingDefaultName, int personBirthdayFirstYear, char[] personCharacters, List personContainers, long ticks) { List results = new(); long personKey; Models.Person person; int? approximateYears = null; Models.PersonBirthday personBirthday; Models.PersonContainer personContainer; List personKeys = GetPersonKeys(personContainers); string[] personDisplayDirectoryAllFiles = Array.Empty(); DateTime incrementDate = new(personBirthdayFirstYear, 1, 1); for (int i = 0; i < int.MaxValue; i++) { personKey = incrementDate.Ticks; incrementDate = incrementDate.AddDays(1); if (incrementDate.Ticks > ticks) break; if (personKeys.Contains(personKey)) continue; personBirthday = IPersonBirthday.GetPersonBirthday(personKey); person = IPerson.GetPerson(mappingDefaultName, personCharacters, mappingDefaultName, personKey, personBirthday); personContainer = new(approximateYears, new Models.PersonBirthday[] { personBirthday }, personDisplayDirectoryAllFiles, mappingDefaultName, personKey, person); results.Add(personContainer); } return results; } private static ReadOnlyDictionary GetPersonKeyFormattedToPersonFullName(string personBirthdayFormat, List personContainers) { Dictionary results = new(); string? value; string personFullName; string personKeyFormatted; foreach (Models.PersonContainer personContainer in personContainers) { if (personContainer.Key is null || personContainer.Birthdays is null || personContainer.Person is null || personContainer.PersonDirectory is null || !personContainer.Birthdays.Any()) continue; personKeyFormatted = IPersonBirthday.GetFormatted(personBirthdayFormat, personContainer.Key.Value); personFullName = PersonName.GetFullName(personContainer.Person.Name); if (!results.TryGetValue(personKeyFormatted, out value)) results.Add(personKeyFormatted, personFullName); else if (value != personFullName) throw new NotSupportedException(); } return new(results); } private static ReadOnlyDictionary> GetFamilyIndexToCollection(List genealogicalDataCommunicationRelations) { Dictionary> results = new(); List? relations; foreach (GenealogicalDataCommunicationRelation genealogicalDataCommunicationRelation in genealogicalDataCommunicationRelations) { if (!results.TryGetValue(genealogicalDataCommunicationRelation.FamilyIndex, out relations)) { results.Add(genealogicalDataCommunicationRelation.FamilyIndex, new()); if (!results.TryGetValue(genealogicalDataCommunicationRelation.FamilyIndex, out relations)) throw new NotSupportedException(); } relations.Add(genealogicalDataCommunicationRelation); } return new(results); } internal static void MaybeWriteFiles(string mappingDefaultName, string personBirthdayFormat, long ticks, List genealogicalDataCommunicationRelations, List personContainers, string a2PeopleContentDirectory) { bool? male; bool? first; string[] matches; string? directory; bool isDefaultName; bool verify = true; const int zero = 0; string personKeyFormatted; Models.GenealogicalDataCommunication genealogicalDataCommunication; GenealogicalDataCommunicationLines? genealogicalDataCommunicationLines; ReadOnlyDictionary personKeyFormattedToPersonFullName = GetPersonKeyFormattedToPersonFullName(personBirthdayFormat, personContainers); ReadOnlyDictionary> familyIndexToCollection = GetFamilyIndexToCollection(genealogicalDataCommunicationRelations); foreach (Models.PersonContainer personContainer in personContainers.OrderByDescending(l => l.Key)) { if (personContainer.Key is null || personContainer.Birthdays is null || personContainer.Person is null || personContainer.PersonDirectory is null || !personContainer.Birthdays.Any()) continue; male = personContainer.PersonDirectory.Sex == 'U' ? null : personContainer.PersonDirectory.Sex == 'M' || (personContainer.PersonDirectory.Sex == 'F' ? false : throw new Exception()); first = personContainer.PersonDirectory.First == 'U' ? null : personContainer.PersonDirectory.First == 'Y' || (personContainer.PersonDirectory.First == 'N' ? false : throw new Exception()); if (first is null) continue; isDefaultName = IPerson.IsDefaultName(mappingDefaultName, personContainer.DisplayDirectoryName); personKeyFormatted = IPersonBirthday.GetFormatted(personBirthdayFormat, personContainer.Key.Value); matches = (from l in personContainer.DisplayDirectoryAllFiles where l.Contains(personKeyFormatted) select l).ToArray(); if (!matches.Any()) continue; directory = Path.GetDirectoryName(matches[zero]); if (directory is null) continue; genealogicalDataCommunicationLines = personContainer.GenealogicalDataCommunicationRelationIndividualsLines is null ? null : GenealogicalDataCommunication.GetGenealogicalDataCommunicationLines(personContainer.Birthdays[zero], personContainer.GenealogicalDataCommunicationRelationIndividualsLines); if (genealogicalDataCommunicationLines is null) continue; genealogicalDataCommunication = GenealogicalDataCommunication.GetGenealogicalDataCommunication(genealogicalDataCommunicationLines); if (genealogicalDataCommunication.Sex != personContainer.PersonDirectory.Sex) continue; if (genealogicalDataCommunication.Death is null && personContainer.PersonDirectory.Status == 'D' || genealogicalDataCommunication.Death is not null && personContainer.PersonDirectory.Status == 'A') continue; GenealogicalDataCommunication.WriteFile(personKeyFormatted, personContainer.Person.Name, personContainer.GenealogicalDataCommunicationRelationIndividualsLines, isDefaultName, directory, genealogicalDataCommunication, verify, first.Value); MarkDown.WriteFile(personKeyFormatted, ticks, personContainer.Person.Name, genealogicalDataCommunicationRelations, a2PeopleContentDirectory, personKeyFormattedToPersonFullName, familyIndexToCollection, isDefaultName, genealogicalDataCommunication, first.Value); } } }