using System.Text.Json; using System.Text.RegularExpressions; namespace View_by_Distance.Shared.Models.Stateless.Methods; internal abstract class Person { // ... private static List ValidatePerson(Properties.IStorage storage, string personBirthdayFormat, Models.PersonId id, Models.PersonBirthday birthday, Models.PersonName name) { List results = new(); if (birthday is null) throw new Exception("Birthday must be supplied!"); if (birthday.Value > DateTime.Now) results.Add("Birthday must be in the past!"); if (id is null) throw new Exception("Birthday must be supplied!"); if (id.Value != birthday.Value.Ticks) results.Add("Id must be Birthday ticks!"); if (name.First is null || string.IsNullOrEmpty(name.First.Value)) results.Add("Fist Name must be supplied!"); if (PersonBirthday.DoesBirthDateExits(storage, personBirthdayFormat, birthday)) results.Add("BirthDate already exits!"); return results; } internal static Models.Person CreatePerson(Properties.IStorage storage, string personBirthdayFormat, Models.PersonBirthday birthday, Models.PersonName name, List comments, List urls, List numbers, List emails, List addresses) { Models.Person result; Models.PersonId id = new(birthday.Value.Ticks); if (birthday.Value == DateTime.MinValue) birthday = PersonBirthday.GetNextBirthDate(storage); List results = ValidatePerson(storage, personBirthdayFormat, id, birthday, name); if (results.Any()) throw new Exception(string.Join(Environment.NewLine, results)); if (comments is null) comments = new(); if (urls is null) urls = new(); if (numbers is null) numbers = new(); if (emails is null) emails = new(); if (addresses is null) addresses = new(); result = new(id, birthday, name, comments, urls, numbers, emails, addresses); return result; } private static void SetSegments(ref string[] segments, string KeyFormat, ref DateTime incrementDate) { if (segments[0].Length != KeyFormat.Length || !segments[0].Contains('-') || !segments[0].Contains('_')) { List temporarySegments; temporarySegments = segments.ToList(); temporarySegments.Insert(0, incrementDate.ToString(KeyFormat)); segments = temporarySegments.ToArray(); incrementDate = incrementDate.AddDays(1); } } internal static Dictionary Split(int personBirthdayFirstYear, string personKeyFormat, string knownPeopleFile) { Dictionary results = new(); string[] segments; DateTime personKey; DateTime incrementDate = new(personBirthdayFirstYear, 1, 1); string[] lines = File.ReadAllLines(knownPeopleFile); _ = incrementDate.AddDays(lines.Length); System.Globalization.CultureInfo cultureInfo = System.Globalization.CultureInfo.InvariantCulture; foreach (string line in lines) { if (string.IsNullOrEmpty(line)) continue; segments = line.Replace(" //", "\t//").Split('\t'); if (segments.Length < 1) continue; SetSegments(ref segments, personKeyFormat, ref incrementDate); personKey = DateTime.ParseExact(segments[0], personKeyFormat, cultureInfo); if (results.ContainsKey(personKey)) continue; results.Add(personKey, segments); } if (results.Any()) { int countBefore = results.Count; DateTime minimumDateTime = results.Keys.Min(); for (int i = 1; i < (1000 - countBefore); i++) { personKey = minimumDateTime.AddDays(i * -1); results.Add(personKey, new string[] { personKey.ToString(personKeyFormat) }); } } return results.OrderBy(l => l.Key).ToDictionary(l => l.Key, l => l.Value); } private static void SetValues(ref string name, ref string comment, ref string mergeName, KeyValuePair splitLine) { foreach (string segment in splitLine.Value) { if (!segment.Contains('*')) continue; mergeName = segment.Split('*')[1].Split('\t')[0]; } if (splitLine.Value[1].StartsWith("//")) comment = splitLine.Value[1]; else name = splitLine.Value[1].Split('\t')[0]; if (splitLine.Value.Length > 2) comment = splitLine.Value[2]; } private static void CheckSplitLineAndSetValues(ref string name, ref string comment, ref string mergeName, KeyValuePair splitLine) { if (splitLine.Value.Length > 1) SetValues(ref name, ref comment, ref mergeName, splitLine); } private static Dictionary GetPersonCollection(int personBirthdayFirstYear, string personKeyFormat, string knownPeopleFile) { Dictionary results = new(); string name; DateTime key; string comment; string oldName; string mergeName; PersonImport person; Dictionary splitLines = Split(personBirthdayFirstYear, personKeyFormat, knownPeopleFile); foreach (KeyValuePair splitLine in splitLines) { name = string.Empty; key = splitLine.Key; comment = string.Empty; oldName = string.Empty; mergeName = string.Empty; CheckSplitLineAndSetValues(ref name, ref comment, ref mergeName, splitLine); person = new(key, name, mergeName, oldName, comment); results.Add(splitLine.Key, person); } return results; } internal static void SavePerson(Properties.IStorage storage, string personBirthdayFormat, Models.Person person) { string fileName = IPerson.GetFileFullName(storage, personBirthdayFormat, person); string json = JsonSerializer.Serialize(person, new JsonSerializerOptions { WriteIndented = true }); _ = IStorage.WriteAllText(fileName, json, updateDateWhenMatches: true, compareBeforeWrite: true); } private static string GetComment(List urls, List comments, KeyValuePair keyValuePair) { string result = keyValuePair.Value.Comment[2..]; if (!string.IsNullOrEmpty(result)) { if (result.StartsWith("http://") || result.StartsWith("https://")) urls.Add(new(new(result))); else comments.Add(new(new(result))); } return result; } private static List GetPeopleFromText(Properties.IStorage storage, int personBirthdayFirstYear, string personBirthdayFormat, string personKeyFormat, string localKnownPeopleFile) { List results = new(); string comment; Models.Person person; Models.PersonName name; List urls; Models.PersonBirthday birthday; List comments; List emails = new(); List numbers = new(); List addresses = new(); Dictionary keyValuePairs = GetPersonCollection(personBirthdayFirstYear, personKeyFormat, localKnownPeopleFile); foreach (KeyValuePair keyValuePair in keyValuePairs) { if (string.IsNullOrEmpty(keyValuePair.Value.Name)) continue; urls = new(); comments = new(); birthday = new(keyValuePair.Key); name = PersonName.Create(keyValuePair.Value.Name); if (name.First is null || string.IsNullOrEmpty(name.First.Value)) continue; if (!string.IsNullOrEmpty(keyValuePair.Value.Comment)) comment = GetComment(urls, comments, keyValuePair); if (!string.IsNullOrEmpty(keyValuePair.Value.OldName)) comments.Add(new(new(keyValuePair.Value.OldName))); person = IPerson.CreatePerson(storage, personBirthdayFormat, birthday, name, comments, urls, numbers, emails, addresses); SavePerson(storage, personBirthdayFormat, person); results.Add(person); } return results; } internal static Models.Person[] GetPeople(Properties.IStorage storage, int personBirthdayFirstYear, string personBirthdayFormat, string personKeyFormat) { List results = new(); string json; string[] files; FileInfo fileInfo; Models.Person? person; string localKnownPeopleFile; DateTime dateTime = DateTime.MinValue; string peopleContentDirectory = Path.Combine(storage.PeopleRootDirectory, "()"); string peopleSingletonDirectory = Path.Combine(storage.PeopleRootDirectory, "{}"); if (!Directory.Exists(peopleSingletonDirectory)) _ = Directory.CreateDirectory(peopleSingletonDirectory); if (!Directory.Exists(peopleContentDirectory)) localKnownPeopleFile = string.Empty; else { files = Directory.GetFiles(peopleContentDirectory, "*People*.txt", SearchOption.TopDirectoryOnly); if (files.Any()) localKnownPeopleFile = files[0]; else localKnownPeopleFile = string.Empty; } files = Directory.GetFiles(peopleSingletonDirectory, "*.json", SearchOption.TopDirectoryOnly); if (!files.Any() && string.IsNullOrEmpty(localKnownPeopleFile)) throw new Exception("Copy \"KnownPeople.txt\" file from server!"); foreach (string file in files) { fileInfo = new(file); if (dateTime < fileInfo.LastWriteTime) dateTime = fileInfo.LastWriteTime; json = File.ReadAllText(file); person = JsonSerializer.Deserialize(json); if (person is null) continue; results.Add(person); } if (!results.Any()) results = GetPeopleFromText(storage, personBirthdayFirstYear, personBirthdayFormat, personKeyFormat, localKnownPeopleFile); else if (!string.IsNullOrEmpty(localKnownPeopleFile)) { fileInfo = new FileInfo(localKnownPeopleFile); if (fileInfo.LastWriteTime > dateTime) { foreach (string file in files) File.Delete(file); results = GetPeopleFromText(storage, personBirthdayFirstYear, personBirthdayFormat, personKeyFormat, localKnownPeopleFile); } } SaveToDirectory(storage, personBirthdayFormat, results); return results.ToArray(); } private static void SaveToDirectory(Properties.IStorage storage, string personBirthdayFormat, List people) { int years; TimeSpan? timeSpan; string personDirectory; string? personFullName; DateTime createdDateTime; string birthdayDirectory; string personJsonFileName; string personDirectoryName; string? peopleDirectory = null; DateTime dateTime = DateTime.Now; string? personJsonFileNameWithoutExtension; const string pattern = @"[\\,\/,\:,\*,\?,\"",\<,\>,\|]"; foreach (Models.Person person in people) { personJsonFileName = IPerson.GetFileFullName(storage, personBirthdayFormat, person); if (string.IsNullOrEmpty(peopleDirectory)) peopleDirectory = Path.GetDirectoryName(personJsonFileName); if (string.IsNullOrEmpty(peopleDirectory)) break; personJsonFileNameWithoutExtension = Path.GetFileNameWithoutExtension(personJsonFileName); if (string.IsNullOrEmpty(personJsonFileNameWithoutExtension)) break; personFullName = Regex.Replace(person.GetFullName(), pattern, string.Empty); timeSpan = IPersonBirthday.GetTimeSpan(dateTime, person.Birthday); if (timeSpan is null || timeSpan.Value.Ticks < 0) personDirectoryName = $"{personFullName}~"; else { createdDateTime = new FileInfo(personJsonFileName).CreationTime; (years, timeSpan) = IPersonBirthday.GetAge(createdDateTime, person.Birthday); personDirectoryName = $"{personFullName}^{years}-{Math.Floor(timeSpan.Value.TotalDays):000}"; } personDirectory = Path.Combine(peopleDirectory, personDirectoryName); if (!Directory.Exists(personDirectory)) _ = Directory.CreateDirectory(personDirectory); birthdayDirectory = Path.Combine(personDirectory, personJsonFileNameWithoutExtension); if (!Directory.Exists(birthdayDirectory)) { _ = Directory.CreateDirectory(birthdayDirectory); File.Copy(personJsonFileName, Path.Combine(birthdayDirectory, $"{personJsonFileNameWithoutExtension}.json")); } } } }