file-folder-helper/Helpers/HelperGenealogicalDataCommunication.cs
2023-08-06 23:00:38 -07:00

800 lines
36 KiB
C#

using File_Folder_Helper.Models;
using Microsoft.Extensions.Logging;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Text.Json;
using System.Text.RegularExpressions;
namespace File_Folder_Helper.Helpers;
internal static partial class HelperGenealogicalDataCommunication
{
private record Input(string GenealogicalDataCommunicationDirectory,
string? GenealogicalDataCommunicationFile,
string? SingletonDirectory,
string? Destination);
private record GenealogicalDataCommunicationCollections(ReadOnlyCollection<string> HeaderLines,
ReadOnlyDictionary<long, ReadOnlyCollection<string>> IndividualsToLines,
ReadOnlyCollection<ReadOnlyCollection<string>> FamilyGroupLines,
ReadOnlyCollection<string> FooterLines);
private record GenealogicalDataCommunicationRelation(int FamilyIndex,
string Relation,
int Id,
string? LineTwo);
private record PersonHour(char Status,
char Sex,
char First);
[GeneratedRegex("[\\\\,\\/,\\:,\\*,\\?,\\\",\\<,\\>,\\|]")]
private static partial Regex WindowsFileSystem();
private static Input GetInput(List<string> args)
{
Input result;
string? destination = null;
string? singletonDirectory = null;
string genealogicalDataCommunicationRootDirectory = Path.GetFullPath(args[0]);
string fileName = Path.GetFileName(genealogicalDataCommunicationRootDirectory);
string[] files = Directory.GetFiles(genealogicalDataCommunicationRootDirectory, $"{fileName}.ged", SearchOption.TopDirectoryOnly);
string genealogicalDataCommunicationDirectory = Path.Combine(genealogicalDataCommunicationRootDirectory, fileName);
if (!Directory.Exists(genealogicalDataCommunicationDirectory))
_ = Directory.CreateDirectory(genealogicalDataCommunicationDirectory);
for (int i = 1; i < args.Count; i++)
{
if (args[i].Length == 2 && i + 1 < args.Count)
{
if (args[i][1] == 's')
singletonDirectory = Path.GetFullPath(args[i + 1]);
else if (args[i][1] == 'd')
destination = Path.GetFullPath(args[i + 1]);
i++;
}
}
string? genealogicalDataCommunicationFile = files.Length != 1 ? null : files[0];
if (destination is not null)
{
string? root = Path.GetPathRoot(destination);
if (root is null || !Directory.Exists(root))
throw new NotSupportedException($"This method requires frontMatterYamlLines valid -d path <{root}>!");
if (!Directory.Exists(destination))
_ = Directory.CreateDirectory(destination);
}
result = new(genealogicalDataCommunicationDirectory, genealogicalDataCommunicationFile, singletonDirectory, destination);
return result;
}
private static ReadOnlyCollection<string> GetHeaderLines(string startsWith, string[] sourceLines)
{
List<string> results = new();
for (int i = 0; i < sourceLines.Length; i++)
{
if (sourceLines[i].StartsWith(startsWith))
break;
results.Add(sourceLines[i]);
}
return new(results);
}
private static ReadOnlyDictionary<long, ReadOnlyCollection<string>> Convert(Dictionary<long, List<string>> keyValuePairs)
{
Dictionary<long, ReadOnlyCollection<string>> results = new();
foreach (KeyValuePair<long, List<string>> keyValuePair in keyValuePairs)
results.Add(keyValuePair.Key, new(keyValuePair.Value));
return new(results);
}
private static long? GetId(string line)
{
long? result;
string[] segments = line.Split('@');
result = segments[1].Length < 2 || !long.TryParse(segments[1][1..], out long idValue) ? null : idValue;
return result;
}
private static GenealogicalDataCommunicationCollections GetGenealogicalDataCommunicationCollections(Input input)
{
GenealogicalDataCommunicationCollections result;
long? id;
List<string> lines = new();
const string startsWith = "0 @";
List<string> footerLines = new();
Dictionary<long, List<string>> keyValuePairs = new();
List<ReadOnlyCollection<string>> familyGroupLines = new();
string[] sourceLines = string.IsNullOrEmpty(input.GenealogicalDataCommunicationFile) || !File.Exists(input.GenealogicalDataCommunicationFile) ? Array.Empty<string>() : File.ReadAllLines(input.GenealogicalDataCommunicationFile);
ReadOnlyCollection<string> headerLines = GetHeaderLines(startsWith, sourceLines);
for (int i = headerLines.Count; i < sourceLines.Length; i++)
{
if (!sourceLines[i].StartsWith(startsWith))
continue;
if (sourceLines[i].EndsWith("@ SOUR") || sourceLines[i].EndsWith("@ SUBM") || sourceLines[i].EndsWith("@ OBJE") || sourceLines[i].EndsWith("@ REPO"))
continue;
lines.Add(sourceLines[i]);
if (sourceLines[i].EndsWith("@ FAM"))
{
lines.Clear();
for (int j = sourceLines.Length - 1; j >= i; j--)
{
lines.Add(sourceLines[j]);
if (sourceLines[j][0] == '0')
{
if (!sourceLines[j].EndsWith("@ FAM"))
footerLines.AddRange(lines);
else
{
lines.Reverse();
familyGroupLines.Add(new(lines.ToArray()));
}
lines.Clear();
}
}
familyGroupLines.Reverse();
footerLines.Reverse();
break;
}
else if (sourceLines[i].EndsWith("@ INDI"))
{
id = GetId(sourceLines[i]);
for (int j = i + 1; j < sourceLines.Length; j++)
{
if (sourceLines[j].StartsWith(startsWith))
break;
lines.Add(sourceLines[j]);
}
if (id is null)
throw new Exception(string.Join(Environment.NewLine, lines));
keyValuePairs.Add(id.Value, new());
if (lines.Count == 0)
continue;
keyValuePairs[id.Value].AddRange(lines);
lines.Clear();
}
else
throw new NotSupportedException();
}
ReadOnlyDictionary<long, ReadOnlyCollection<string>> individualsToLines = Convert(keyValuePairs);
result = new(headerLines, individualsToLines, new(familyGroupLines), new(footerLines));
return result;
}
private static PersonHour GetPersonHour(string personDisplayDirectoryName, int hour) =>
hour == 0 ? new('U', 'U', 'U') :
hour == 1 ? new('U', 'U', 'U') :
hour == 2 ? new('U', 'U', 'U') :
hour == 3 ? new('A', 'U', 'Y') :
hour == 4 ? new('A', 'F', 'Y') :
hour == 5 ? new('A', 'M', 'Y') :
hour == 6 ? new('A', 'F', 'N') :
hour == 7 ? new('A', 'M', 'N') :
hour == 13 ? new('D', 'U', 'Y') :
hour == 14 ? new('D', 'F', 'Y') :
hour == 15 ? new('D', 'M', 'Y') :
hour == 16 ? new('D', 'F', 'N') :
hour == 17 ? new('D', 'M', 'N') :
throw new NotImplementedException(personDisplayDirectoryName);
private static string GetHourGroup(string personDisplayDirectoryName, int hour) =>
hour == 0 ? "Unknown-Unknown-Unknown" :
hour == 1 ? "Unknown-Unknown-Unknown" :
hour == 2 ? "Unknown-Unknown-Unknown" :
hour == 3 ? "Alive-Unknown-Yes" :
hour == 4 ? "Alive-Female-Yes" :
hour == 5 ? "Alive-Male-Yes" :
hour == 6 ? "Alive-Female-No" :
hour == 7 ? "Alive-Male-No" :
hour == 13 ? "Dead-Unknown-Yes" :
hour == 14 ? "Dead-Female-Yes" :
hour == 15 ? "Dead-Male-Yes" :
hour == 16 ? "Dead-Female-No" :
hour == 17 ? "Dead-Male-No" :
throw new NotImplementedException(personDisplayDirectoryName);
private static (int, Name) GetName(ReadOnlyCollection<string> lines, int i)
{
Name result;
string seven;
string? surName = null;
string? nickName = null;
string? givenName = null;
string? suffixName = null;
string? forwardSlashFullName = lines[i][..7] == "1 NAME " ? lines[i][7..] : null;
for (int j = i + 1; j < lines.Count; j++)
{
if (lines[j][0] == '1')
break;
i++;
if (lines[j].Length < 7)
throw new NotImplementedException();
seven = lines[j][..7];
if (seven == "2 GIVN ")
givenName = lines[j][7..];
else if (seven == "2 SURN ")
surName = lines[j][7..];
else if (seven == "2 NICK ")
nickName = lines[j][7..];
else if (seven == "2 NSFX ")
suffixName = lines[j][7..];
else
throw new NotImplementedException();
}
result = new(forwardSlashFullName, givenName, surName, nickName, suffixName);
return (i, result);
}
private static (int, Birth, bool) GetBirth(Dictionary<string, List<string>> keyValuePairs, ReadOnlyCollection<string> lines, int i)
{
Birth result;
string seven;
string? note = null;
bool moreAdded = false;
List<string>? collection;
DateOnly? dateOnly = null;
List<string> distinct = new();
List<string> @continue = new();
for (int j = i + 1; j < lines.Count; j++)
{
if (lines[j][0] == '1')
break;
i++;
if (lines[j].Length < 7)
throw new NotImplementedException();
seven = lines[j][..7];
if (seven == "2 DATE ")
dateOnly = !DateOnly.TryParseExact(lines[j][7..], "d MMM yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out DateOnly dateOnlyValue) ? null : dateOnlyValue;
else if (seven == "2 NOTE ")
note = lines[j][7..];
else if (seven == "3 CONT ")
{
for (int k = j; k < lines.Count; k++)
{
seven = lines[k][..7];
if (seven != "3 CONT ")
break;
j++;
@continue.Add(lines[k][7..]);
}
if (note is not null && keyValuePairs.TryGetValue(note, out collection))
{
distinct.Add(note);
distinct.AddRange(@continue);
foreach (string text in collection)
{
if (distinct.Contains(text))
continue;
distinct.Add(text);
if (!moreAdded)
moreAdded = true;
@continue.Add(text);
}
}
}
else
continue;
}
result = new(dateOnly, note, @continue);
return (i, result, moreAdded);
}
private static (int, Death) GetDeath(ReadOnlyCollection<string> lines, int i)
{
Death result;
string seven;
string? note = null;
DateOnly? dateOnly = null;
List<string> @continue = new();
bool? isDead = lines[i].Length == 8 && lines[i][..8] == "1 DEAT Y" ? true : lines[i].Length == 8 && lines[i][..8] == "1 DEAT N" ? false : null;
for (int j = i + 1; j < lines.Count; j++)
{
if (lines[j][0] == '1')
break;
i++;
if (lines[j].Length < 7)
throw new NotImplementedException();
seven = lines[j][..7];
if (seven == "2 DATE ")
dateOnly = !DateOnly.TryParseExact(lines[j][7..], "d MMM yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out DateOnly dateOnlyValue) ? null : dateOnlyValue;
else if (seven == "2 NOTE ")
note = lines[j][7..];
else if (seven == "3 CONT ")
{
for (int k = j; k < lines.Count; k++)
{
seven = lines[k][..7];
if (seven != "3 CONT ")
break;
j++;
@continue.Add(lines[k][7..]);
}
}
else
throw new NotImplementedException();
}
result = new(dateOnly is not null ? true : isDead, dateOnly, note, @continue);
return (i, result);
}
private static (int, Change) GetChange(ReadOnlyCollection<string> lines, int i)
{
Change result;
string seven;
string? note = null;
DateOnly? dateOnly = null;
List<string> @continue = new();
for (int j = i + 1; j < lines.Count; j++)
{
if (lines[j][0] == '1')
break;
i++;
if (lines[j].Length < 7)
throw new NotImplementedException();
seven = lines[j][..7];
if (seven == "2 DATE ")
dateOnly = !DateOnly.TryParseExact(lines[j][7..], "d MMM yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out DateOnly dateOnlyValue) ? null : dateOnlyValue;
else if (seven == "2 NOTE ")
note = lines[j][7..];
else if (seven == "3 CONT ")
{
for (int k = j; k < lines.Count; k++)
{
seven = lines[k][..7];
if (seven != "3 CONT ")
break;
j++;
@continue.Add(lines[k][7..]);
}
}
else
throw new NotImplementedException();
}
result = new(dateOnly, note, @continue);
return (i, result);
}
private static Dictionary<string, List<string>> GetTxtFileCollection(Input input)
{
Dictionary<string, List<string>> results = new();
string[] lines;
string[] directories;
string directoryName;
string? sourceDirectory;
string? parentDirectory;
List<string>? collectionA;
List<string>? collectionB;
string siblingDirectoryName;
string[] files = input.SingletonDirectory is null || !Directory.Exists(input.SingletonDirectory) ? Array.Empty<string>() : Directory.GetFiles(input.SingletonDirectory, "*.txt", SearchOption.AllDirectories);
foreach (string file in files)
{
sourceDirectory = Path.GetDirectoryName(file);
if (sourceDirectory is null)
continue;
parentDirectory = Path.GetDirectoryName(sourceDirectory);
if (parentDirectory is null)
continue;
lines = File.ReadAllLines(file);
if (lines.Length != 1 || lines.Length == 2 && string.IsNullOrEmpty(lines[1]))
continue;
directoryName = Path.GetFileName(sourceDirectory);
if (!results.TryGetValue(directoryName, out collectionA))
{
results.Add(directoryName, new());
if (!results.TryGetValue(directoryName, out collectionA))
throw new Exception();
}
collectionA.Add(lines[0]);
directories = Directory.GetDirectories(parentDirectory, "*", SearchOption.TopDirectoryOnly);
foreach (string directory in directories)
{
siblingDirectoryName = Path.GetFileName(directory);
collectionA.Add(siblingDirectoryName);
}
foreach (string directory in directories)
{
siblingDirectoryName = Path.GetFileName(directory);
if (!results.TryGetValue(siblingDirectoryName, out collectionB))
{
results.Add(siblingDirectoryName, new());
if (!results.TryGetValue(siblingDirectoryName, out collectionB))
throw new Exception();
}
collectionB.AddRange(collectionA);
collectionB.Add(lines[0]);
}
}
return results;
}
private static string[] GetNewLines(string[] lines, Birth? birth)
{
List<string> results = new();
string six;
string text;
string seven;
List<string> @continue = birth is null ? new() : birth.Continue.ToList();
for (int i = 0; i < lines.Length; i++)
{
if (birth is null)
throw new NotSupportedException();
if (lines[i].Length < 6)
throw new NotImplementedException();
results.Add(lines[i]);
six = lines[i][..6];
if (lines[i][0] == '1')
{
if (six != "1 BIRT")
continue;
for (int j = i + 1; j < lines.Length; j++)
{
if (lines[j].Length < 7)
throw new NotImplementedException();
if (lines[j][0] == '1')
break;
i++;
seven = lines[j][..7];
if (seven != "3 CONT ")
results.Add(lines[j]);
else
{
text = lines[j][7..];
if (@continue.Contains(text))
{
results.Add(lines[j]);
_ = @continue.Remove(text);
}
}
}
results.AddRange(from l in @continue orderby l select $"3 CONT {l}");
}
}
return results.ToArray();
}
private static Dictionary<long, Person> GetPeople(Input input, GenealogicalDataCommunicationCollections genealogicalDataCommunicationCollections)
{
Dictionary<long, Person> results = new();
string six;
Person person;
long? id = null;
char? sex = null;
Name? name = null;
string? uId = null;
Birth? birth = null;
Death? death = null;
Change? change = null;
bool? moreAdded = null;
ReadOnlyCollection<string> lines;
Dictionary<string, List<string>> keyValuePairs = GetTxtFileCollection(input);
foreach (KeyValuePair<long, ReadOnlyCollection<string>> keyValuePair in genealogicalDataCommunicationCollections.IndividualsToLines)
{
lines = keyValuePair.Value;
for (int i = 0; i < lines.Count; i++)
{
if (lines[i].Length < 6)
throw new NotImplementedException();
six = lines[i][..6];
if (lines[i][0] == '0')
{
if (lines[i][^6..] == "@ INDI")
id = GetId(lines[i]);
else
throw new NotImplementedException();
}
else if (lines[i][0] == '1')
{
if (six == "1 NAME")
(i, name) = GetName(lines, i);
else if (six == "1 SEX ")
sex = lines[i].Length != 7 ? null : lines[i][6];
else if (six is "1 UID " or "1 _UID")
uId = lines[i].Length == 6 ? null : lines[i][7..];
else if (six == "1 BIRT")
(i, birth, moreAdded) = GetBirth(keyValuePairs, lines, i);
else if (six == "1 DEAT")
(i, death) = GetDeath(lines, i);
else if (six == "1 CHAN")
(i, change) = GetChange(lines, i);
else if (six is "1 FAMC" or "1 FAMS")
continue;
else
throw new NotImplementedException();
}
}
if (id is null)
throw new Exception(string.Join(Environment.NewLine, lines));
if (moreAdded is null || !moreAdded.Value)
person = new(id.Value, name, sex, uId, birth, death, change, lines.ToArray());
else
person = new(id.Value, name, sex, uId, birth, death, change, GetNewLines(lines.ToArray(), birth));
results.Add(id.Value, person);
}
return results;
}
private static (ReadOnlyDictionary<long, long>, ReadOnlyDictionary<long, string>, ReadOnlyDictionary<long, string>, ReadOnlyCollection<(long, ReadOnlyCollection<string>, string, char[], DateTime, long)>) GetCollections(AppSettings appSettings, Dictionary<long, Person> people)
{
long personKey;
char[] ageCollection;
Dictionary<long, string> idToName = new();
Dictionary<long, long> idToPersonKey = new();
Dictionary<long, string> idToGivenName = new();
int length = appSettings.PersonBirthdayFormat.Length;
List<(long, ReadOnlyCollection<string>, string, char[], DateTime, long)> collection = new();
foreach (KeyValuePair<long, Person> keyValuePair in people)
{
if (keyValuePair.Value.Birth?.Note is null)
continue;
if (string.IsNullOrEmpty(keyValuePair.Value.Name?.ForwardSlashFull))
continue;
if (keyValuePair.Value.Birth.Note.Length != length)
continue;
if (!DateTime.TryParseExact(keyValuePair.Value.Birth.Note, appSettings.PersonBirthdayFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime dateTime))
continue;
personKey = dateTime.Ticks;
idToPersonKey.Add(keyValuePair.Key, personKey);
idToName.Add(keyValuePair.Key, WindowsFileSystem().Replace(keyValuePair.Value.Name.ForwardSlashFull, "_"));
ageCollection = keyValuePair.Value.Birth.Continue.Count == 0 ? Array.Empty<char>() : keyValuePair.Value.Birth.Continue[0].ToArray();
idToGivenName.Add(keyValuePair.Key, string.IsNullOrEmpty(keyValuePair.Value.Name.Given) ? WindowsFileSystem().Replace(keyValuePair.Value.Name.ForwardSlashFull, "_") : WindowsFileSystem().Replace(keyValuePair.Value.Name.Given, "_"));
collection.Add((keyValuePair.Key, new(keyValuePair.Value.Lines), keyValuePair.Value.Birth.Note, ageCollection, dateTime, personKey));
}
return (new(idToPersonKey), new(idToName), new(idToGivenName), new(collection));
}
private static void ExportFamilies(AppSettings appSettings, Input input, GenealogicalDataCommunicationCollections genealogicalDataCommunicationCollections, ReadOnlyDictionary<long, long> idToPersonKey, ReadOnlyDictionary<long, string> idToName, ReadOnlyDictionary<long, string> idToGivenName)
{
string? name;
long personKey;
DateTime dateTime;
string? givenName;
string familyIndex;
string? destinationRoot;
const string wife = "WIFE";
const string child = "CHIL";
string destinationDirectory;
const string husband = "HUSB";
string wifeName = string.Empty;
string? lastFamilyIndex = null;
string husbandName = string.Empty;
ReadOnlyCollection<GenealogicalDataCommunicationRelation> genealogicalDataCommunicationRelations = GetRelations(genealogicalDataCommunicationCollections.FamilyGroupLines);
foreach (GenealogicalDataCommunicationRelation genealogicalDataCommunicationRelation in genealogicalDataCommunicationRelations)
{
if (idToName.Count == 0 || idToGivenName.Count == 0)
break;
destinationRoot = Path.GetDirectoryName(input.GenealogicalDataCommunicationFile);
if (string.IsNullOrEmpty(destinationRoot))
continue;
if (!idToName.TryGetValue(genealogicalDataCommunicationRelation.Id, out name))
continue;
if (!idToGivenName.TryGetValue(genealogicalDataCommunicationRelation.Id, out givenName))
continue;
familyIndex = genealogicalDataCommunicationRelation.FamilyIndex.ToString("0000");
if (lastFamilyIndex is not null && lastFamilyIndex != familyIndex)
{
wifeName = string.Empty;
husbandName = string.Empty;
}
lastFamilyIndex = familyIndex;
if (genealogicalDataCommunicationRelation.Relation == husband)
{
husbandName = givenName;
continue;
}
if (genealogicalDataCommunicationRelation.Relation == wife)
{
wifeName = givenName;
continue;
}
if (genealogicalDataCommunicationRelation.Relation != child)
continue;
if (!idToPersonKey.TryGetValue(genealogicalDataCommunicationRelation.Id, out personKey))
continue;
dateTime = new(personKey);
destinationDirectory = Path.Combine(destinationRoot, string.Concat($"{husbandName}-{wifeName}".Trim('-'), "-", familyIndex), name, dateTime.ToString(appSettings.PersonBirthdayFormat));
if (!Directory.Exists(destinationDirectory))
_ = Directory.CreateDirectory(destinationDirectory);
File.WriteAllText(Path.Combine(destinationDirectory, ".txt"), genealogicalDataCommunicationRelation.LineTwo);
}
foreach (GenealogicalDataCommunicationRelation genealogicalDataCommunicationRelation in genealogicalDataCommunicationRelations)
{
if (idToName.Count == 0 || idToGivenName.Count == 0)
break;
destinationRoot = Path.GetDirectoryName(input.GenealogicalDataCommunicationFile);
if (string.IsNullOrEmpty(destinationRoot))
continue;
if (!idToName.TryGetValue(genealogicalDataCommunicationRelation.Id, out name))
continue;
if (!idToPersonKey.TryGetValue(genealogicalDataCommunicationRelation.Id, out personKey))
continue;
dateTime = new(personKey);
destinationDirectory = Path.Combine(destinationRoot, "A-A-0000", name, dateTime.ToString(appSettings.PersonBirthdayFormat));
if (!Directory.Exists(destinationDirectory))
_ = Directory.CreateDirectory(destinationDirectory);
File.WriteAllText(Path.Combine(destinationDirectory, ".txt"), genealogicalDataCommunicationRelation.LineTwo);
}
}
private static void WriteGenealogicalDataCommunicationCollections(ILogger<Worker> logger, Input input, GenealogicalDataCommunicationCollections genealogicalDataCommunicationCollections, Dictionary<long, Person> people)
{
List<string> lines = new();
List<string> allLines = new();
if (genealogicalDataCommunicationCollections.HeaderLines.Count > 0)
{
allLines.AddRange(genealogicalDataCommunicationCollections.HeaderLines);
File.WriteAllLines(Path.Combine(input.GenealogicalDataCommunicationDirectory, "a.pged"), genealogicalDataCommunicationCollections.HeaderLines);
}
if (people.Count > 0)
{
lines.Clear();
ReadOnlyCollection<string>? collection;
foreach (KeyValuePair<long, Person> keyValuePair in people)
{
if (!genealogicalDataCommunicationCollections.IndividualsToLines.TryGetValue(keyValuePair.Key, out collection))
throw new NotSupportedException();
if (keyValuePair.Value.Lines.Length != collection.Count)
logger.LogInformation("{name} has been changed", keyValuePair.Value.Name?.ForwardSlashFull);
lines.AddRange(keyValuePair.Value.Lines);
}
allLines.AddRange(lines);
File.WriteAllLines(Path.Combine(input.GenealogicalDataCommunicationDirectory, "b.pged"), lines);
}
if (genealogicalDataCommunicationCollections.FamilyGroupLines.Count > 0)
{
lines.Clear();
foreach (ReadOnlyCollection<string> keyValuePair in genealogicalDataCommunicationCollections.FamilyGroupLines)
lines.AddRange(keyValuePair);
allLines.AddRange(lines);
File.WriteAllLines(Path.Combine(input.GenealogicalDataCommunicationDirectory, "c.pged"), lines);
}
if (genealogicalDataCommunicationCollections.FooterLines.Count > 0)
{
allLines.AddRange(genealogicalDataCommunicationCollections.FooterLines);
File.WriteAllLines(Path.Combine(input.GenealogicalDataCommunicationDirectory, "d.pged"), genealogicalDataCommunicationCollections.FooterLines);
}
File.WriteAllLines(Path.Combine(input.GenealogicalDataCommunicationDirectory, "e.ged"), allLines);
}
private static string? GetYearGroup(string year) =>
!int.TryParse(year[2..], out int part) ? null : string.Concat(year[..^2], part < 50 ? "--" : "++");
private static (int, TimeSpan) GetAge(long minuendTicks, long subtrahendTicks)
{
TimeSpan result;
int years = 0;
DateTime check = new(subtrahendTicks);
for (int i = 0; i < int.MaxValue; i++)
{
check = check.AddYears(1);
if (check.Ticks > minuendTicks)
break;
years += 1;
}
result = new(minuendTicks - check.AddYears(-1).Ticks);
return (years, result);
}
private static void Export(Input input, long ticks, ReadOnlyDictionary<long, string> idToName, ReadOnlyCollection<(long, ReadOnlyCollection<string>, string, char[], DateTime, long)> collection)
{
int age;
string text;
string? name;
string directory;
string hourGroup;
string? yearGroup;
long count = ticks;
string rootDirectory;
string approximateYears;
List<string> distinct = new();
List<string> duplicates = new();
string personDisplayDirectoryName;
foreach ((long id, ReadOnlyCollection<string> lines, string personKeyFormatted, char[] ageCollection, DateTime dateTime, long personKey) in collection)
{
if (input.Destination is null)
break;
if (!idToName.TryGetValue(id, out name))
continue;
hourGroup = GetHourGroup(name, dateTime.Hour);
(age, _) = GetAge(DateTime.Now.Ticks, personKey);
for (int i = 1; i < 3; i++)
{
if (i == 2)
{
yearGroup = GetYearGroup(dateTime.Year.ToString());
personDisplayDirectoryName = name;
if (string.IsNullOrEmpty(yearGroup))
continue;
}
else if (i == 1)
{
yearGroup = ageCollection[0].ToString();
approximateYears = yearGroup[0] == '^' ? $"^{age}" : new string(ageCollection);
personDisplayDirectoryName = $"{name}{approximateYears}";
if (distinct.Contains(personDisplayDirectoryName))
{
duplicates.Add(personDisplayDirectoryName);
continue;
}
distinct.Add(personDisplayDirectoryName);
}
else
throw new NotSupportedException();
rootDirectory = i == 1 ? input.Destination : i == 2 ? input.GenealogicalDataCommunicationDirectory : throw new NotSupportedException();
directory = Path.Combine(rootDirectory, yearGroup, hourGroup, personDisplayDirectoryName, personKeyFormatted);
if (!Directory.Exists(directory))
_ = Directory.CreateDirectory(directory);
if (i == 2)
{
text = string.Join(Environment.NewLine, lines);
count += 1;
File.WriteAllText(Path.Combine(directory, $"{count}-A.pged"), text);
}
text = string.Join(Environment.NewLine, lines);
if (!string.IsNullOrEmpty(text))
{
count += 1;
if (i == 2)
File.WriteAllText(Path.Combine(directory, $"{count}-B.pged"), text);
else
File.WriteAllText(Path.Combine(directory, $"{personKeyFormatted}.pged"), text);
}
}
}
if (duplicates.Count > 0)
throw new NotSupportedException();
}
private static ReadOnlyCollection<GenealogicalDataCommunicationRelation> GetRelations(ReadOnlyCollection<ReadOnlyCollection<string>> familyGroupLines)
{
List<GenealogicalDataCommunicationRelation> results = new();
int id;
string relation;
string[] segments;
ReadOnlyCollection<string> familyLines;
for (int i = 0; i < familyGroupLines.Count; i++)
{
familyLines = familyGroupLines[i];
for (int j = 0; j < familyLines.Count; j++)
{
segments = familyLines[j].Split('@');
if (segments[0].Length < 3 || segments.Length != 3)
continue;
if (!int.TryParse(segments[1][1..], out id))
continue;
relation = segments[0][2..].Trim();
if (j + 1 >= familyLines.Count || familyLines[j + 1].Length < 3 || familyLines[j + 1][..3] != "2 _")
results.Add(new(i, relation, id, null));
else
results.Add(new(i, relation, id, familyLines[j + 1][2..]));
}
}
return new(results.OrderBy(l => l.FamilyIndex).ToArray());
}
internal static void FileSystemToGenealogicalDataCommunication(AppSettings appSettings, ILogger<Worker> logger, List<string> args)
{
Input input = GetInput(args);
long ticks = DateTime.Now.Ticks;
logger.LogInformation("{ticks}", ticks);
logger.LogInformation("{old} {days} day(s) => {new}", 638258293638438812, 4, new DateTime(638258293638438812).AddDays(4.0001).Ticks);
GenealogicalDataCommunicationCollections genealogicalDataCommunicationCollections = GetGenealogicalDataCommunicationCollections(input);
Dictionary<long, Person> people = GetPeople(input, genealogicalDataCommunicationCollections);
if (people.Count != genealogicalDataCommunicationCollections.IndividualsToLines.Count)
throw new NotSupportedException();
string json = JsonSerializer.Serialize(people, PeopleSourceGenerationContext.Default.DictionaryInt64Person);
File.WriteAllText(Path.Combine(input.GenealogicalDataCommunicationDirectory, ".json"), json);
Dictionary<long, Person>? result = JsonSerializer.Deserialize(json, PeopleSourceGenerationContext.Default.DictionaryInt64Person);
if (result is null)
throw new NullReferenceException(nameof(result));
(ReadOnlyDictionary<long, long> idToPersonKey, ReadOnlyDictionary<long, string> idToName, ReadOnlyDictionary<long, string> idToGivenName, ReadOnlyCollection<(long, ReadOnlyCollection<string>, string, char[], DateTime, long)> collection) = GetCollections(appSettings, people);
if (idToPersonKey.Count != people.Count || idToPersonKey.Count != idToName.Count || idToPersonKey.Count != idToGivenName.Count)
throw new NotSupportedException();
WriteGenealogicalDataCommunicationCollections(logger, input, genealogicalDataCommunicationCollections, people);
if (input.Destination is not null)
ExportFamilies(appSettings, input, genealogicalDataCommunicationCollections, idToPersonKey, idToName, idToGivenName);
if (input.Destination is not null)
Export(input, ticks, idToName, collection);
if (string.IsNullOrEmpty(input.GenealogicalDataCommunicationFile))
logger.LogInformation("{file} is null?", input.GenealogicalDataCommunicationDirectory);
}
}