Family Tree as Markdown Files

This commit is contained in:
2023-07-16 23:06:08 -07:00
parent 240c1ef6f9
commit b2fe53275f
15 changed files with 594 additions and 202 deletions

View File

@ -2,7 +2,17 @@ using System.Text.Json;
namespace View_by_Distance.Shared.Models;
public record GenealogicalDataCommunication(string? Id, string? UId, string? Name, string? GivenName, string? SurName, string? Suffix, string? NickName, char Sex, DateTime? Birth, DateTime? Death, DateTime? Changed)
public record GenealogicalDataCommunication(string? Id,
string? UId,
string? Name,
string? GivenName,
string? SurName,
string? Suffix,
string? NickName,
char Sex,
DateTime? Birth,
DateTime? Death,
DateTime? Changed)
{
public override string ToString()

View File

@ -2,7 +2,17 @@ using System.Text.Json;
namespace View_by_Distance.Shared.Models;
public record GenealogicalDataCommunicationLines(string? Id, string? UId, string? Name, string? GivenName, string? SurName, string? Suffix, string? NickName, string? Sex, List<string> Birth, List<string> Death, List<string> Changed)
public record GenealogicalDataCommunicationLines(string? Id,
string? UId,
string? Name,
string? GivenName,
string? SurName,
string? Suffix,
string? NickName,
string? Sex,
List<string> Birth,
List<string> Death,
List<string> Changed)
{
public override string ToString()

View File

@ -0,0 +1,18 @@
using System.Text.Json;
namespace View_by_Distance.Shared.Models;
public record GenealogicalDataCommunicationRelation(int FamilyIndex,
string Relation,
string Id,
string NickName,
string? LineTwo)
{
public override string ToString()
{
string result = JsonSerializer.Serialize(this, new JsonSerializerOptions() { WriteIndented = true });
return result;
}
}

View File

@ -10,18 +10,20 @@ public class PersonContainer : Properties.IPersonContainer
public PersonBirthday[]? Birthdays { init; get; }
public string[] DisplayDirectoryAllFiles { init; get; }
public string DisplayDirectoryName { init; get; }
public string[]? GenealogicalDataCommunicationRelationIndividualsLines { init; get; }
public long? Key { init; get; }
public bool? KeyIsMaxBirthday { init; get; }
public Person? Person { init; get; }
public PersonDirectory? PersonDirectory { init; get; }
[JsonConstructor]
public PersonContainer(int? approximateYears, PersonBirthday[]? birthdays, string[] displayDirectoryAllFiles, string displayDirectoryName, long? key, Person? person, PersonDirectory? personDirectory)
public PersonContainer(int? approximateYears, PersonBirthday[]? birthdays, string[] displayDirectoryAllFiles, string displayDirectoryName, string[]? genealogicalDataCommunicationRelationIndividualsLines, long? key, Person? person, PersonDirectory? personDirectory)
{
ApproximateYears = approximateYears;
Birthdays = birthdays;
DisplayDirectoryAllFiles = displayDirectoryAllFiles;
DisplayDirectoryName = displayDirectoryName;
GenealogicalDataCommunicationRelationIndividualsLines = genealogicalDataCommunicationRelationIndividualsLines;
Key = key;
Person = person;
PersonDirectory = personDirectory;
@ -29,23 +31,23 @@ public class PersonContainer : Properties.IPersonContainer
}
public PersonContainer(string mappingDefaultName, char[] personCharacters, PersonBirthday birthday, string displayDirectoryName) :
this(Stateless.Methods.IAge.GetApproximateYears(personCharacters, displayDirectoryName), new PersonBirthday[] { birthday }, Array.Empty<string>(), displayDirectoryName, birthday.Value.Ticks, Stateless.Methods.IPerson.GetPerson(mappingDefaultName, personCharacters, displayDirectoryName, birthday.Value.Ticks, birthday), null)
this(Stateless.Methods.IAge.GetApproximateYears(personCharacters, displayDirectoryName), new PersonBirthday[] { birthday }, Array.Empty<string>(), displayDirectoryName, null, birthday.Value.Ticks, Stateless.Methods.IPerson.GetPerson(mappingDefaultName, personCharacters, displayDirectoryName, birthday.Value.Ticks, birthday), null)
{ }
public PersonContainer(int? approximateYears, PersonBirthday birthdays, string displayDirectoryName, long key) :
this(approximateYears, new PersonBirthday[] { birthdays }, Array.Empty<string>(), displayDirectoryName, key, null, null)
this(approximateYears, new PersonBirthday[] { birthdays }, Array.Empty<string>(), displayDirectoryName, null, key, null, null)
{ }
public PersonContainer(int? approximateYears, PersonBirthday birthdays, PersonDirectory? personDirectory, string displayDirectoryName, long key) :
this(approximateYears, new PersonBirthday[] { birthdays }, Array.Empty<string>(), displayDirectoryName, key, null, personDirectory)
this(approximateYears, new PersonBirthday[] { birthdays }, Array.Empty<string>(), displayDirectoryName, null, key, null, personDirectory)
{ }
public PersonContainer(int? approximateYears, string[] displayDirectoryAllFiles, string displayDirectoryName, PersonDirectory? personDirectory) :
this(approximateYears, null, displayDirectoryAllFiles, displayDirectoryName, null, null, personDirectory)
this(approximateYears, null, displayDirectoryAllFiles, displayDirectoryName, null, null, null, personDirectory)
{ }
public PersonContainer(int? approximateYears, PersonBirthday[]? birthdays, string[] displayDirectoryAllFiles, string displayDirectoryName, long? key, Person? person) :
this(approximateYears, birthdays, displayDirectoryAllFiles, displayDirectoryName, key, person, null)
this(approximateYears, birthdays, displayDirectoryAllFiles, displayDirectoryName, null, key, person, null)
{ }
public override string ToString()

View File

@ -7,6 +7,7 @@ public interface IPersonContainer
public PersonBirthday[]? Birthdays { init; get; }
public string[] DisplayDirectoryAllFiles { init; get; }
public string DisplayDirectoryName { init; get; }
public string[]? GenealogicalDataCommunicationRelationIndividualsLines { init; get; }
public long? Key { init; get; }
public bool? KeyIsMaxBirthday { init; get; }
public Person? Person { init; get; }

View File

@ -1,3 +1,5 @@
using System.Collections.ObjectModel;
namespace View_by_Distance.Shared.Models.Stateless.Methods;
internal abstract class GenealogicalDataCommunication
@ -17,13 +19,52 @@ internal abstract class GenealogicalDataCommunication
return results.ToArray();
}
internal static (string[] headerLines, Dictionary<string, List<string>> individuals, string[] footerLines) GetIndividuals(string genealogicalDataCommunicationFile, bool requireNickName)
private static List<GenealogicalDataCommunicationRelation> GetRelations(Dictionary<string, string> idToNick, List<string[]> familyGroupLines)
{
Dictionary<string, List<string>> results = new();
List<GenealogicalDataCommunicationRelation> results = new();
string? nick;
string relation;
string[] segments;
string[] familyLines;
for (int i = 0; i < familyGroupLines.Count; i++)
{
familyLines = familyGroupLines[i];
for (int j = 0; j < familyLines.Length; j++)
{
segments = familyLines[j].Split('@');
if (segments.First().Length < 3 || segments.Length != 3)
continue;
if (!idToNick.TryGetValue(segments[1], out nick))
continue;
relation = segments.First()[2..].Trim();
if (j + 1 >= familyLines.Length || familyLines[j + 1].Length < 3 || familyLines[j + 1][..3] != "2 _")
results.Add(new(i, relation, segments[1], nick, null));
else
results.Add(new(i, relation, segments[1], nick, familyLines[j + 1][2..]));
}
}
return results;
}
private static ReadOnlyDictionary<string, string[]> Convert(Dictionary<string, List<string>> keyValuePairs)
{
Dictionary<string, string[]> results = new();
foreach (KeyValuePair<string, List<string>> keyValuePair in keyValuePairs)
results.Add(keyValuePair.Key, keyValuePair.Value.ToArray());
return new(results);
}
internal static (string[], ReadOnlyDictionary<string, string[]>, List<string[]>, string[], List<GenealogicalDataCommunicationRelation> genealogicalDataCommunicationRelations) GetIndividuals(string genealogicalDataCommunicationFile, bool requireNickName)
{
ReadOnlyDictionary<string, string[]> results;
string? nick;
string[] segments;
List<string> lines = new();
const string startsWith = "0 @";
List<string> footerLines = new();
List<string[]> familyGroupLines = new();
Dictionary<string, string> idToNick = new();
Dictionary<string, List<string>> keyValuePairs = new();
string[] sourceLines = string.IsNullOrEmpty(genealogicalDataCommunicationFile) || !File.Exists(genealogicalDataCommunicationFile) ? Array.Empty<string>() : File.ReadAllLines(genealogicalDataCommunicationFile);
string[] headerLines = GetHeaderLines(startsWith, sourceLines);
for (int i = headerLines.Length; i < sourceLines.Length; i++)
@ -36,13 +77,29 @@ internal abstract class GenealogicalDataCommunication
continue;
else if (sourceLines[i].EndsWith("@ FAM"))
{
for (int j = i + 1; j < sourceLines.Length; j++)
lines.Clear();
for (int j = sourceLines.Length - 1; j >= i; j--)
{
lines.Add(sourceLines[j]);
footerLines.AddRange(lines);
if (sourceLines[j].First() == '0')
{
if (!sourceLines[j].EndsWith("@ FAM"))
footerLines.AddRange(lines);
else
{
lines.Reverse();
familyGroupLines.Add(lines.ToArray());
}
lines.Clear();
}
}
familyGroupLines.Reverse();
footerLines.Reverse();
break;
}
else if (sourceLines[i].EndsWith("@ INDI"))
{
segments = sourceLines[i].Split('@');
for (int j = i + 1; j < sourceLines.Length; j++)
{
if (sourceLines[j].StartsWith(startsWith))
@ -51,26 +108,30 @@ internal abstract class GenealogicalDataCommunication
if (!sourceLines[j].StartsWith("2 NICK "))
continue;
nick = sourceLines[j][7..];
if (segments.Length == 3)
idToNick.Add(segments[1], nick);
}
if (requireNickName && string.IsNullOrEmpty(nick))
throw new Exception(string.Join(Environment.NewLine, lines));
nick ??= Guid.NewGuid().ToString();
results.Add(nick, new());
keyValuePairs.Add(nick, new());
if (!lines.Any())
continue;
results[nick].AddRange(lines);
keyValuePairs[nick].AddRange(lines);
lines.Clear();
}
else
throw new NotSupportedException();
}
return (headerLines, results, footerLines.ToArray());
results = Convert(keyValuePairs);
List<GenealogicalDataCommunicationRelation> genealogicalDataCommunicationRelations = GetRelations(idToNick, familyGroupLines);
return (headerLines, results, familyGroupLines, footerLines.ToArray(), genealogicalDataCommunicationRelations);
}
private static string[] GetFilteredOutMapped(List<string> individualsLines)
private static string[] GetFilteredOutMapped(string[] individualsLines)
{
List<string> results = new();
for (int i = 0; i < individualsLines.Count; i++)
for (int i = 0; i < individualsLines.Length; i++)
{
if (individualsLines[i].StartsWith("0 @I"))
continue;
@ -90,19 +151,19 @@ internal abstract class GenealogicalDataCommunication
continue;
else if (individualsLines[i] == "1 BIRT")
{
if (individualsLines.Count > i + 1 && individualsLines[i + 1].StartsWith("2 DATE"))
if (individualsLines.Length > i + 1 && individualsLines[i + 1].StartsWith("2 DATE"))
i += 1;
continue;
}
else if (individualsLines[i].StartsWith("1 DEAT"))
{
if (individualsLines.Count > i + 1 && individualsLines[i + 1].StartsWith("2 DATE"))
if (individualsLines.Length > i + 1 && individualsLines[i + 1].StartsWith("2 DATE"))
i += 1;
continue;
}
else if (individualsLines[i] == "1 CHAN")
{
if (individualsLines.Count > i + 1 && individualsLines[i + 1].StartsWith("2 DATE"))
if (individualsLines.Length > i + 1 && individualsLines[i + 1].StartsWith("2 DATE"))
i += 1;
continue;
}
@ -116,9 +177,9 @@ internal abstract class GenealogicalDataCommunication
List<string> results = new();
Models.PersonBirthday personBirthday = new(DateTime.Now);
GenealogicalDataCommunicationLines genealogicalDataCommunicationLines;
(string[] headerLines, Dictionary<string, List<string>> individuals, string[] footerLines) = GetIndividuals(genealogicalDataCommunicationFile, requireNickName);
(string[] headerLines, ReadOnlyDictionary<string, string[]> individuals, List<string[]> familyGroupLines, string[] footerLines, _) = GetIndividuals(genealogicalDataCommunicationFile, requireNickName);
results.AddRange(headerLines);
foreach (KeyValuePair<string, List<string>> keyValuePair in individuals)
foreach (KeyValuePair<string, string[]> keyValuePair in individuals)
{
genealogicalDataCommunicationLines = GetGenealogicalDataCommunicationLines(personBirthday, keyValuePair.Value);
if (!string.IsNullOrEmpty(genealogicalDataCommunicationLines.Id))
@ -139,11 +200,13 @@ internal abstract class GenealogicalDataCommunication
results.AddRange(genealogicalDataCommunicationLines.Death);
results.AddRange(genealogicalDataCommunicationLines.Changed);
}
for (int i = 0; i < familyGroupLines.Count; i++)
results.AddRange(familyGroupLines[i]);
results.AddRange(footerLines);
return results;
}
internal static GenealogicalDataCommunicationLines GetGenealogicalDataCommunicationLines(Models.PersonBirthday personBirthday, List<string> individualsLines)
internal static GenealogicalDataCommunicationLines GetGenealogicalDataCommunicationLines(Models.PersonBirthday personBirthday, string[] individualsLines)
{
GenealogicalDataCommunicationLines result;
string? idLine = null;
@ -157,7 +220,7 @@ internal abstract class GenealogicalDataCommunication
List<string> birthLines = new();
List<string> deathLines = new();
List<string> changedLines = new();
for (int i = 0; i < individualsLines.Count; i++)
for (int i = 0; i < individualsLines.Length; i++)
{
if (idLine is null && individualsLines[i].EndsWith("@ INDI"))
idLine = individualsLines[i];
@ -178,7 +241,7 @@ internal abstract class GenealogicalDataCommunication
else if (!birthLines.Any() && individualsLines[i] == "1 BIRT")
{
birthLines.Add(individualsLines[i]);
if (individualsLines.Count > i + 1 && individualsLines[i + 1].StartsWith("2 DATE"))
if (individualsLines.Length > i + 1 && individualsLines[i + 1].StartsWith("2 DATE"))
{
i += 1;
birthLines.Add(individualsLines[i]);
@ -187,7 +250,7 @@ internal abstract class GenealogicalDataCommunication
else if (!deathLines.Any() && individualsLines[i].StartsWith("1 DEAT"))
{
deathLines.Add(individualsLines[i]);
if (individualsLines.Count > i + 1 && individualsLines[i + 1].StartsWith("2 DATE"))
if (individualsLines.Length > i + 1 && individualsLines[i + 1].StartsWith("2 DATE"))
{
i += 1;
deathLines.Add(individualsLines[i]);
@ -196,7 +259,7 @@ internal abstract class GenealogicalDataCommunication
else if (!changedLines.Any() && individualsLines[i] == "1 CHAN")
{
changedLines.Add(individualsLines[i]);
if (individualsLines.Count > i + 1 && individualsLines[i + 1].StartsWith("2 DATE"))
if (individualsLines.Length > i + 1 && individualsLines[i + 1].StartsWith("2 DATE"))
{
i += 1;
changedLines.Add(individualsLines[i]);
@ -259,7 +322,7 @@ internal abstract class GenealogicalDataCommunication
return result;
}
internal static void WriteFile(string personKeyFormatted, Models.PersonName personName, List<string>? individualsLines, bool isDefaultName, string directory, Models.GenealogicalDataCommunication genealogicalDataCommunication, bool verify, bool first)
internal static void WriteFile(string personKeyFormatted, Models.PersonName personName, string[]? individualsLines, bool isDefaultName, string directory, Models.GenealogicalDataCommunication genealogicalDataCommunication, bool verify, bool first)
{
if (verify)
{
@ -287,64 +350,65 @@ internal abstract class GenealogicalDataCommunication
_ = Directory.CreateDirectory(directory);
if (first && !personKeyFormatted.EndsWith(code))
personKeyFormatted = $"{personKeyFormatted[..^2]}{code}";
List<string> pGedLines = new();
List<string> lines = new();
if (individualsLines is null || !individualsLines.Any())
pGedLines.Add($"0 @I{personKeyFormatted}@ INDI");
lines.Add($"0 @I{personKeyFormatted}@ INDI");
else
{
if (!individualsLines[0].StartsWith("0 @I"))
throw new NotSupportedException();
pGedLines.Add(individualsLines[0]);
lines.Add(individualsLines[0]);
}
pGedLines.Add($"1 NAME {personName.First.Value} /{personName.Last.Value}/{jrOrSr}");
lines.Add($"1 NAME {personName.First.Value} /{personName.Last.Value}/{jrOrSr}");
if (!string.IsNullOrEmpty(personName.First.Value))
pGedLines.Add($"2 GIVN {personName.First.Value}");
lines.Add($"2 GIVN {personName.First.Value}");
if (!string.IsNullOrEmpty(personName.Last.Value))
pGedLines.Add($"2 SURN {personName.Last.Value}");
lines.Add($"2 SURN {personName.Last.Value}");
if (!string.IsNullOrEmpty(jrOrSr))
pGedLines.Add($"2 NSFX {jrOrSr.Trim()}");
pGedLines.Add($"2 NICK {personKeyFormatted}");
pGedLines.Add($"1 SEX {genealogicalDataCommunication.Sex}");
lines.Add($"2 NSFX {jrOrSr.Trim()}");
lines.Add($"2 NICK {personKeyFormatted}");
lines.Add($"1 SEX {genealogicalDataCommunication.Sex}");
if (genealogicalDataCommunication.Birth is not null)
{
Models.PersonBirthday personBirthday = new(genealogicalDataCommunication.Birth.Value);
if (!IPersonBirthday.IsCounterPersonBirthday(personBirthday))
{
pGedLines.Add("1 BIRT");
pGedLines.Add($"2 DATE {genealogicalDataCommunication.Birth.Value:dd MMM yyyy}");
lines.Add("1 BIRT");
lines.Add($"2 DATE {genealogicalDataCommunication.Birth.Value:dd MMM yyyy}");
}
}
if (genealogicalDataCommunication.Death is not null)
{
if (genealogicalDataCommunication?.Death is null || genealogicalDataCommunication.Death == genealogicalDataCommunication.Birth || IPersonBirthday.IsCounterPersonBirthday(new(genealogicalDataCommunication.Death.Value)))
pGedLines.Add("1 DEAT Y");
lines.Add("1 DEAT Y");
else
{
pGedLines.Add("1 DEAT");
pGedLines.Add($"2 DATE {genealogicalDataCommunication.Death.Value:dd MMM yyyy}");
lines.Add("1 DEAT");
lines.Add($"2 DATE {genealogicalDataCommunication.Death.Value:dd MMM yyyy}");
}
}
if (isDefaultName)
pGedLines.Add("9 NOTE");
lines.Add("9 NOTE");
if (individualsLines is not null)
pGedLines.AddRange(GetFilteredOutMapped(individualsLines));
string text = string.Join(Environment.NewLine, pGedLines);
lines.AddRange(GetFilteredOutMapped(individualsLines));
string text = string.Join(Environment.NewLine, lines);
_ = IPath.WriteAllText(Path.Combine(directory, $"{personKeyFormatted}.pged"), text, updateDateWhenMatches: false, compareBeforeWrite: true);
}
internal static void CreateTree(string mappingDefaultName, string personBirthdayFormat, string resultAllInOne, List<Models.PersonContainer> personContainers, string[] genealogicalDataCommunicationHeaderLines, string[] genealogicalDataCommunicationFooterLines, long ticks, string a2PeopleContentDirectory, Dictionary<long, List<int>> personKeyToIds)
internal static bool CleanDisplayDirectoryAllFilesAndWriteTicksGed(string mappingDefaultName, string personBirthdayFormat, List<Models.PersonContainer> personContainers, string[] headerLines, List<string[]> familyGroupLines, string[] footerLines, long ticks, string a2PeopleContentDirectory)
{
string by;
string[] matches;
bool result = false;
string[] mdFiles;
string[] txtFiles;
const int zero = 0;
string[] jsonFiles;
string[] pGedFiles;
string[] pGedLines;
string personKeyFormatted;
List<string> lines = new();
List<long> distinct = new();
lines.AddRange(genealogicalDataCommunicationHeaderLines);
List<string> individualsLines;
Models.PersonBirthday personBirthday;
string rootDirectory = Path.Combine(a2PeopleContentDirectory, $"{ticks}-Tree");
lines.AddRange(headerLines);
foreach (Models.PersonContainer personContainer in personContainers)
{
if (personContainer.Key is null || personContainer.Birthdays is null || personContainer.Person is null || !personContainer.Birthdays.Any())
@ -356,28 +420,56 @@ internal abstract class GenealogicalDataCommunication
distinct.Add(personContainer.Key.Value);
personBirthday = personContainer.Birthdays[zero];
personKeyFormatted = IPersonBirthday.GetFormatted(personBirthdayFormat, personBirthday);
by = IPersonBirthday.IsCounterPersonBirthday(personBirthday) ? resultAllInOne : "People";
matches = (from l in personContainer.DisplayDirectoryAllFiles where !string.IsNullOrEmpty(personKeyFormatted) && l.Contains(personKeyFormatted) select l).ToArray();
if (!matches.Any())
continue;
pGedFiles = (from l in matches where l.EndsWith(".pged") select l).ToArray();
if (!pGedFiles.Any())
continue;
pGedLines = File.ReadAllLines(pGedFiles[0]);
lines.AddRange(pGedLines);
if (!personKeyToIds.ContainsKey(personContainer.Key.Value))
lines.Add("1 NOTE");
// segments = personContainer.DisplayDirectoryName.Split(_Configuration.PersonCharacters.ToArray());
// if (segments.Length < 2)
// directory = Path.Combine(rootDirectory, $"000 {personKeyFormatted} {personContainer.DisplayDirectoryName}");
// else
// directory = Path.Combine(rootDirectory, $"{segments[1].PadLeft(3, '0')} {personKeyFormatted} {personContainer.DisplayDirectoryName}");
// if (Directory.Exists(directory))
// continue;
// _ = Directory.CreateDirectory(directory);
mdFiles = (from l in personContainer.DisplayDirectoryAllFiles where l.EndsWith(".md") select l).ToArray();
txtFiles = (from l in personContainer.DisplayDirectoryAllFiles where l.EndsWith(".txt") select l).ToArray();
jsonFiles = (from l in personContainer.DisplayDirectoryAllFiles where l.EndsWith(".json") select l).ToArray();
pGedFiles = (from l in personContainer.DisplayDirectoryAllFiles where l.EndsWith(".pged") select l).ToArray();
foreach (string mdFile in mdFiles)
{
if (string.IsNullOrEmpty(personKeyFormatted))
continue;
if (!mdFile.Contains(personKeyFormatted))
{
if (!result)
result = true;
File.Delete(mdFile);
}
}
foreach (string pGedFile in pGedFiles)
{
if (string.IsNullOrEmpty(personKeyFormatted))
continue;
if (!pGedFile.Contains(personKeyFormatted))
{
if (!result)
result = true;
File.Delete(pGedFile);
continue;
}
individualsLines = File.ReadAllLines(pGedFile).ToList();
foreach (string jsonFile in jsonFiles)
{
if (!result)
result = true;
File.Delete(jsonFile);
}
foreach (string txtFile in txtFiles)
{
if (new FileInfo(txtFile).Length == 0)
{
if (!result)
result = true;
File.Delete(txtFile);
}
}
lines.AddRange(individualsLines);
}
}
lines.AddRange(genealogicalDataCommunicationFooterLines);
for (int i = 0; i < familyGroupLines.Count; i++)
lines.AddRange(familyGroupLines[i]);
lines.AddRange(footerLines);
File.WriteAllLines(Path.Combine(a2PeopleContentDirectory, $"{ticks}.ged"), lines);
return result;
}
}

View File

@ -1,3 +1,5 @@
using System.Collections.ObjectModel;
namespace View_by_Distance.Shared.Models.Stateless.Methods;
public interface IGenealogicalDataCommunication
@ -5,9 +7,9 @@ public interface IGenealogicalDataCommunication
// ...
void TestStatic_WriteFile(string personKeyFormatted, Models.PersonName personName, List<string>? individualsLines, bool isDefaultName, string directory, Models.GenealogicalDataCommunication genealogicalDataCommunication, bool verify, bool first) =>
void TestStatic_WriteFile(string personKeyFormatted, Models.PersonName personName, string[]? individualsLines, bool isDefaultName, string directory, Models.GenealogicalDataCommunication genealogicalDataCommunication, bool verify, bool first) =>
WriteFile(personKeyFormatted, personName, individualsLines, isDefaultName, directory, genealogicalDataCommunication, verify, first);
static void WriteFile(string personKeyFormatted, Models.PersonName personName, List<string>? individualsLines, bool isDefaultName, string directory, Models.GenealogicalDataCommunication genealogicalDataCommunication, bool verify, bool first) =>
static void WriteFile(string personKeyFormatted, Models.PersonName personName, string[]? individualsLines, bool isDefaultName, string directory, Models.GenealogicalDataCommunication genealogicalDataCommunication, bool verify, bool first) =>
GenealogicalDataCommunication.WriteFile(personKeyFormatted, personName, individualsLines, isDefaultName, directory, genealogicalDataCommunication, verify, first);
List<string> TestStatic_GetMappedLines(string genealogicalDataCommunicationFile, bool requireNickName) =>
@ -15,9 +17,9 @@ public interface IGenealogicalDataCommunication
static List<string> GetMappedLines(string genealogicalDataCommunicationFile, bool requireNickName) =>
GenealogicalDataCommunication.GetMappedLines(genealogicalDataCommunicationFile, requireNickName);
GenealogicalDataCommunicationLines TestStatic_GetGenealogicalDataCommunicationLines(Models.PersonBirthday personBirthday, List<string> individualsLines) =>
GenealogicalDataCommunicationLines TestStatic_GetGenealogicalDataCommunicationLines(Models.PersonBirthday personBirthday, string[] individualsLines) =>
GetGenealogicalDataCommunicationLines(individualsLines);
static GenealogicalDataCommunicationLines GetGenealogicalDataCommunicationLines(List<string> individualsLines) =>
static GenealogicalDataCommunicationLines GetGenealogicalDataCommunicationLines(string[] individualsLines) =>
GenealogicalDataCommunication.GetGenealogicalDataCommunicationLines(new(DateTime.Now), individualsLines);
Models.GenealogicalDataCommunication TestStatic_GetGenealogicalDataCommunication(GenealogicalDataCommunicationLines genealogicalDataCommunicationLines) =>
@ -25,14 +27,14 @@ public interface IGenealogicalDataCommunication
static Models.GenealogicalDataCommunication GetGenealogicalDataCommunication(GenealogicalDataCommunicationLines genealogicalDataCommunicationLines) =>
GenealogicalDataCommunication.GetGenealogicalDataCommunication(genealogicalDataCommunicationLines);
(string[] headerLines, Dictionary<string, List<string>> individuals, string[] footerLines) TestStatic_GetIndividuals(string genealogicalDataCommunicationFile, bool requireNickName) =>
(string[], ReadOnlyDictionary<string, string[]>, List<string[]>, string[], List<GenealogicalDataCommunicationRelation> genealogicalDataCommunicationRelations) TestStatic_GetIndividuals(string genealogicalDataCommunicationFile, bool requireNickName) =>
GetIndividuals(genealogicalDataCommunicationFile, requireNickName);
static (string[] headerLines, Dictionary<string, List<string>> individuals, string[] footerLines) GetIndividuals(string genealogicalDataCommunicationFile, bool requireNickName) =>
static (string[], ReadOnlyDictionary<string, string[]>, List<string[]>, string[], List<GenealogicalDataCommunicationRelation> genealogicalDataCommunicationRelations) GetIndividuals(string genealogicalDataCommunicationFile, bool requireNickName) =>
GenealogicalDataCommunication.GetIndividuals(genealogicalDataCommunicationFile, requireNickName);
void TestStatic_CreateTree(string mappingDefaultName, string personBirthdayFormat, string resultAllInOne, List<Models.PersonContainer> personContainers, string[] genealogicalDataCommunicationHeaderLines, string[] genealogicalDataCommunicationFooterLines, long ticks, string a2PeopleContentDirectory, Dictionary<long, List<int>> personKeyToIds) =>
CreateTree(mappingDefaultName, personBirthdayFormat, resultAllInOne, personContainers, genealogicalDataCommunicationHeaderLines, genealogicalDataCommunicationFooterLines, ticks, a2PeopleContentDirectory, personKeyToIds);
static void CreateTree(string mappingDefaultName, string personBirthdayFormat, string resultAllInOne, List<Models.PersonContainer> personContainers, string[] genealogicalDataCommunicationHeaderLines, string[] genealogicalDataCommunicationFooterLines, long ticks, string a2PeopleContentDirectory, Dictionary<long, List<int>> personKeyToIds) =>
GenealogicalDataCommunication.CreateTree(mappingDefaultName, personBirthdayFormat, resultAllInOne, personContainers, genealogicalDataCommunicationHeaderLines, genealogicalDataCommunicationFooterLines, ticks, a2PeopleContentDirectory, personKeyToIds);
bool TestStatic_CleanDisplayDirectoryAllFilesAndWriteTicksGed(string mappingDefaultName, string personBirthdayFormat, List<Models.PersonContainer> personContainers, string[] headerLines, List<string[]> familyGroupLines, string[] footerLines, long ticks, string a2PeopleContentDirectory) =>
CleanDisplayDirectoryAllFilesAndWriteTicksGed(mappingDefaultName, personBirthdayFormat, personContainers, headerLines, familyGroupLines, footerLines, ticks, a2PeopleContentDirectory);
static bool CleanDisplayDirectoryAllFilesAndWriteTicksGed(string mappingDefaultName, string personBirthdayFormat, List<Models.PersonContainer> personContainers, string[] headerLines, List<string[]> familyGroupLines, string[] footerLines, long ticks, string a2PeopleContentDirectory) =>
GenealogicalDataCommunication.CleanDisplayDirectoryAllFilesAndWriteTicksGed(mappingDefaultName, personBirthdayFormat, personContainers, headerLines, familyGroupLines, footerLines, ticks, a2PeopleContentDirectory);
}

View File

@ -1,3 +1,5 @@
using System.Collections.ObjectModel;
namespace View_by_Distance.Shared.Models.Stateless.Methods;
public interface IPersonContainer
@ -15,11 +17,16 @@ public interface IPersonContainer
static List<Models.PersonContainer> GetNonSpecificPeopleCollection(string mappingDefaultName, int personBirthdayFirstYear, char[] personCharacters, List<Models.PersonContainer> personContainers, long ticks) =>
PersonContainer.GetNonSpecificPeopleCollection(mappingDefaultName, personBirthdayFirstYear, personCharacters, personContainers, ticks);
List<Models.PersonContainer> TestStatic_GetPersonContainers(Properties.IStorage storage, string mappingDefaultName, string personBirthdayFormat, char[] personCharacters, string facesFileNameExtension, Dictionary<string, List<string>> individuals) =>
List<Models.PersonContainer> TestStatic_GetPersonContainers(Properties.IStorage storage, string mappingDefaultName, string personBirthdayFormat, char[] personCharacters, string facesFileNameExtension, ReadOnlyDictionary<string, string[]> individuals) =>
GetPersonContainers(storage, mappingDefaultName, personBirthdayFormat, personCharacters, facesFileNameExtension, individuals);
static List<Models.PersonContainer> GetPersonContainers(Properties.IStorage storage, string mappingDefaultName, string personBirthdayFormat, char[] personCharacters, string facesFileNameExtension, Dictionary<string, List<string>> individuals) =>
static List<Models.PersonContainer> GetPersonContainers(Properties.IStorage storage, string mappingDefaultName, string personBirthdayFormat, char[] personCharacters, string facesFileNameExtension, ReadOnlyDictionary<string, string[]> individuals) =>
PersonContainer.GetPersonContainers(storage, mappingDefaultName, personBirthdayFormat, personCharacters, facesFileNameExtension, individuals);
void TestStatic_MaybeWriteFiles(string mappingDefaultName, string personBirthdayFormat, List<GenealogicalDataCommunicationRelation> genealogicalDataCommunicationRelations, List<Models.PersonContainer> personContainers) =>
MaybeWriteFiles(mappingDefaultName, personBirthdayFormat, genealogicalDataCommunicationRelations, personContainers);
static void MaybeWriteFiles(string mappingDefaultName, string personBirthdayFormat, List<GenealogicalDataCommunicationRelation> genealogicalDataCommunicationRelations, List<Models.PersonContainer> personContainers) =>
PersonContainer.MaybeWriteFiles(mappingDefaultName, personBirthdayFormat, genealogicalDataCommunicationRelations, personContainers);
List<(long?, string)> TestStatic_GetDisplay(string personBirthdayFormat, Models.PersonContainer personContainer) =>
GetDisplay(personBirthdayFormat, personContainer);
static List<(long?, string)> GetDisplay(string personBirthdayFormat, Models.PersonContainer personContainer) =>

View File

@ -0,0 +1,132 @@
using System.Collections.ObjectModel;
using System.Text.RegularExpressions;
namespace View_by_Distance.Shared.Models.Stateless.Methods;
internal abstract class MarkDown
{
// ...
internal static void WriteFile(string personKeyFormatted, Models.PersonName personName, List<GenealogicalDataCommunicationRelation> genealogicalDataCommunicationRelations, ReadOnlyDictionary<string, string> personKeyFormattedToPersonFullName, ReadOnlyDictionary<int, List<GenealogicalDataCommunicationRelation>> familyIndexToCollection, bool isDefaultName, string directory, Models.GenealogicalDataCommunication genealogicalDataCommunication, bool first, string fullName, string lowerHyphenFullName)
{
string? personFullName;
bool hasRelation = false;
string lowerHyphenRelation;
List<GenealogicalDataCommunicationRelation>? relations;
string now = DateTime.Now.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.fffZ");
string jrOrSr;
if (string.IsNullOrEmpty(personName.Alias.Value))
jrOrSr = string.Empty;
else
{
if (personName.Alias.Value.Contains(" Jr"))
jrOrSr = " Jr";
else if (personName.Alias.Value.Contains(" Sr"))
jrOrSr = " Sr";
else
jrOrSr = string.Empty;
}
string code = IPersonBirthday.GetHour(genealogicalDataCommunication.Death is null, genealogicalDataCommunication.Sex).ToString("00");
if (directory.EndsWith("00"))
directory = string.Concat(directory[..^2], code);
else if (directory.EndsWith("01"))
directory = string.Concat(directory[..^2], code);
if (!Directory.Exists(directory))
_ = Directory.CreateDirectory(directory);
if (first && !personKeyFormatted.EndsWith(code))
personKeyFormatted = $"{personKeyFormatted[..^2]}{code}";
List<string> lines = new()
{
"---",
"type: person",
$"created: {now}",
$"updated: {now}",
$"{nameof(fullName)}: {fullName}",
$"name: {personName.First.Value} /{personName.Last.Value}/{jrOrSr}",
};
if (!string.IsNullOrEmpty(personName.First.Value))
lines.Add($"given: {personName.First.Value}");
if (!string.IsNullOrEmpty(personName.Last.Value))
lines.Add($"surname: {personName.Last.Value}");
if (!string.IsNullOrEmpty(jrOrSr))
lines.Add($"suffix: {jrOrSr.Trim()}");
lines.Add($"sex: {genealogicalDataCommunication.Sex}");
if (genealogicalDataCommunication.Birth is not null)
{
Models.PersonBirthday personBirthday = new(genealogicalDataCommunication.Birth.Value);
if (!IPersonBirthday.IsCounterPersonBirthday(personBirthday))
lines.Add($"birthDate: {genealogicalDataCommunication.Birth.Value:dd MMM yyyy}");
}
if (genealogicalDataCommunication.Death is not null)
{
if (genealogicalDataCommunication?.Death is null || genealogicalDataCommunication.Death == genealogicalDataCommunication.Birth || IPersonBirthday.IsCounterPersonBirthday(new(genealogicalDataCommunication.Death.Value)))
lines.Add("isDead: true");
else
lines.Add($"deathDate: {genealogicalDataCommunication.Death.Value:dd MMM yyyy}");
}
if (isDefaultName)
lines.Add($"{nameof(isDefaultName)}: {isDefaultName}");
lines.Add($"{nameof(personKeyFormatted)}: {personKeyFormatted}");
lines.Add("---");
lines.Add(string.Empty);
lines.Add($"# {lowerHyphenFullName}");
lines.Add(string.Empty);
const char father = 'F';
const char mother = 'M';
const string wife = "WIFE";
const string child = "CHIL";
const string husband = "HUSB";
foreach (GenealogicalDataCommunicationRelation genealogicalDataCommunicationRelation in genealogicalDataCommunicationRelations)
{
if (genealogicalDataCommunicationRelation.Relation != child)
continue;
if (genealogicalDataCommunicationRelation.NickName != personKeyFormatted)
continue;
if (!familyIndexToCollection.TryGetValue(genealogicalDataCommunicationRelation.FamilyIndex, out relations))
continue;
foreach (GenealogicalDataCommunicationRelation relation in relations)
{
if (relation.FamilyIndex != genealogicalDataCommunicationRelation.FamilyIndex)
continue;
if (relation.Relation is husband or wife)
{
if (!hasRelation)
{
lines.Add("## Relations");
lines.Add(string.Empty);
hasRelation = true;
}
if (!personKeyFormattedToPersonFullName.TryGetValue(relation.NickName, out personFullName))
lowerHyphenRelation = relation.NickName;
else
lowerHyphenRelation = Regex.Replace(personFullName.ToLower(), "[^a-z0-9-]", "-");
if (string.IsNullOrEmpty(genealogicalDataCommunicationRelation.LineTwo))
lines.Add($"- [[{lowerHyphenRelation}]]");
else
{
if (genealogicalDataCommunicationRelation.LineTwo[1] == father)
{
if (relation.Relation == wife)
lines.Add($"- [[{lowerHyphenRelation}]] {nameof(mother)}");
else if (relation.Relation == husband)
lines.Add($"- [[{lowerHyphenRelation}]] {genealogicalDataCommunicationRelation.LineTwo.Split(' ').Last()} {nameof(father)}");
}
else if (genealogicalDataCommunicationRelation.LineTwo[1] == mother)
{
if (relation.Relation == husband)
lines.Add($"- [[{lowerHyphenRelation}]] {nameof(father)}");
else if (relation.Relation == wife)
lines.Add($"- [[{lowerHyphenRelation}]] {genealogicalDataCommunicationRelation.LineTwo.Split(' ').Last()} {nameof(mother)}");
}
}
}
}
}
if (hasRelation)
lines.Add(string.Empty);
string text = string.Join(Environment.NewLine, lines);
_ = IPath.WriteAllText(Path.Combine(directory, $"{lowerHyphenFullName}.md"), text, updateDateWhenMatches: false, compareBeforeWrite: true);
}
}

View File

@ -1,3 +1,6 @@
using System.Collections.ObjectModel;
using System.Text.RegularExpressions;
namespace View_by_Distance.Shared.Models.Stateless.Methods;
internal abstract class PersonContainer
@ -90,17 +93,19 @@ internal abstract class PersonContainer
return results;
}
private static List<Models.PersonContainer> GetPersonContainersCollections(string mappingDefaultName, string facesFileNameExtension, char[] personCharacters, PersonDirectory personDirectory, char numberSign, string personDisplayDirectory, string personDisplayDirectoryName, bool isDefaultName, int? approximateYears, List<(string PersonKeyFormatted, Models.PersonBirthday PersonBirthday)> collection)
private static List<Models.PersonContainer> GetPersonContainersCollections(string mappingDefaultName, string facesFileNameExtension, char[] personCharacters, ReadOnlyDictionary<string, string[]> individuals, PersonDirectory personDirectory, char numberSign, string personDisplayDirectory, string personDisplayDirectoryName, bool isDefaultName, int? approximateYears, List<(string PersonKeyFormatted, Models.PersonBirthday PersonBirthday)> collection)
{
List<Models.PersonContainer> 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;
@ -111,7 +116,7 @@ internal abstract class PersonContainer
personKey = orderedPersonBirthdays[zero].Value.Ticks;
}
person = IPerson.GetPerson(mappingDefaultName, personCharacters, personDisplayDirectoryName, personDisplayDirectoryAllFiles, personKey);
personContainer = new(approximateYears, orderedPersonBirthdays, personDisplayDirectoryAllFiles, personDisplayDirectoryName, personKey, person, personDirectory);
personContainer = new(approximateYears, orderedPersonBirthdays, personDisplayDirectoryAllFiles, personDisplayDirectoryName, individualsLines, personKey, person, personDirectory);
results.Add(personContainer);
}
return results;
@ -148,48 +153,7 @@ internal abstract class PersonContainer
return result;
}
private static void MaybeGenealogicalDataCommunicationWriteFile(string mappingDefaultName, string personBirthdayFormat, Dictionary<string, List<string>> individuals, PersonDirectory personDirectory, string personDisplayDirectoryName, bool isDefaultName, List<Models.PersonContainer> personContainers)
{
bool? first;
bool? male;
string[] matches;
string? directory;
bool verify = true;
const int zero = 0;
string personKeyFormatted;
List<string>? individualsLines = null;
Models.GenealogicalDataCommunication genealogicalDataCommunication;
GenealogicalDataCommunicationLines? genealogicalDataCommunicationLines;
foreach (Models.PersonContainer personContainer in personContainers)
{
if (personContainer.Key is null || personContainer.Birthdays is null || personContainer.Person is null || !personContainer.Birthdays.Any())
continue;
male = personDirectory.Sex == 'U' ? null : personDirectory.Sex == 'M' || (personDirectory.Sex == 'F' ? false : throw new Exception());
first = personDirectory.First == 'U' ? null : personDirectory.First == 'Y' || (personDirectory.First == 'N' ? false : throw new Exception());
if (first is null)
continue;
isDefaultName = IPerson.IsDefaultName(mappingDefaultName, personDisplayDirectoryName);
personKeyFormatted = IPersonBirthday.GetFormatted(personBirthdayFormat, personContainer.Key.Value);
_ = individuals.TryGetValue(personKeyFormatted, out individualsLines);
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 = individualsLines is null ? null : GenealogicalDataCommunication.GetGenealogicalDataCommunicationLines(personContainer.Birthdays[0], individualsLines);
if (genealogicalDataCommunicationLines is null)
continue;
genealogicalDataCommunication = GenealogicalDataCommunication.GetGenealogicalDataCommunication(genealogicalDataCommunicationLines);
if (genealogicalDataCommunication.Sex != personDirectory.Sex)
continue;
if (genealogicalDataCommunication.Death is null && personDirectory.Status == 'D' || genealogicalDataCommunication.Death is not null && personDirectory.Status == 'A')
continue;
GenealogicalDataCommunication.WriteFile(personKeyFormatted, personContainer.Person.Name, individualsLines, isDefaultName, directory, genealogicalDataCommunication, verify, first.Value);
}
}
private static (List<string?>, List<Models.PersonContainer>) GetPersonContainersGroup(string mappingDefaultName, string personBirthdayFormat, string facesFileNameExtension, char[] personCharacters, Dictionary<string, List<string>> individuals, PersonDirectory personDirectory, string[] personDisplayDirectories)
private static (List<string?>, List<Models.PersonContainer>) GetPersonContainersGroup(string mappingDefaultName, string personBirthdayFormat, string facesFileNameExtension, char[] personCharacters, ReadOnlyDictionary<string, string[]> individuals, PersonDirectory personDirectory, string[] personDisplayDirectories)
{
List<Models.PersonContainer> results = new();
string? minusOne;
@ -223,8 +187,7 @@ internal abstract class PersonContainer
continue;
if (collection.Any())
{
personContainers = GetPersonContainersCollections(mappingDefaultName, facesFileNameExtension, personCharacters, personDirectory, numberSign, personDisplayDirectory, personDisplayDirectoryName, isDefaultName, approximateYears, collection);
MaybeGenealogicalDataCommunicationWriteFile(mappingDefaultName, personBirthdayFormat, individuals, personDirectory, personDisplayDirectoryName, isDefaultName, personContainers);
personContainers = GetPersonContainersCollections(mappingDefaultName, facesFileNameExtension, personCharacters, individuals, personDirectory, numberSign, personDisplayDirectory, personDisplayDirectoryName, isDefaultName, approximateYears, collection);
results.AddRange(personContainers);
}
else
@ -237,7 +200,7 @@ internal abstract class PersonContainer
return new(changes, results);
}
private static (List<string?>, List<Models.PersonContainer>) GetPersonContainersInnerGroups(string mappingDefaultName, string personBirthdayFormat, string facesFileNameExtension, char[] personCharacters, Dictionary<string, List<string>> individuals, string groupDirectory, string groupDirectoryName)
private static (List<string?>, List<Models.PersonContainer>) GetPersonContainersInnerGroups(string mappingDefaultName, string personBirthdayFormat, string facesFileNameExtension, char[] personCharacters, ReadOnlyDictionary<string, string[]> individuals, string groupDirectory, string groupDirectoryName)
{
List<Models.PersonContainer> results = new();
string[] segments;
@ -284,7 +247,7 @@ internal abstract class PersonContainer
return new(allChanges, results);
}
private static List<Models.PersonContainer> GetPersonContainersGroups(string mappingDefaultName, string personBirthdayFormat, string facesFileNameExtension, char[] personCharacters, Dictionary<string, List<string>> individuals, string[] groupDirectories)
private static List<Models.PersonContainer> GetPersonContainersGroups(string mappingDefaultName, string personBirthdayFormat, string facesFileNameExtension, char[] personCharacters, ReadOnlyDictionary<string, string[]> individuals, string[] groupDirectories)
{
List<Models.PersonContainer> results;
const int zero = 0;
@ -308,7 +271,7 @@ internal abstract class PersonContainer
return results;
}
internal static List<Models.PersonContainer> GetPersonContainers(Properties.IStorage storage, string mappingDefaultName, string personBirthdayFormat, char[] personCharacters, string facesFileNameExtension, Dictionary<string, List<string>> individuals)
internal static List<Models.PersonContainer> GetPersonContainers(Properties.IStorage storage, string mappingDefaultName, string personBirthdayFormat, char[] personCharacters, string facesFileNameExtension, ReadOnlyDictionary<string, string[]> individuals)
{
List<Models.PersonContainer> results;
string a2PeopleSingletonDirectory = Path.Combine(storage.PeopleRootDirectory, "{}");
@ -391,4 +354,92 @@ internal abstract class PersonContainer
return results;
}
private static ReadOnlyDictionary<string, string> GetPersonKeyFormattedToPersonFullName(string personBirthdayFormat, List<Models.PersonContainer> personContainers)
{
Dictionary<string, string> 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<int, List<GenealogicalDataCommunicationRelation>> GetFamilyIndexToCollection(List<GenealogicalDataCommunicationRelation> genealogicalDataCommunicationRelations)
{
Dictionary<int, List<GenealogicalDataCommunicationRelation>> results = new();
List<GenealogicalDataCommunicationRelation>? 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, List<GenealogicalDataCommunicationRelation> genealogicalDataCommunicationRelations, List<Models.PersonContainer> personContainers)
{
bool? male;
bool? first;
string fullName;
string[] matches;
string? directory;
bool isDefaultName;
bool verify = true;
const int zero = 0;
string personKeyFormatted;
string lowerHyphenFullName;
List<string> distinct = new();
Models.GenealogicalDataCommunication genealogicalDataCommunication;
GenealogicalDataCommunicationLines? genealogicalDataCommunicationLines;
ReadOnlyDictionary<string, string> personKeyFormattedToPersonFullName = GetPersonKeyFormattedToPersonFullName(personBirthdayFormat, personContainers);
ReadOnlyDictionary<int, List<GenealogicalDataCommunicationRelation>> 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);
fullName = PersonName.GetFullName(personContainer.Person.Name);
lowerHyphenFullName = $"{Regex.Replace(fullName.ToLower(), "[^a-z0-9-]", "-")}";
if (distinct.Contains(lowerHyphenFullName))
continue;
MarkDown.WriteFile(personKeyFormatted, personContainer.Person.Name, genealogicalDataCommunicationRelations, personKeyFormattedToPersonFullName, familyIndexToCollection, isDefaultName, directory, genealogicalDataCommunication, first.Value, fullName, lowerHyphenFullName);
distinct.Add(lowerHyphenFullName);
}
}
}

View File

@ -62,12 +62,19 @@ internal abstract class PersonName
internal static string GetFullName(Models.PersonName personName)
{
StringBuilder result = new();
if (personName.First is not null)
if (personName.First is not null && !string.IsNullOrEmpty(personName.First.Value))
_ = result.Append(personName.First.Value);
if (personName.Middle is not null)
if (personName.Middle is not null && !string.IsNullOrEmpty(personName.Middle.Value))
_ = result.Append(' ').Append(personName.Middle.Value);
if (personName.Last is not null)
if (personName.Last is not null && !string.IsNullOrEmpty(personName.Last.Value))
_ = result.Append(' ').Append(personName.Last.Value);
if (personName.Alias is not null && !string.IsNullOrEmpty(personName.Alias.Value))
{
if (personName.Alias.Value.Contains(" Jr"))
_ = result.Append(" Jr");
else if (personName.Alias.Value.Contains(" Sr"))
_ = result.Append(" Sr");
}
return result.ToString();
}