Family Tree as Markdown Files

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

View File

@ -9,4 +9,4 @@ tags: []
# Family Tree as Markdown Files # Family Tree as Markdown Files
- [ ] Look at how I can export from ged files - [ ] Look at how I can export from ged files
- [x] In addition to writing the *.pged maybe write *.md also

View File

@ -41,8 +41,6 @@ public partial class DlibDotNet
private readonly List<PersonContainer> _PersonContainers; private readonly List<PersonContainer> _PersonContainers;
private readonly bool _ArgZeroIsConfigurationRootDirectory; private readonly bool _ArgZeroIsConfigurationRootDirectory;
private readonly Map.Models.Configuration _MapConfiguration; private readonly Map.Models.Configuration _MapConfiguration;
private readonly string[]? _GenealogicalDataCommunicationFooterLines;
private readonly string[]? _GenealogicalDataCommunicationHeaderLines;
public DlibDotNet( public DlibDotNet(
List<string> args, List<string> args,
@ -111,11 +109,7 @@ public partial class DlibDotNet
_MapConfiguration = Get(configuration, _Faces.FileNameExtension, _Faces.HiddenFileNameExtension, _FaceParts.FileNameExtension); _MapConfiguration = Get(configuration, _Faces.FileNameExtension, _Faces.HiddenFileNameExtension, _FaceParts.FileNameExtension);
_Distance = new(configuration.DistanceMoveUnableToMatch, configuration.DistanceRenameToMatch, _Configuration.FaceConfidencePercent, configuration.RangeDistanceTolerance, configuration.RangeFaceConfidence, configuration.RectangleIntersectMinimums); _Distance = new(configuration.DistanceMoveUnableToMatch, configuration.DistanceRenameToMatch, _Configuration.FaceConfidencePercent, configuration.RangeDistanceTolerance, configuration.RangeFaceConfidence, configuration.RectangleIntersectMinimums);
if (_PropertyRootExistedBefore || !_ArgZeroIsConfigurationRootDirectory) if (_PropertyRootExistedBefore || !_ArgZeroIsConfigurationRootDirectory)
{
_GenealogicalDataCommunicationFooterLines = null;
_GenealogicalDataCommunicationHeaderLines = null;
_PersonContainers = new(); _PersonContainers = new();
}
else else
{ {
int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds); int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds);
@ -128,9 +122,20 @@ public partial class DlibDotNet
string? rootResultsDirectory = Path.GetDirectoryName(Path.GetDirectoryName(peopleRootDirectory)) ?? throw new Exception(); string? rootResultsDirectory = Path.GetDirectoryName(Path.GetDirectoryName(peopleRootDirectory)) ?? throw new Exception();
Storage storage = new(rootDirectory, rootResultsDirectory, peopleRootDirectory); Storage storage = new(rootDirectory, rootResultsDirectory, peopleRootDirectory);
_ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(Path.Combine(peopleRootDirectory, _Configuration.PropertyConfiguration.ResultSingleton)); _ = Shared.Models.Stateless.Methods.IPath.DeleteEmptyDirectories(Path.Combine(peopleRootDirectory, _Configuration.PropertyConfiguration.ResultSingleton));
(_GenealogicalDataCommunicationHeaderLines, Dictionary<string, List<string>> individuals, _GenealogicalDataCommunicationFooterLines) = IGenealogicalDataCommunication.GetIndividuals(configuration.GenealogicalDataCommunicationFile, requireNickName: true); (string[] headerLines, ReadOnlyDictionary<string, string[]> individuals, List<string[]> familyGroupLines, string[] footerLines, List<GenealogicalDataCommunicationRelation> genealogicalDataCommunicationRelations) = IGenealogicalDataCommunication.GetIndividuals(configuration.GenealogicalDataCommunicationFile, requireNickName: true);
_PersonContainers = IPersonContainer.GetPersonContainers(storage, configuration.MappingDefaultName, configuration.PersonBirthdayFormat, configuration.PersonCharacters.ToArray(), _Faces.FileNameExtension, individuals); _PersonContainers = IPersonContainer.GetPersonContainers(storage, configuration.MappingDefaultName, configuration.PersonBirthdayFormat, configuration.PersonCharacters.ToArray(), _Faces.FileNameExtension, individuals);
VerifyPersonContainersDisplayDirectoryAllFiles(); VerifyPersonContainersDisplayDirectoryAllFiles();
if (!string.IsNullOrEmpty(_Configuration.GenealogicalDataCommunicationFile) && headerLines.Any() && familyGroupLines.Any() && genealogicalDataCommunicationRelations.Any() && footerLines.Any())
{
string a2PeopleContentDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(A2_People), "([])");
TimeSpan a2LastWriteTimeTimeSpan = new(ticks - new DirectoryInfo(a2PeopleContentDirectory).LastWriteTime.Ticks);
if (a2LastWriteTimeTimeSpan.TotalDays > 1)
{
IPersonContainer.MaybeWriteFiles(configuration.MappingDefaultName, configuration.PersonBirthdayFormat, genealogicalDataCommunicationRelations, _PersonContainers);
if (IGenealogicalDataCommunication.CleanDisplayDirectoryAllFilesAndWriteTicksGed(_Configuration.MappingDefaultName, _Configuration.PersonBirthdayFormat, _PersonContainers, headerLines, familyGroupLines, footerLines, ticks, a2PeopleContentDirectory))
_PersonContainers = IPersonContainer.GetPersonContainers(storage, configuration.MappingDefaultName, configuration.PersonBirthdayFormat, configuration.PersonCharacters.ToArray(), _Faces.FileNameExtension, individuals);
}
}
} }
{ {
(ImageCodecInfo imageCodecInfo, EncoderParameters encoderParameters, string filenameExtension) = C_Resize.GetTuple( (ImageCodecInfo imageCodecInfo, EncoderParameters encoderParameters, string filenameExtension) = C_Resize.GetTuple(
@ -1150,6 +1155,7 @@ public partial class DlibDotNet
int t; int t;
int count; int count;
string message; string message;
MapLogic? mapLogic;
Container[] containers; Container[] containers;
A_Property propertyLogic; A_Property propertyLogic;
string eDistanceContentDirectory; string eDistanceContentDirectory;
@ -1167,17 +1173,23 @@ public partial class DlibDotNet
List<string[]>? filesCollection = null; List<string[]>? filesCollection = null;
const string directorySearchFilter = "*"; const string directorySearchFilter = "*";
Dictionary<long, List<int>> personKeyToIds; Dictionary<long, List<int>> personKeyToIds;
bool eLastWriteTimeTimeSpanIsMoreThen = false; bool configurationOutputResolutionsHas = false;
Dictionary<int, List<MappingFromPhotoPrism>> fileNameToCollection; Dictionary<int, List<MappingFromPhotoPrism>> fileNameToCollection;
(aResultsFullGroupDirectory, bResultsFullGroupDirectory) = GetResultsFullGroupDirectories(); (aResultsFullGroupDirectory, bResultsFullGroupDirectory) = GetResultsFullGroupDirectories();
ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
a2PeopleContentDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(A2_People), "([])");
eDistanceContentDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(E_Distance), _Configuration.PropertyConfiguration.ResultContent); eDistanceContentDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(E_Distance), _Configuration.PropertyConfiguration.ResultContent);
string a2PeopleSingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(A2_People), _Configuration.PropertyConfiguration.ResultSingleton);
TimeSpan eLastWriteTimeTimeSpan = new(ticks - new DirectoryInfo(eDistanceContentDirectory).LastWriteTime.Ticks); TimeSpan eLastWriteTimeTimeSpan = new(ticks - new DirectoryInfo(eDistanceContentDirectory).LastWriteTime.Ticks);
if (eLastWriteTimeTimeSpan.TotalDays < 1)
mapLogic = null;
else
mapLogic = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _MapConfiguration, new(_PersonContainers), ticks, a2PeopleSingletonDirectory, eDistanceContentDirectory);
foreach (string outputResolution in _Configuration.OutputResolutions) foreach (string outputResolution in _Configuration.OutputResolutions)
{ {
if (outputResolution.Any(l => char.IsNumber(l))) if (outputResolution.Any(l => char.IsNumber(l)))
continue; continue;
eLastWriteTimeTimeSpanIsMoreThen = true; configurationOutputResolutionsHas = true;
if (eLastWriteTimeTimeSpan.TotalDays < 1) if (eLastWriteTimeTimeSpan.TotalDays < 1)
break; break;
ProgressBar progressBar; ProgressBar progressBar;
@ -1196,10 +1208,8 @@ public partial class DlibDotNet
progressBar.Dispose(); progressBar.Dispose();
break; break;
} }
a2PeopleContentDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(A2_People), "([])");
fPhotoPrismContentDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(F_PhotoPrism), _Configuration.PropertyConfiguration.ResultContent); fPhotoPrismContentDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(F_PhotoPrism), _Configuration.PropertyConfiguration.ResultContent);
fPhotoPrismSingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(F_PhotoPrism), _Configuration.PropertyConfiguration.ResultSingleton); fPhotoPrismSingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(F_PhotoPrism), _Configuration.PropertyConfiguration.ResultSingleton);
string a2PeopleSingletonDirectory = Property.Models.Stateless.IResult.GetResultsDateGroupDirectory(_Configuration.PropertyConfiguration, nameof(A2_People), _Configuration.PropertyConfiguration.ResultSingleton);
propertyLogic = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _Resize.FileNameExtension, _Configuration.Reverse, aResultsFullGroupDirectory); propertyLogic = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _Resize.FileNameExtension, _Configuration.Reverse, aResultsFullGroupDirectory);
if (filesCollectionCountIsOne) if (filesCollectionCountIsOne)
{ {
@ -1221,7 +1231,7 @@ public partial class DlibDotNet
propertyRoot = Property.Models.Stateless.IResult.GetResultsGroupDirectory(_Configuration.PropertyConfiguration, nameof(A_Property), create: false); propertyRoot = Property.Models.Stateless.IResult.GetResultsGroupDirectory(_Configuration.PropertyConfiguration, nameof(A_Property), create: false);
propertyLogic = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _Resize.FileNameExtension, _Configuration.Reverse, aResultsFullGroupDirectory); propertyLogic = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _Resize.FileNameExtension, _Configuration.Reverse, aResultsFullGroupDirectory);
} }
if (eLastWriteTimeTimeSpanIsMoreThen) if (configurationOutputResolutionsHas)
{ {
foreach (string outputResolution in _Configuration.OutputResolutions) foreach (string outputResolution in _Configuration.OutputResolutions)
{ {
@ -1247,19 +1257,14 @@ public partial class DlibDotNet
} }
fileNameToCollection = !Directory.Exists(fPhotoPrismSingletonDirectory) ? fileNameToCollection = new() : F_PhotoPrism.GetFileNameToCollection(fPhotoPrismSingletonDirectory); fileNameToCollection = !Directory.Exists(fPhotoPrismSingletonDirectory) ? fileNameToCollection = new() : F_PhotoPrism.GetFileNameToCollection(fPhotoPrismSingletonDirectory);
B_Metadata metadata = new(_Configuration.PropertyConfiguration, _Configuration.ForceMetadataLastWriteTimeToCreationTime, _Configuration.PropertiesChangedForMetadata, bResultsFullGroupDirectory); B_Metadata metadata = new(_Configuration.PropertyConfiguration, _Configuration.ForceMetadataLastWriteTimeToCreationTime, _Configuration.PropertiesChangedForMetadata, bResultsFullGroupDirectory);
MapLogic mapLogic = new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _MapConfiguration, new(_PersonContainers), ticks, a2PeopleSingletonDirectory, eDistanceContentDirectory); mapLogic ??= new(_AppSettings.MaxDegreeOfParallelism, _Configuration.PropertyConfiguration, _MapConfiguration, new(_PersonContainers), ticks, a2PeopleSingletonDirectory, eDistanceContentDirectory);
_PersonContainers.AddRange(IPersonContainer.GetNonSpecificPeopleCollection(_Configuration.MappingDefaultName, _Configuration.PersonBirthdayFirstYear, _Configuration.PersonCharacters.ToArray(), _PersonContainers, ticks)); _PersonContainers.AddRange(IPersonContainer.GetNonSpecificPeopleCollection(_Configuration.MappingDefaultName, _Configuration.PersonBirthdayFirstYear, _Configuration.PersonCharacters.ToArray(), _PersonContainers, ticks));
containers = Shared.Models.Stateless.Methods.IContainer.SortContainers(_Configuration.PropertyConfiguration, _Configuration.IgnoreRelativePaths, _ArgZeroIsConfigurationRootDirectory, argZero, containers); containers = Shared.Models.Stateless.Methods.IContainer.SortContainers(_Configuration.PropertyConfiguration, _Configuration.IgnoreRelativePaths, _ArgZeroIsConfigurationRootDirectory, argZero, containers);
personKeyToIds = mapLogic.GetPersonKeyToIds();
if (!string.IsNullOrEmpty(_Configuration.GenealogicalDataCommunicationFile) && !string.IsNullOrEmpty(a2PeopleContentDirectory) && _GenealogicalDataCommunicationHeaderLines is not null && _GenealogicalDataCommunicationFooterLines is not null && _GenealogicalDataCommunicationHeaderLines.Any() && _GenealogicalDataCommunicationFooterLines.Any())
IGenealogicalDataCommunication.CreateTree(_Configuration.MappingDefaultName, _Configuration.PersonBirthdayFormat, _Configuration.PropertyConfiguration.ResultAllInOne, _PersonContainers, _GenealogicalDataCommunicationHeaderLines, _GenealogicalDataCommunicationFooterLines, ticks, a2PeopleContentDirectory, personKeyToIds);
ReadOnlyDictionary<int, List<LocationContainer<MetadataExtractor.Directory>>> idToLocationContainers = mapLogic.GetIdToLocationContainers(); ReadOnlyDictionary<int, List<LocationContainer<MetadataExtractor.Directory>>> idToLocationContainers = mapLogic.GetIdToLocationContainers();
FullDoWork(argZero, propertyRoot, ticks, aResultsFullGroupDirectory, bResultsFullGroupDirectory, t, containers, propertyLogic, metadata, fileNameToCollection, idToLocationContainers, mapLogic); FullDoWork(argZero, propertyRoot, ticks, aResultsFullGroupDirectory, bResultsFullGroupDirectory, t, containers, propertyLogic, metadata, fileNameToCollection, idToLocationContainers, mapLogic);
if (_Configuration.LookForAbandoned) if (_Configuration.LookForAbandoned)
LookForAbandoned(bResultsFullGroupDirectory, containers, idToLocationContainers); LookForAbandoned(bResultsFullGroupDirectory, containers, idToLocationContainers);
_Distance.Clear(); _Distance.Clear();
if (!personKeyToIds.Any())
personKeyToIds = mapLogic.GetPersonKeyToIds();
List<Item> distinctFilteredItems = Shared.Models.Stateless.Methods.IContainer.GetItems(_Configuration.PropertyConfiguration, containers, distinctItems: true, filterItems: true); List<Item> distinctFilteredItems = Shared.Models.Stateless.Methods.IContainer.GetItems(_Configuration.PropertyConfiguration, containers, distinctItems: true, filterItems: true);
Verify(eDistanceContentDirectory, distinctFilteredItems); Verify(eDistanceContentDirectory, distinctFilteredItems);
List<Shared.Models.Face> distinctFilteredFaces = Map.Models.Stateless.Methods.IMapLogic.GetFaces(distinctFilteredItems); List<Shared.Models.Face> distinctFilteredFaces = Map.Models.Stateless.Methods.IMapLogic.GetFaces(distinctFilteredItems);
@ -1273,6 +1278,7 @@ public partial class DlibDotNet
{ {
if (_PropertyRootExistedBefore) if (_PropertyRootExistedBefore)
break; break;
personKeyToIds = mapLogic.GetPersonKeyToIds();
if (!string.IsNullOrEmpty(a2PeopleContentDirectory) && _Configuration.SaveShortcutsForOutputResolutions.Contains(outputResolution)) if (!string.IsNullOrEmpty(a2PeopleContentDirectory) && _Configuration.SaveShortcutsForOutputResolutions.Contains(outputResolution))
mapLogic.SaveShortcutsForOutputResolutionsPreMapLogic(eDistanceContentDirectory, personKeyToIds, distinctFilteredMappingCollection); mapLogic.SaveShortcutsForOutputResolutionsPreMapLogic(eDistanceContentDirectory, personKeyToIds, distinctFilteredMappingCollection);
if (!string.IsNullOrEmpty(a2PeopleContentDirectory) && _Configuration.SaveFilteredOriginalImagesFromJLinksForOutputResolutions.Contains(outputResolution)) if (!string.IsNullOrEmpty(a2PeopleContentDirectory) && _Configuration.SaveFilteredOriginalImagesFromJLinksForOutputResolutions.Contains(outputResolution))

View File

@ -13,6 +13,10 @@ namespace View_by_Distance.Map.Models.Stateless;
internal abstract class MapLogic internal abstract class MapLogic
{ {
private record Record(string PersonKeyFormatted,
string[] PersonDisplayDirectoryNames,
string MappedFaceFile);
private static void SetPersonCollections(Configuration configuration, ReadOnlyCollection<PersonContainer> personContainers, string? a2PeopleSingletonDirectory, Dictionary<string, string> personKeyFormattedToNewestPersonKeyFormatted, List<string> personKeyFormattedCollection, Dictionary<int, List<int>> skipCollection, Dictionary<int, List<int>> skipNotSkipCollection) private static void SetPersonCollections(Configuration configuration, ReadOnlyCollection<PersonContainer> personContainers, string? a2PeopleSingletonDirectory, Dictionary<string, string> personKeyFormattedToNewestPersonKeyFormatted, List<string> personKeyFormattedCollection, Dictionary<int, List<int>> skipCollection, Dictionary<int, List<int>> skipNotSkipCollection)
{ {
int? id; int? id;
@ -150,12 +154,45 @@ internal abstract class MapLogic
} }
} }
internal static List<(string, string[], string)> DeleteEmptyDirectoriesAndGetCollection(Configuration configuration, List<string> personKeyFormattedCollection, string[] ticksDirectories, string message) private static void MoveFiles(string personKeyFormatted, string personKeyDirectory, string newestPersonKeyFormatted, string newestPersonKeyDirectory)
{ {
List<(string, string[], string)> results = new(); string[] files;
string checkFile;
string? checkDirectory;
string[] directories = Directory.GetDirectories(personKeyDirectory, "*", SearchOption.TopDirectoryOnly);
foreach (string directory in directories)
{
checkDirectory = Path.Combine(newestPersonKeyDirectory, Path.GetFileName(directory));
if (!Directory.Exists(checkDirectory))
Directory.Move(directory, checkDirectory);
else
{
files = Directory.GetFiles(directory, "*", SearchOption.AllDirectories);
foreach (string file in files)
{
if (file.Split(personKeyFormatted).Length != 2 || file.Contains(newestPersonKeyFormatted))
continue;
checkFile = file.Replace(personKeyFormatted, newestPersonKeyFormatted);
checkDirectory = Path.GetDirectoryName(checkFile);
if (checkDirectory is null)
continue;
if (File.Exists(checkFile))
continue;
if (!Directory.Exists(checkDirectory))
_ = Directory.CreateDirectory(checkDirectory);
File.Move(file, checkFile);
}
}
}
}
private static List<Record> DeleteEmptyDirectoriesAndGetCollection(Configuration configuration, Dictionary<string, string> personKeyFormattedToNewestPersonKeyFormatted, List<string> personKeyFormattedCollection, string[] ticksDirectories, string message)
{
List<Record> results = new();
int? id; int? id;
string[] files; string[] files;
string fileName; string fileName;
bool check = false;
const int zero = 0; const int zero = 0;
int? wholePercentages; int? wholePercentages;
string[] yearDirectories; string[] yearDirectories;
@ -166,6 +203,8 @@ internal abstract class MapLogic
List<string> distinct = new(); List<string> distinct = new();
string[] personKeyDirectories; string[] personKeyDirectories;
string[] personNameDirectories; string[] personNameDirectories;
string newestPersonKeyDirectory;
string? newestPersonKeyFormatted;
string[] personNameLinkDirectories; string[] personNameLinkDirectories;
string? personFirstInitialDirectory; string? personFirstInitialDirectory;
string[] personDisplayDirectoryNames; string[] personDisplayDirectoryNames;
@ -189,6 +228,17 @@ internal abstract class MapLogic
Individually(configuration, ticksDirectory, personKeyDirectory); Individually(configuration, ticksDirectory, personKeyDirectory);
throw new Exception($"B) Move personKey directories up one from {nameof(Shared.Models.Stateless.IMapLogic.Sorting)} and delete {nameof(Shared.Models.Stateless.IMapLogic.Sorting)} directory!"); throw new Exception($"B) Move personKey directories up one from {nameof(Shared.Models.Stateless.IMapLogic.Sorting)} and delete {nameof(Shared.Models.Stateless.IMapLogic.Sorting)} directory!");
} }
if (personKeyFormattedToNewestPersonKeyFormatted.TryGetValue(personKeyFormatted, out newestPersonKeyFormatted) && personKeyFormatted != newestPersonKeyFormatted)
{
if (!check)
check = true;
newestPersonKeyDirectory = Path.Combine(ticksDirectory, newestPersonKeyFormatted);
if (Directory.Exists(newestPersonKeyDirectory))
MoveFiles(personKeyFormatted, personKeyDirectory, newestPersonKeyFormatted, newestPersonKeyDirectory);
else
Directory.Move(personKeyDirectory, newestPersonKeyDirectory);
continue;
}
yearDirectories = Directory.GetDirectories(personKeyDirectory, "*", SearchOption.TopDirectoryOnly); yearDirectories = Directory.GetDirectories(personKeyDirectory, "*", SearchOption.TopDirectoryOnly);
foreach (string yearDirectory in yearDirectories) foreach (string yearDirectory in yearDirectories)
{ {
@ -201,6 +251,11 @@ internal abstract class MapLogic
personDisplayDirectoryNames = IPath.GetDirectoryNames(personNameDirectory); personDisplayDirectoryNames = IPath.GetDirectoryNames(personNameDirectory);
if (!personDisplayDirectoryNames.Any()) if (!personDisplayDirectoryNames.Any())
continue; continue;
if (newestPersonKeyFormatted is null)
{
if (!IPerson.IsDefaultName(configuration.MappingDefaultName, personDisplayDirectoryNames[^1]))
throw new NotImplementedException("Should this happen?");
}
files = Directory.GetFiles(personNameDirectory, "*", SearchOption.TopDirectoryOnly); files = Directory.GetFiles(personNameDirectory, "*", SearchOption.TopDirectoryOnly);
if (isReservedDirectoryName && files.Any()) if (isReservedDirectoryName && files.Any())
throw new Exception($"Move personKey directories up one from {nameof(Shared.Models.Stateless.IMapLogic.Sorting)} and delete {nameof(Shared.Models.Stateless.IMapLogic.Sorting)} directory!"); throw new Exception($"Move personKey directories up one from {nameof(Shared.Models.Stateless.IMapLogic.Sorting)} and delete {nameof(Shared.Models.Stateless.IMapLogic.Sorting)} directory!");
@ -231,22 +286,22 @@ internal abstract class MapLogic
Directory.Move(personNameDirectory, personFirstInitialDirectory); Directory.Move(personNameDirectory, personFirstInitialDirectory);
files = Directory.GetFiles(personFirstInitialDirectory, "*", SearchOption.TopDirectoryOnly); files = Directory.GetFiles(personFirstInitialDirectory, "*", SearchOption.TopDirectoryOnly);
} }
foreach (string file in files) foreach (string mappedFaceFile in files)
{ {
if (file.EndsWith(".lnk")) if (mappedFaceFile.EndsWith(".lnk"))
continue; continue;
(id, wholePercentages) = IMapping.GetConverted(configuration.FacesFileNameExtension, file); (id, wholePercentages) = IMapping.GetConverted(configuration.FacesFileNameExtension, mappedFaceFile);
if (id is null || wholePercentages is null) if (id is null || wholePercentages is null)
continue; continue;
fileName = Path.GetFileName(file); fileName = Path.GetFileName(mappedFaceFile);
if (distinct.Contains(fileName)) if (distinct.Contains(fileName))
{ {
if (!File.Exists($"{file}.dup")) if (!File.Exists($"{mappedFaceFile}.dup"))
File.Move(file, $"{file}.dup"); File.Move(mappedFaceFile, $"{mappedFaceFile}.dup");
continue; continue;
} }
distinct.Add(fileName); distinct.Add(fileName);
results.Add(new(personKeyFormatted, personDisplayDirectoryNames, file)); results.Add(new(personKeyFormatted, personDisplayDirectoryNames, mappedFaceFile));
} }
personNameLinkDirectories = Directory.GetDirectories(personFirstInitialDirectory, "*", SearchOption.TopDirectoryOnly); personNameLinkDirectories = Directory.GetDirectories(personFirstInitialDirectory, "*", SearchOption.TopDirectoryOnly);
foreach (string personNameLinkDirectory in personNameLinkDirectories) foreach (string personNameLinkDirectory in personNameLinkDirectories)
@ -269,6 +324,8 @@ internal abstract class MapLogic
_ = IPath.DeleteEmptyDirectories(ticksDirectory); _ = IPath.DeleteEmptyDirectories(ticksDirectory);
_ = IPath.DeleteEmptyDirectories(ticksDirectory); _ = IPath.DeleteEmptyDirectories(ticksDirectory);
} }
if (check)
throw new Exception("PersonKey director(ies) where renamed. Please restart!");
return results; return results;
} }
@ -363,12 +420,11 @@ internal abstract class MapLogic
return results; return results;
} }
private static int SetCollectionsAndGetUnableToConvertCount(Configuration configuration, long ticks, Dictionary<string, string> personKeyFormattedToNewestPersonKeyFormatted, List<(string, string[], int, int)> personKeyFormattedIdThenWholePercentagesCollection, List<(string, string[], string)> collection) private static int SetCollectionsAndGetUnableToConvertCount(Configuration configuration, long ticks, List<(string, string[], int, int)> personKeyFormattedIdThenWholePercentagesCollection, List<Record> collection)
{ {
int result = 0; int result = 0;
int? id; int? id;
int? wholePercentages; int? wholePercentages;
string? newestPersonKeyFormatted;
string personDisplayDirectoryName; string personDisplayDirectoryName;
List<int> wholePercentagesCollection; List<int> wholePercentagesCollection;
Dictionary<int, List<int>> idToWholePercentagesCollection = new(); Dictionary<int, List<int>> idToWholePercentagesCollection = new();
@ -379,12 +435,6 @@ internal abstract class MapLogic
foreach ((string personKeyFormatted, string[] personDisplayDirectoryNames, string mappedFaceFile) in collection) foreach ((string personKeyFormatted, string[] personDisplayDirectoryNames, string mappedFaceFile) in collection)
{ {
progressBar.Tick(); progressBar.Tick();
if (!personKeyFormattedToNewestPersonKeyFormatted.TryGetValue(personKeyFormatted, out newestPersonKeyFormatted))
{
if (personDisplayDirectoryNames.Any() && !IPerson.IsDefaultName(configuration.MappingDefaultName, personDisplayDirectoryNames[^1]))
continue;
newestPersonKeyFormatted = personKeyFormatted;
}
(id, wholePercentages) = IMapping.GetConverted(configuration.FacesFileNameExtension, mappedFaceFile); (id, wholePercentages) = IMapping.GetConverted(configuration.FacesFileNameExtension, mappedFaceFile);
if (id is null || wholePercentages is null) if (id is null || wholePercentages is null)
{ {
@ -399,7 +449,7 @@ internal abstract class MapLogic
personDisplayDirectoryName = personDisplayDirectoryNames[^1]; personDisplayDirectoryName = personDisplayDirectoryNames[^1];
if (string.IsNullOrEmpty(personDisplayDirectoryName)) if (string.IsNullOrEmpty(personDisplayDirectoryName))
continue; continue;
personKeyFormattedIdThenWholePercentagesCollection.Add(new(newestPersonKeyFormatted, personDisplayDirectoryNames, id.Value, wholePercentages.Value)); personKeyFormattedIdThenWholePercentagesCollection.Add(new(personKeyFormatted, personDisplayDirectoryNames, id.Value, wholePercentages.Value));
} }
return result; return result;
} }
@ -543,7 +593,7 @@ internal abstract class MapLogic
collection.Add((ticksDirectory, new TimeSpan(directoryTicks - lastDirectoryTicks.Value))); collection.Add((ticksDirectory, new TimeSpan(directoryTicks - lastDirectoryTicks.Value)));
lastDirectoryTicks = directoryTicks; lastDirectoryTicks = directoryTicks;
} }
string[] compare = (from l in collection where l.TimeSpan.TotalDays < 4 select l.Directory).ToArray(); string[] compare = (from l in collection where l.TimeSpan.TotalDays < 3.95 select l.Directory).ToArray();
if (compare.Any()) if (compare.Any())
throw new Exception($"Please Consolidate <{string.Join(Environment.NewLine, compare)}>"); throw new Exception($"Please Consolidate <{string.Join(Environment.NewLine, compare)}>");
return results; return results;
@ -552,6 +602,7 @@ internal abstract class MapLogic
private static List<(long, string)> GetDisplayDirectoryAllFiles(string fileNameExtension, ReadOnlyCollection<PersonContainer> personContainers) private static List<(long, string)> GetDisplayDirectoryAllFiles(string fileNameExtension, ReadOnlyCollection<PersonContainer> personContainers)
{ {
List<(long, string)> results = new(); List<(long, string)> results = new();
string fileName;
List<string> distinct = new(); List<string> distinct = new();
foreach (PersonContainer personContainer in personContainers) foreach (PersonContainer personContainer in personContainers)
{ {
@ -559,35 +610,38 @@ internal abstract class MapLogic
continue; continue;
foreach (string displayDirectoryAllFile in personContainer.DisplayDirectoryAllFiles) foreach (string displayDirectoryAllFile in personContainer.DisplayDirectoryAllFiles)
{ {
if (!displayDirectoryAllFile.EndsWith(fileNameExtension)) fileName = Path.GetFileName(displayDirectoryAllFile);
if (!fileName.EndsWith(fileNameExtension))
continue; continue;
if (distinct.Contains(displayDirectoryAllFile)) if (distinct.Contains(fileName))
continue; continue;
distinct.Add(displayDirectoryAllFile); distinct.Add(fileName);
results.Add(new(personContainer.Key.Value, displayDirectoryAllFile)); results.Add(new(personContainer.Key.Value, displayDirectoryAllFile));
} }
} }
return results; return results;
} }
private static List<(long PersonKey, string File)> GetCollection(Configuration configuration, ReadOnlyCollection<PersonContainer> personContainers, List<(string, string[], string)> collection) private static List<(long PersonKey, string File)> GetCollection(Configuration configuration, ReadOnlyCollection<PersonContainer> personContainers, List<Record> records)
{ {
List<(long PersonKey, string File)> results = new(); List<(long PersonKey, string File)> results = new();
string file; string file;
long personKey; long personKey;
string fileName;
List<string> distinct = new(); List<string> distinct = new();
PersonBirthday? personBirthday; PersonBirthday? personBirthday;
results.AddRange(GetDisplayDirectoryAllFiles(configuration.FacesFileNameExtension, personContainers)); results.AddRange(GetDisplayDirectoryAllFiles(configuration.FacesFileNameExtension, personContainers));
foreach ((string personKeyFormatted, _, string mappedFaceFile) in collection) foreach (Record record in records)
{ {
personBirthday = IPersonBirthday.GetPersonBirthday(configuration.PersonBirthdayFormat, personKeyFormatted); personBirthday = IPersonBirthday.GetPersonBirthday(configuration.PersonBirthdayFormat, record.PersonKeyFormatted);
if (personBirthday is null) if (personBirthday is null)
continue; continue;
if (distinct.Contains(mappedFaceFile)) fileName = Path.GetFileName(record.MappedFaceFile);
if (distinct.Contains(fileName))
continue; continue;
distinct.Add(mappedFaceFile); distinct.Add(fileName);
personKey = personBirthday.Value.Ticks; personKey = personBirthday.Value.Ticks;
results.Add(new(personKey, mappedFaceFile)); results.Add(new(personKey, record.MappedFaceFile));
} }
for (int i = results.Count - 1; i > -1; i--) for (int i = results.Count - 1; i > -1; i--)
{ {
@ -700,10 +754,10 @@ internal abstract class MapLogic
} }
} }
private static List<LocationContainer<MetadataExtractor.Directory>> GetLocationContainers(int maxDegreeOfParallelism, Configuration configuration, long ticks, ReadOnlyCollection<PersonContainer> personContainers, string eDistanceContentDirectory, List<(string, string[], string)> sourceCollection) private static List<LocationContainer<MetadataExtractor.Directory>> GetLocationContainers(int maxDegreeOfParallelism, Configuration configuration, long ticks, ReadOnlyCollection<PersonContainer> personContainers, string eDistanceContentDirectory, List<Record> records)
{ {
List<LocationContainer<MetadataExtractor.Directory>> results = new(); List<LocationContainer<MetadataExtractor.Directory>> results = new();
List<(long PersonKey, string File)> collection = GetCollection(configuration, personContainers, sourceCollection); List<(long PersonKey, string File)> collection = GetCollection(configuration, personContainers, records);
if (collection.Any() && (configuration.DistanceMoveUnableToMatch || configuration.DistanceRenameToMatch)) if (collection.Any() && (configuration.DistanceMoveUnableToMatch || configuration.DistanceRenameToMatch))
{ {
int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds); int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds);
@ -734,17 +788,16 @@ internal abstract class MapLogic
List<(string, string[], int, int)> personKeyFormattedIdThenWholePercentagesCollection = new(); List<(string, string[], int, int)> personKeyFormattedIdThenWholePercentagesCollection = new();
List<(string[], PersonContainer)> possiblyNewPersonDisplayDirectoryNamesAndPersonContainer = new(); List<(string[], PersonContainer)> possiblyNewPersonDisplayDirectoryNamesAndPersonContainer = new();
SetPersonCollections(configuration, personContainers, a2PeopleSingletonDirectory, personKeyFormattedToNewestPersonKeyFormatted, personKeyFormattedCollection, skipCollection, skipNotSkipCollection); SetPersonCollections(configuration, personContainers, a2PeopleSingletonDirectory, personKeyFormattedToNewestPersonKeyFormatted, personKeyFormattedCollection, skipCollection, skipNotSkipCollection);
// personContainers.AddRange(GetNonSpecificPeopleCollection(configuration, ticks, personKeys));
totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds); totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds);
message = $") {ticksDirectories.Length:000} compile from and clean ticks Director(ies) - B - {totalSeconds} total second(s)"; message = $") {ticksDirectories.Length:000} compile from and clean ticks Director(ies) - B - {totalSeconds} total second(s)";
List<(string, string[], string)> collection = DeleteEmptyDirectoriesAndGetCollection(configuration, personKeyFormattedCollection, ticksDirectories, message); List<Record> records = DeleteEmptyDirectoriesAndGetCollection(configuration, personKeyFormattedToNewestPersonKeyFormatted, personKeyFormattedCollection, ticksDirectories, message);
locationContainers.AddRange(GetLocationContainers(maxDegreeOfParallelism, configuration, ticks, personContainers, eDistanceContentDirectory, collection)); locationContainers.AddRange(GetLocationContainers(maxDegreeOfParallelism, configuration, ticks, personContainers, eDistanceContentDirectory, records));
int unableToMatchCount = SetCollectionsAndGetUnableToConvertCount(configuration, ticks, personKeyFormattedToNewestPersonKeyFormatted, personKeyFormattedIdThenWholePercentagesCollection, collection); int unableToMatchCount = SetCollectionsAndGetUnableToConvertCount(configuration, ticks, personKeyFormattedIdThenWholePercentagesCollection, records);
SetKeyValuePairs(configuration, personContainers, personKeyToPersonContainerCollection, personKeyFormattedToPersonContainer, personKeyFormattedIdThenWholePercentagesCollection, personKeyToPersonContainer, idThenWholePercentagesToPersonContainers, possiblyNewPersonDisplayDirectoryNamesAndPersonContainer); SetKeyValuePairs(configuration, personContainers, personKeyToPersonContainerCollection, personKeyFormattedToPersonContainer, personKeyFormattedIdThenWholePercentagesCollection, personKeyToPersonContainer, idThenWholePercentagesToPersonContainers, possiblyNewPersonDisplayDirectoryNamesAndPersonContainer);
totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds); totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds);
message = $") {collection.Count:000} message from ticks Director(ies) - D - {unableToMatchCount} Unable To Match Count / {collection.Count} Collection - {totalSeconds} total second(s)"; message = $") {records.Count:000} message from ticks Director(ies) - D - {unableToMatchCount} Unable To Match Count / {records.Count} Collection - {totalSeconds} total second(s)";
ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true }; ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
using (ProgressBar progressBar = new(collection.Count, message, options)) using (ProgressBar progressBar = new(records.Count, message, options))
{ {
foreach (KeyValuePair<int, Dictionary<int, PersonContainer[]>> keyValuePair in idThenWholePercentagesToPersonContainers) foreach (KeyValuePair<int, Dictionary<int, PersonContainer[]>> keyValuePair in idThenWholePercentagesToPersonContainers)
{ {

View File

@ -2,7 +2,17 @@ using System.Text.Json;
namespace View_by_Distance.Shared.Models; 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() public override string ToString()

View File

@ -2,7 +2,17 @@ using System.Text.Json;
namespace View_by_Distance.Shared.Models; 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() 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 PersonBirthday[]? Birthdays { init; get; }
public string[] DisplayDirectoryAllFiles { init; get; } public string[] DisplayDirectoryAllFiles { init; get; }
public string DisplayDirectoryName { init; get; } public string DisplayDirectoryName { init; get; }
public string[]? GenealogicalDataCommunicationRelationIndividualsLines { init; get; }
public long? Key { init; get; } public long? Key { init; get; }
public bool? KeyIsMaxBirthday { init; get; } public bool? KeyIsMaxBirthday { init; get; }
public Person? Person { init; get; } public Person? Person { init; get; }
public PersonDirectory? PersonDirectory { init; get; } public PersonDirectory? PersonDirectory { init; get; }
[JsonConstructor] [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; ApproximateYears = approximateYears;
Birthdays = birthdays; Birthdays = birthdays;
DisplayDirectoryAllFiles = displayDirectoryAllFiles; DisplayDirectoryAllFiles = displayDirectoryAllFiles;
DisplayDirectoryName = displayDirectoryName; DisplayDirectoryName = displayDirectoryName;
GenealogicalDataCommunicationRelationIndividualsLines = genealogicalDataCommunicationRelationIndividualsLines;
Key = key; Key = key;
Person = person; Person = person;
PersonDirectory = personDirectory; PersonDirectory = personDirectory;
@ -29,23 +31,23 @@ public class PersonContainer : Properties.IPersonContainer
} }
public PersonContainer(string mappingDefaultName, char[] personCharacters, PersonBirthday birthday, string displayDirectoryName) : 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) : 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) : 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) : 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) : 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() public override string ToString()

View File

@ -7,6 +7,7 @@ public interface IPersonContainer
public PersonBirthday[]? Birthdays { init; get; } public PersonBirthday[]? Birthdays { init; get; }
public string[] DisplayDirectoryAllFiles { init; get; } public string[] DisplayDirectoryAllFiles { init; get; }
public string DisplayDirectoryName { init; get; } public string DisplayDirectoryName { init; get; }
public string[]? GenealogicalDataCommunicationRelationIndividualsLines { init; get; }
public long? Key { init; get; } public long? Key { init; get; }
public bool? KeyIsMaxBirthday { init; get; } public bool? KeyIsMaxBirthday { init; get; }
public Person? Person { 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; namespace View_by_Distance.Shared.Models.Stateless.Methods;
internal abstract class GenealogicalDataCommunication internal abstract class GenealogicalDataCommunication
@ -17,13 +19,52 @@ internal abstract class GenealogicalDataCommunication
return results.ToArray(); 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? 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(); List<string> lines = new();
const string startsWith = "0 @"; const string startsWith = "0 @";
List<string> footerLines = new(); 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[] sourceLines = string.IsNullOrEmpty(genealogicalDataCommunicationFile) || !File.Exists(genealogicalDataCommunicationFile) ? Array.Empty<string>() : File.ReadAllLines(genealogicalDataCommunicationFile);
string[] headerLines = GetHeaderLines(startsWith, sourceLines); string[] headerLines = GetHeaderLines(startsWith, sourceLines);
for (int i = headerLines.Length; i < sourceLines.Length; i++) for (int i = headerLines.Length; i < sourceLines.Length; i++)
@ -36,13 +77,29 @@ internal abstract class GenealogicalDataCommunication
continue; continue;
else if (sourceLines[i].EndsWith("@ FAM")) 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]); 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; break;
} }
else if (sourceLines[i].EndsWith("@ INDI")) else if (sourceLines[i].EndsWith("@ INDI"))
{ {
segments = sourceLines[i].Split('@');
for (int j = i + 1; j < sourceLines.Length; j++) for (int j = i + 1; j < sourceLines.Length; j++)
{ {
if (sourceLines[j].StartsWith(startsWith)) if (sourceLines[j].StartsWith(startsWith))
@ -51,26 +108,30 @@ internal abstract class GenealogicalDataCommunication
if (!sourceLines[j].StartsWith("2 NICK ")) if (!sourceLines[j].StartsWith("2 NICK "))
continue; continue;
nick = sourceLines[j][7..]; nick = sourceLines[j][7..];
if (segments.Length == 3)
idToNick.Add(segments[1], nick);
} }
if (requireNickName && string.IsNullOrEmpty(nick)) if (requireNickName && string.IsNullOrEmpty(nick))
throw new Exception(string.Join(Environment.NewLine, lines)); throw new Exception(string.Join(Environment.NewLine, lines));
nick ??= Guid.NewGuid().ToString(); nick ??= Guid.NewGuid().ToString();
results.Add(nick, new()); keyValuePairs.Add(nick, new());
if (!lines.Any()) if (!lines.Any())
continue; continue;
results[nick].AddRange(lines); keyValuePairs[nick].AddRange(lines);
lines.Clear(); lines.Clear();
} }
else else
throw new NotSupportedException(); 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(); 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")) if (individualsLines[i].StartsWith("0 @I"))
continue; continue;
@ -90,19 +151,19 @@ internal abstract class GenealogicalDataCommunication
continue; continue;
else if (individualsLines[i] == "1 BIRT") 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; i += 1;
continue; continue;
} }
else if (individualsLines[i].StartsWith("1 DEAT")) 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; i += 1;
continue; continue;
} }
else if (individualsLines[i] == "1 CHAN") 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; i += 1;
continue; continue;
} }
@ -116,9 +177,9 @@ internal abstract class GenealogicalDataCommunication
List<string> results = new(); List<string> results = new();
Models.PersonBirthday personBirthday = new(DateTime.Now); Models.PersonBirthday personBirthday = new(DateTime.Now);
GenealogicalDataCommunicationLines genealogicalDataCommunicationLines; 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); results.AddRange(headerLines);
foreach (KeyValuePair<string, List<string>> keyValuePair in individuals) foreach (KeyValuePair<string, string[]> keyValuePair in individuals)
{ {
genealogicalDataCommunicationLines = GetGenealogicalDataCommunicationLines(personBirthday, keyValuePair.Value); genealogicalDataCommunicationLines = GetGenealogicalDataCommunicationLines(personBirthday, keyValuePair.Value);
if (!string.IsNullOrEmpty(genealogicalDataCommunicationLines.Id)) if (!string.IsNullOrEmpty(genealogicalDataCommunicationLines.Id))
@ -139,11 +200,13 @@ internal abstract class GenealogicalDataCommunication
results.AddRange(genealogicalDataCommunicationLines.Death); results.AddRange(genealogicalDataCommunicationLines.Death);
results.AddRange(genealogicalDataCommunicationLines.Changed); results.AddRange(genealogicalDataCommunicationLines.Changed);
} }
for (int i = 0; i < familyGroupLines.Count; i++)
results.AddRange(familyGroupLines[i]);
results.AddRange(footerLines); results.AddRange(footerLines);
return results; return results;
} }
internal static GenealogicalDataCommunicationLines GetGenealogicalDataCommunicationLines(Models.PersonBirthday personBirthday, List<string> individualsLines) internal static GenealogicalDataCommunicationLines GetGenealogicalDataCommunicationLines(Models.PersonBirthday personBirthday, string[] individualsLines)
{ {
GenealogicalDataCommunicationLines result; GenealogicalDataCommunicationLines result;
string? idLine = null; string? idLine = null;
@ -157,7 +220,7 @@ internal abstract class GenealogicalDataCommunication
List<string> birthLines = new(); List<string> birthLines = new();
List<string> deathLines = new(); List<string> deathLines = new();
List<string> changedLines = 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")) if (idLine is null && individualsLines[i].EndsWith("@ INDI"))
idLine = individualsLines[i]; idLine = individualsLines[i];
@ -178,7 +241,7 @@ internal abstract class GenealogicalDataCommunication
else if (!birthLines.Any() && individualsLines[i] == "1 BIRT") else if (!birthLines.Any() && individualsLines[i] == "1 BIRT")
{ {
birthLines.Add(individualsLines[i]); 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; i += 1;
birthLines.Add(individualsLines[i]); birthLines.Add(individualsLines[i]);
@ -187,7 +250,7 @@ internal abstract class GenealogicalDataCommunication
else if (!deathLines.Any() && individualsLines[i].StartsWith("1 DEAT")) else if (!deathLines.Any() && individualsLines[i].StartsWith("1 DEAT"))
{ {
deathLines.Add(individualsLines[i]); 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; i += 1;
deathLines.Add(individualsLines[i]); deathLines.Add(individualsLines[i]);
@ -196,7 +259,7 @@ internal abstract class GenealogicalDataCommunication
else if (!changedLines.Any() && individualsLines[i] == "1 CHAN") else if (!changedLines.Any() && individualsLines[i] == "1 CHAN")
{ {
changedLines.Add(individualsLines[i]); 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; i += 1;
changedLines.Add(individualsLines[i]); changedLines.Add(individualsLines[i]);
@ -259,7 +322,7 @@ internal abstract class GenealogicalDataCommunication
return result; 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) if (verify)
{ {
@ -287,64 +350,65 @@ internal abstract class GenealogicalDataCommunication
_ = Directory.CreateDirectory(directory); _ = Directory.CreateDirectory(directory);
if (first && !personKeyFormatted.EndsWith(code)) if (first && !personKeyFormatted.EndsWith(code))
personKeyFormatted = $"{personKeyFormatted[..^2]}{code}"; personKeyFormatted = $"{personKeyFormatted[..^2]}{code}";
List<string> pGedLines = new(); List<string> lines = new();
if (individualsLines is null || !individualsLines.Any()) if (individualsLines is null || !individualsLines.Any())
pGedLines.Add($"0 @I{personKeyFormatted}@ INDI"); lines.Add($"0 @I{personKeyFormatted}@ INDI");
else else
{ {
if (!individualsLines[0].StartsWith("0 @I")) if (!individualsLines[0].StartsWith("0 @I"))
throw new NotSupportedException(); 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)) 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)) if (!string.IsNullOrEmpty(personName.Last.Value))
pGedLines.Add($"2 SURN {personName.Last.Value}"); lines.Add($"2 SURN {personName.Last.Value}");
if (!string.IsNullOrEmpty(jrOrSr)) if (!string.IsNullOrEmpty(jrOrSr))
pGedLines.Add($"2 NSFX {jrOrSr.Trim()}"); lines.Add($"2 NSFX {jrOrSr.Trim()}");
pGedLines.Add($"2 NICK {personKeyFormatted}"); lines.Add($"2 NICK {personKeyFormatted}");
pGedLines.Add($"1 SEX {genealogicalDataCommunication.Sex}"); lines.Add($"1 SEX {genealogicalDataCommunication.Sex}");
if (genealogicalDataCommunication.Birth is not null) if (genealogicalDataCommunication.Birth is not null)
{ {
Models.PersonBirthday personBirthday = new(genealogicalDataCommunication.Birth.Value); Models.PersonBirthday personBirthday = new(genealogicalDataCommunication.Birth.Value);
if (!IPersonBirthday.IsCounterPersonBirthday(personBirthday)) if (!IPersonBirthday.IsCounterPersonBirthday(personBirthday))
{ {
pGedLines.Add("1 BIRT"); lines.Add("1 BIRT");
pGedLines.Add($"2 DATE {genealogicalDataCommunication.Birth.Value:dd MMM yyyy}"); lines.Add($"2 DATE {genealogicalDataCommunication.Birth.Value:dd MMM yyyy}");
} }
} }
if (genealogicalDataCommunication.Death is not null) if (genealogicalDataCommunication.Death is not null)
{ {
if (genealogicalDataCommunication?.Death is null || genealogicalDataCommunication.Death == genealogicalDataCommunication.Birth || IPersonBirthday.IsCounterPersonBirthday(new(genealogicalDataCommunication.Death.Value))) 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 else
{ {
pGedLines.Add("1 DEAT"); lines.Add("1 DEAT");
pGedLines.Add($"2 DATE {genealogicalDataCommunication.Death.Value:dd MMM yyyy}"); lines.Add($"2 DATE {genealogicalDataCommunication.Death.Value:dd MMM yyyy}");
} }
} }
if (isDefaultName) if (isDefaultName)
pGedLines.Add("9 NOTE"); lines.Add("9 NOTE");
if (individualsLines is not null) if (individualsLines is not null)
pGedLines.AddRange(GetFilteredOutMapped(individualsLines)); lines.AddRange(GetFilteredOutMapped(individualsLines));
string text = string.Join(Environment.NewLine, pGedLines); string text = string.Join(Environment.NewLine, lines);
_ = IPath.WriteAllText(Path.Combine(directory, $"{personKeyFormatted}.pged"), text, updateDateWhenMatches: false, compareBeforeWrite: true); _ = 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; bool result = false;
string[] matches; string[] mdFiles;
string[] txtFiles;
const int zero = 0; const int zero = 0;
string[] jsonFiles;
string[] pGedFiles; string[] pGedFiles;
string[] pGedLines;
string personKeyFormatted; string personKeyFormatted;
List<string> lines = new(); List<string> lines = new();
List<long> distinct = new(); List<long> distinct = new();
lines.AddRange(genealogicalDataCommunicationHeaderLines); List<string> individualsLines;
Models.PersonBirthday personBirthday; Models.PersonBirthday personBirthday;
string rootDirectory = Path.Combine(a2PeopleContentDirectory, $"{ticks}-Tree"); lines.AddRange(headerLines);
foreach (Models.PersonContainer personContainer in personContainers) foreach (Models.PersonContainer personContainer in personContainers)
{ {
if (personContainer.Key is null || personContainer.Birthdays is null || personContainer.Person is null || !personContainer.Birthdays.Any()) 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); distinct.Add(personContainer.Key.Value);
personBirthday = personContainer.Birthdays[zero]; personBirthday = personContainer.Birthdays[zero];
personKeyFormatted = IPersonBirthday.GetFormatted(personBirthdayFormat, personBirthday); personKeyFormatted = IPersonBirthday.GetFormatted(personBirthdayFormat, personBirthday);
by = IPersonBirthday.IsCounterPersonBirthday(personBirthday) ? resultAllInOne : "People"; mdFiles = (from l in personContainer.DisplayDirectoryAllFiles where l.EndsWith(".md") select l).ToArray();
matches = (from l in personContainer.DisplayDirectoryAllFiles where !string.IsNullOrEmpty(personKeyFormatted) && l.Contains(personKeyFormatted) select l).ToArray(); txtFiles = (from l in personContainer.DisplayDirectoryAllFiles where l.EndsWith(".txt") select l).ToArray();
if (!matches.Any()) jsonFiles = (from l in personContainer.DisplayDirectoryAllFiles where l.EndsWith(".json") select l).ToArray();
continue; pGedFiles = (from l in personContainer.DisplayDirectoryAllFiles where l.EndsWith(".pged") select l).ToArray();
pGedFiles = (from l in matches where l.EndsWith(".pged") select l).ToArray(); foreach (string mdFile in mdFiles)
if (!pGedFiles.Any()) {
continue; if (string.IsNullOrEmpty(personKeyFormatted))
pGedLines = File.ReadAllLines(pGedFiles[0]); continue;
lines.AddRange(pGedLines); if (!mdFile.Contains(personKeyFormatted))
if (!personKeyToIds.ContainsKey(personContainer.Key.Value)) {
lines.Add("1 NOTE"); if (!result)
// segments = personContainer.DisplayDirectoryName.Split(_Configuration.PersonCharacters.ToArray()); result = true;
// if (segments.Length < 2) File.Delete(mdFile);
// directory = Path.Combine(rootDirectory, $"000 {personKeyFormatted} {personContainer.DisplayDirectoryName}"); }
// else }
// directory = Path.Combine(rootDirectory, $"{segments[1].PadLeft(3, '0')} {personKeyFormatted} {personContainer.DisplayDirectoryName}"); foreach (string pGedFile in pGedFiles)
// if (Directory.Exists(directory)) {
// continue; if (string.IsNullOrEmpty(personKeyFormatted))
// _ = Directory.CreateDirectory(directory); 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); 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; namespace View_by_Distance.Shared.Models.Stateless.Methods;
public interface IGenealogicalDataCommunication 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); 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); GenealogicalDataCommunication.WriteFile(personKeyFormatted, personName, individualsLines, isDefaultName, directory, genealogicalDataCommunication, verify, first);
List<string> TestStatic_GetMappedLines(string genealogicalDataCommunicationFile, bool requireNickName) => List<string> TestStatic_GetMappedLines(string genealogicalDataCommunicationFile, bool requireNickName) =>
@ -15,9 +17,9 @@ public interface IGenealogicalDataCommunication
static List<string> GetMappedLines(string genealogicalDataCommunicationFile, bool requireNickName) => static List<string> GetMappedLines(string genealogicalDataCommunicationFile, bool requireNickName) =>
GenealogicalDataCommunication.GetMappedLines(genealogicalDataCommunicationFile, requireNickName); GenealogicalDataCommunication.GetMappedLines(genealogicalDataCommunicationFile, requireNickName);
GenealogicalDataCommunicationLines TestStatic_GetGenealogicalDataCommunicationLines(Models.PersonBirthday personBirthday, List<string> individualsLines) => GenealogicalDataCommunicationLines TestStatic_GetGenealogicalDataCommunicationLines(Models.PersonBirthday personBirthday, string[] individualsLines) =>
GetGenealogicalDataCommunicationLines(individualsLines); GetGenealogicalDataCommunicationLines(individualsLines);
static GenealogicalDataCommunicationLines GetGenealogicalDataCommunicationLines(List<string> individualsLines) => static GenealogicalDataCommunicationLines GetGenealogicalDataCommunicationLines(string[] individualsLines) =>
GenealogicalDataCommunication.GetGenealogicalDataCommunicationLines(new(DateTime.Now), individualsLines); GenealogicalDataCommunication.GetGenealogicalDataCommunicationLines(new(DateTime.Now), individualsLines);
Models.GenealogicalDataCommunication TestStatic_GetGenealogicalDataCommunication(GenealogicalDataCommunicationLines genealogicalDataCommunicationLines) => Models.GenealogicalDataCommunication TestStatic_GetGenealogicalDataCommunication(GenealogicalDataCommunicationLines genealogicalDataCommunicationLines) =>
@ -25,14 +27,14 @@ public interface IGenealogicalDataCommunication
static Models.GenealogicalDataCommunication GetGenealogicalDataCommunication(GenealogicalDataCommunicationLines genealogicalDataCommunicationLines) => static Models.GenealogicalDataCommunication GetGenealogicalDataCommunication(GenealogicalDataCommunicationLines genealogicalDataCommunicationLines) =>
GenealogicalDataCommunication.GetGenealogicalDataCommunication(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); 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); 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) => bool TestStatic_CleanDisplayDirectoryAllFilesAndWriteTicksGed(string mappingDefaultName, string personBirthdayFormat, List<Models.PersonContainer> personContainers, string[] headerLines, List<string[]> familyGroupLines, string[] footerLines, long ticks, string a2PeopleContentDirectory) =>
CreateTree(mappingDefaultName, personBirthdayFormat, resultAllInOne, personContainers, genealogicalDataCommunicationHeaderLines, genealogicalDataCommunicationFooterLines, ticks, a2PeopleContentDirectory, personKeyToIds); CleanDisplayDirectoryAllFilesAndWriteTicksGed(mappingDefaultName, personBirthdayFormat, personContainers, headerLines, familyGroupLines, footerLines, ticks, a2PeopleContentDirectory);
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) => static bool CleanDisplayDirectoryAllFilesAndWriteTicksGed(string mappingDefaultName, string personBirthdayFormat, List<Models.PersonContainer> personContainers, string[] headerLines, List<string[]> familyGroupLines, string[] footerLines, long ticks, string a2PeopleContentDirectory) =>
GenealogicalDataCommunication.CreateTree(mappingDefaultName, personBirthdayFormat, resultAllInOne, personContainers, genealogicalDataCommunicationHeaderLines, genealogicalDataCommunicationFooterLines, ticks, a2PeopleContentDirectory, personKeyToIds); 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; namespace View_by_Distance.Shared.Models.Stateless.Methods;
public interface IPersonContainer 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) => static List<Models.PersonContainer> GetNonSpecificPeopleCollection(string mappingDefaultName, int personBirthdayFirstYear, char[] personCharacters, List<Models.PersonContainer> personContainers, long ticks) =>
PersonContainer.GetNonSpecificPeopleCollection(mappingDefaultName, personBirthdayFirstYear, personCharacters, personContainers, 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); 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); 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) => List<(long?, string)> TestStatic_GetDisplay(string personBirthdayFormat, Models.PersonContainer personContainer) =>
GetDisplay(personBirthdayFormat, personContainer); GetDisplay(personBirthdayFormat, personContainer);
static List<(long?, string)> GetDisplay(string personBirthdayFormat, Models.PersonContainer 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; namespace View_by_Distance.Shared.Models.Stateless.Methods;
internal abstract class PersonContainer internal abstract class PersonContainer
@ -90,17 +93,19 @@ internal abstract class PersonContainer
return results; 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(); List<Models.PersonContainer> results = new();
long personKey; long personKey;
const int zero = 0; const int zero = 0;
Models.Person person; Models.Person person;
string[]? individualsLines;
Models.PersonContainer personContainer; Models.PersonContainer personContainer;
Models.PersonBirthday[] orderedPersonBirthdays; Models.PersonBirthday[] orderedPersonBirthdays;
string[] personDisplayDirectoryAllFiles = GetFiles(facesFileNameExtension, personDisplayDirectory, isDefaultName); string[] personDisplayDirectoryAllFiles = GetFiles(facesFileNameExtension, personDisplayDirectory, isDefaultName);
foreach ((string personKeyFormatted, Models.PersonBirthday personBirthday) in collection) 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(); orderedPersonBirthdays = (from l in collection where !l.PersonKeyFormatted.Contains(numberSign) orderby l.PersonBirthday.Value.Ticks descending select l.PersonBirthday).ToArray();
if (!orderedPersonBirthdays.Any()) if (!orderedPersonBirthdays.Any())
personKey = collection[zero].PersonBirthday.Value.Ticks; personKey = collection[zero].PersonBirthday.Value.Ticks;
@ -111,7 +116,7 @@ internal abstract class PersonContainer
personKey = orderedPersonBirthdays[zero].Value.Ticks; personKey = orderedPersonBirthdays[zero].Value.Ticks;
} }
person = IPerson.GetPerson(mappingDefaultName, personCharacters, personDisplayDirectoryName, personDisplayDirectoryAllFiles, personKey); 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); results.Add(personContainer);
} }
return results; return results;
@ -148,48 +153,7 @@ internal abstract class PersonContainer
return result; 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) private static (List<string?>, List<Models.PersonContainer>) GetPersonContainersGroup(string mappingDefaultName, string personBirthdayFormat, string facesFileNameExtension, char[] personCharacters, ReadOnlyDictionary<string, string[]> individuals, PersonDirectory personDirectory, string[] personDisplayDirectories)
{
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)
{ {
List<Models.PersonContainer> results = new(); List<Models.PersonContainer> results = new();
string? minusOne; string? minusOne;
@ -223,8 +187,7 @@ internal abstract class PersonContainer
continue; continue;
if (collection.Any()) if (collection.Any())
{ {
personContainers = GetPersonContainersCollections(mappingDefaultName, facesFileNameExtension, personCharacters, personDirectory, numberSign, personDisplayDirectory, personDisplayDirectoryName, isDefaultName, approximateYears, collection); personContainers = GetPersonContainersCollections(mappingDefaultName, facesFileNameExtension, personCharacters, individuals, personDirectory, numberSign, personDisplayDirectory, personDisplayDirectoryName, isDefaultName, approximateYears, collection);
MaybeGenealogicalDataCommunicationWriteFile(mappingDefaultName, personBirthdayFormat, individuals, personDirectory, personDisplayDirectoryName, isDefaultName, personContainers);
results.AddRange(personContainers); results.AddRange(personContainers);
} }
else else
@ -237,7 +200,7 @@ internal abstract class PersonContainer
return new(changes, results); 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(); List<Models.PersonContainer> results = new();
string[] segments; string[] segments;
@ -284,7 +247,7 @@ internal abstract class PersonContainer
return new(allChanges, results); 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; List<Models.PersonContainer> results;
const int zero = 0; const int zero = 0;
@ -308,7 +271,7 @@ internal abstract class PersonContainer
return results; 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; List<Models.PersonContainer> results;
string a2PeopleSingletonDirectory = Path.Combine(storage.PeopleRootDirectory, "{}"); string a2PeopleSingletonDirectory = Path.Combine(storage.PeopleRootDirectory, "{}");
@ -391,4 +354,92 @@ internal abstract class PersonContainer
return results; 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) internal static string GetFullName(Models.PersonName personName)
{ {
StringBuilder result = new(); 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); _ = 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); _ = 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); _ = 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(); return result.ToString();
} }

View File

@ -2,6 +2,7 @@ using Microsoft.Extensions.Configuration;
using Microsoft.VisualStudio.TestTools.UnitTesting; using Microsoft.VisualStudio.TestTools.UnitTesting;
using Phares.Shared; using Phares.Shared;
using Serilog; using Serilog;
using System.Collections.ObjectModel;
using System.Diagnostics; using System.Diagnostics;
using System.Reflection; using System.Reflection;
using View_by_Distance.Shared.Models; using View_by_Distance.Shared.Models;
@ -264,7 +265,7 @@ public partial class UnitTestHardCoded
if (Directory.Exists(Path.GetPathRoot(directory)) && Directory.Exists(directory)) if (Directory.Exists(Path.GetPathRoot(directory)) && Directory.Exists(directory))
{ {
List<string> mappedLines; List<string> mappedLines;
Dictionary<string, List<string>> individuals; ReadOnlyDictionary<string, string[]> individuals;
GenealogicalDataCommunication genealogicalDataCommunication; GenealogicalDataCommunication genealogicalDataCommunication;
GenealogicalDataCommunicationLines genealogicalDataCommunicationLines; GenealogicalDataCommunicationLines genealogicalDataCommunicationLines;
List<(bool, string)> genealogicalDataCommunicationFiles = new() List<(bool, string)> genealogicalDataCommunicationFiles = new()
@ -274,18 +275,18 @@ public partial class UnitTestHardCoded
// new(true, Path.Combine(directory, "Code-638160708345114583/638160708345114583.ged")), // new(true, Path.Combine(directory, "Code-638160708345114583/638160708345114583.ged")),
// new(true, Path.Combine(directory, "Code-638160728606500015/638160728606500015.ged")), // new(true, Path.Combine(directory, "Code-638160728606500015/638160728606500015.ged")),
// new(true, Path.Combine(directory, "Code-638160738845419877/638160738845419877.ged")), // new(true, Path.Combine(directory, "Code-638160738845419877/638160738845419877.ged")),
// new(true, Path.Combine(directory, "Code-638160743318283885/638160743318283885.ged")), new(true, Path.Combine(directory, "Code-638160743318283885/638160743318283885.ged")),
new(true, Path.Combine(directory, "Code-638245446208013055/638245446208013055.ged")), // new(true, Path.Combine(directory, "Code-638245446208013055/638245446208013055.ged")),
// new(false, Path.Combine(directory, "Ancestry-Porterfield/Porterfield Family Tree.ged")), // new(false, Path.Combine(directory, "Ancestry-Porterfield/Porterfield Family Tree.ged")),
// new(true, Path.Combine(directory, "Code-638160708345114583/638160708345114583-Export.ged")), // new(true, Path.Combine(directory, "Code-638160708345114583/638160708345114583-Export.ged")),
// new(true, Path.Combine(directory, "Code-638160738845419877/638160738845419877-Export.ged")), // new(true, Path.Combine(directory, "Code-638160738845419877/638160738845419877-Export.ged")),
// new(true, Path.Combine(directory, "Code-638160743318283885/638160743318283885-Export.ged")), // new(true, Path.Combine(directory, "Code-638160743318283885/638160743318283885-Export.ged")),
new(true, Path.Combine(directory, "Code-638245446208013055/638245446208013055-Export.ged")), // new(true, Path.Combine(directory, "Code-638245446208013055/638245446208013055-Export.ged")),
}; };
foreach ((bool requireNickName, string genealogicalDataCommunicationFile) in genealogicalDataCommunicationFiles) foreach ((bool requireNickName, string genealogicalDataCommunicationFile) in genealogicalDataCommunicationFiles)
{ {
(_, individuals, _) = IGenealogicalDataCommunication.GetIndividuals(genealogicalDataCommunicationFile, requireNickName); (_, individuals, _, _, _) = IGenealogicalDataCommunication.GetIndividuals(genealogicalDataCommunicationFile, requireNickName);
foreach (KeyValuePair<string, List<string>> keyValuePair in individuals) foreach (KeyValuePair<string, string[]> keyValuePair in individuals)
{ {
genealogicalDataCommunicationLines = IGenealogicalDataCommunication.GetGenealogicalDataCommunicationLines(keyValuePair.Value); genealogicalDataCommunicationLines = IGenealogicalDataCommunication.GetGenealogicalDataCommunicationLines(keyValuePair.Value);
Assert.IsNotNull(genealogicalDataCommunicationLines.Name); Assert.IsNotNull(genealogicalDataCommunicationLines.Name);
@ -316,7 +317,7 @@ public partial class UnitTestHardCoded
PersonName? personName; PersonName? personName;
string personKeyFormatted; string personKeyFormatted;
bool isDefaultName = false; bool isDefaultName = false;
Dictionary<string, List<string>> individuals; ReadOnlyDictionary<string, string[]> individuals;
GenealogicalDataCommunication genealogicalDataCommunication; GenealogicalDataCommunication genealogicalDataCommunication;
GenealogicalDataCommunicationLines genealogicalDataCommunicationLines; GenealogicalDataCommunicationLines genealogicalDataCommunicationLines;
List<(bool, bool, string)> genealogicalDataCommunicationFiles = new() List<(bool, bool, string)> genealogicalDataCommunicationFiles = new()
@ -326,19 +327,19 @@ public partial class UnitTestHardCoded
// new(true, true, Path.Combine(saveDirectory, "Code-638160708345114583/638160708345114583.ged.cln")), // new(true, true, Path.Combine(saveDirectory, "Code-638160708345114583/638160708345114583.ged.cln")),
// new(true, true, Path.Combine(saveDirectory, "Code-638160728606500015/638160728606500015.ged.cln")), // new(true, true, Path.Combine(saveDirectory, "Code-638160728606500015/638160728606500015.ged.cln")),
// new(true, true, Path.Combine(saveDirectory, "Code-638160738845419877/638160738845419877.ged.cln")), // new(true, true, Path.Combine(saveDirectory, "Code-638160738845419877/638160738845419877.ged.cln")),
// new(true, true, Path.Combine(saveDirectory, "Code-638160743318283885/638160743318283885.ged.cln")), new(true, true, Path.Combine(saveDirectory, "Code-638160743318283885/638160743318283885.ged.cln")),
new(true, true, Path.Combine(saveDirectory, "Code-638245446208013055/638245446208013055.ged.cln")), // new(true, true, Path.Combine(saveDirectory, "Code-638245446208013055/638245446208013055.ged.cln")),
// new(false, false, Path.Combine(saveDirectory, "Ancestry-Porterfield/Porterfield Family Tree.ged.cln")), // new(false, false, Path.Combine(saveDirectory, "Ancestry-Porterfield/Porterfield Family Tree.ged.cln")),
// new(true, true, Path.Combine(saveDirectory, "Code-638160708345114583/638160708345114583-Export.ged.cln")), // new(true, true, Path.Combine(saveDirectory, "Code-638160708345114583/638160708345114583-Export.ged.cln")),
// new(true, true, Path.Combine(saveDirectory, "Code-638160738845419877/638160738845419877-Export.ged.cln")), // new(true, true, Path.Combine(saveDirectory, "Code-638160738845419877/638160738845419877-Export.ged.cln")),
// new(true, true, Path.Combine(saveDirectory, "Code-638160743318283885/638160743318283885-Export.ged.cln")), // new(true, true, Path.Combine(saveDirectory, "Code-638160743318283885/638160743318283885-Export.ged.cln")),
new(true, true, Path.Combine(saveDirectory, "Code-638245446208013055/638245446208013055-Export.ged.cln")), // new(true, true, Path.Combine(saveDirectory, "Code-638245446208013055/638245446208013055-Export.ged.cln")),
}; };
foreach ((bool verify, bool requireNickName, string genealogicalDataCommunicationFile) in genealogicalDataCommunicationFiles) foreach ((bool verify, bool requireNickName, string genealogicalDataCommunicationFile) in genealogicalDataCommunicationFiles)
{ {
fileName = Path.GetFileNameWithoutExtension(genealogicalDataCommunicationFile).Split(' ')[0]; fileName = Path.GetFileNameWithoutExtension(genealogicalDataCommunicationFile).Split(' ')[0];
(_, individuals, _) = IGenealogicalDataCommunication.GetIndividuals(genealogicalDataCommunicationFile, requireNickName); (_, individuals, _, _, _) = IGenealogicalDataCommunication.GetIndividuals(genealogicalDataCommunicationFile, requireNickName);
foreach (KeyValuePair<string, List<string>> keyValuePair in individuals) foreach (KeyValuePair<string, string[]> keyValuePair in individuals)
{ {
genealogicalDataCommunicationLines = IGenealogicalDataCommunication.GetGenealogicalDataCommunicationLines(keyValuePair.Value); genealogicalDataCommunicationLines = IGenealogicalDataCommunication.GetGenealogicalDataCommunicationLines(keyValuePair.Value);
Assert.IsNotNull(genealogicalDataCommunicationLines.Name); Assert.IsNotNull(genealogicalDataCommunicationLines.Name);