Family Tree as Markdown Files
This commit is contained in:
@ -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;
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user