443 lines
23 KiB
C#
443 lines
23 KiB
C#
using ShellProgressBar;
|
|
using System.Collections.ObjectModel;
|
|
using View_by_Distance.Shared.Models;
|
|
using View_by_Distance.Shared.Models.Stateless.Methods;
|
|
|
|
namespace View_by_Distance.Map.Models.Stateless;
|
|
|
|
internal abstract class RelationLogic
|
|
{
|
|
|
|
internal record Group(string Key,
|
|
long PersonKey,
|
|
ReadOnlyCollection<LocationContainer> RelationContainersCollection);
|
|
|
|
internal static void SaveMappedRelations(Configuration configuration, Shared.Models.Methods.IDistance distance, string a2PeopleContentDirectory, string eDistanceContentDirectory, long ticks, List<LocationContainer> locationContainers, ReadOnlyDictionary<string, PersonContainer> readOnlyPersonKeyFormattedToPersonContainer, ReadOnlyDictionary<long, List<PersonContainer>> readOnlyPersonKeyToPersonContainerCollection)
|
|
{
|
|
int take;
|
|
string directory;
|
|
bool isCounterPersonYear;
|
|
string personKeyFormatted;
|
|
string? displayDirectoryName;
|
|
Uri uri = new(eDistanceContentDirectory);
|
|
ReadOnlyDictionary<string, string> movedFiles;
|
|
ReadOnlyCollection<RelationContainer> relationContainers;
|
|
ReadOnlyCollection<Group> groups = GetGroups(configuration, locationContainers);
|
|
int totalSeconds = (int)Math.Floor(new TimeSpan(DateTime.Now.Ticks - ticks).TotalSeconds);
|
|
string message = $") Save Mapped Relations - {totalSeconds} total second(s)";
|
|
ProgressBarOptions options = new() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true };
|
|
using ProgressBar progressBar = new(groups.Count, message, options);
|
|
foreach (Group group in groups)
|
|
{
|
|
if (configuration.LocationContainerDistanceTolerance is null)
|
|
break;
|
|
progressBar.Tick();
|
|
if (group.RelationContainersCollection.Count == 0)
|
|
continue;
|
|
take = GetTake(configuration.LocationContainerDistanceTake, group.RelationContainersCollection.Count);
|
|
isCounterPersonYear = IPersonBirthday.IsCounterPersonYear(new DateTime(group.PersonKey).Year);
|
|
personKeyFormatted = IPersonBirthday.GetFormatted(configuration.PersonBirthdayFormat, group.PersonKey);
|
|
displayDirectoryName = GetDisplayDirectoryName(readOnlyPersonKeyToPersonContainerCollection, readOnlyPersonKeyFormattedToPersonContainer, group.PersonKey, personKeyFormatted);
|
|
directory = Path.Combine(a2PeopleContentDirectory, $"{ticks}-{configuration.LocationContainerDistanceTolerance.Value}", personKeyFormatted, group.Key);
|
|
if (!Directory.Exists(directory))
|
|
_ = Directory.CreateDirectory(directory);
|
|
WriteVsCodeFiles(eDistanceContentDirectory, displayDirectoryName, directory);
|
|
relationContainers = distance.GetRelationContainers(configuration.DistanceLimits, configuration.FaceDistancePermyriad, configuration.LocationContainerDistanceTake, configuration.LocationContainerDistanceTolerance.Value, group.RelationContainersCollection);
|
|
movedFiles = GetMoveFiles(configuration, group.Key, take, isCounterPersonYear, displayDirectoryName, relationContainers);
|
|
WriteFile(take, group.PersonKey, isCounterPersonYear, personKeyFormatted, displayDirectoryName, directory, ticks, uri, relationContainers, movedFiles);
|
|
}
|
|
if (string.IsNullOrEmpty(configuration.LocationContainerDebugDirectory))
|
|
_ = IPath.DeleteEmptyDirectories(eDistanceContentDirectory);
|
|
else
|
|
AddDisplayDirectoryNames(configuration, eDistanceContentDirectory, readOnlyPersonKeyFormattedToPersonContainer, readOnlyPersonKeyToPersonContainerCollection, groups);
|
|
}
|
|
|
|
private static ReadOnlyCollection<Group> GetGroups(Configuration configuration, List<LocationContainer> locationContainers)
|
|
{
|
|
List<Group> results = [];
|
|
string key;
|
|
int lastIndex;
|
|
List<int> years = [];
|
|
List<int> indices = [];
|
|
LocationContainer locationContainer;
|
|
List<(int Index, int Year)> sort = [];
|
|
List<LocationContainer> collection = [];
|
|
KeyValuePair<int, List<LocationContainer>> keyValue;
|
|
Dictionary<long, Dictionary<int, List<LocationContainer>>> personKeyTo = GetPersonKeyTo(configuration, locationContainers);
|
|
foreach (KeyValuePair<long, Dictionary<int, List<LocationContainer>>> keyValuePair in personKeyTo)
|
|
{
|
|
sort.Clear();
|
|
years.Clear();
|
|
indices.Clear();
|
|
for (int i = 0; i < keyValuePair.Value.Count; i++)
|
|
sort.Add(new(i, keyValuePair.Value.ElementAt(i).Key));
|
|
if (sort.Count == 0)
|
|
continue;
|
|
foreach ((int index, int _) in sort.OrderBy(l => l.Year))
|
|
indices.Add(index);
|
|
lastIndex = indices[^1];
|
|
foreach (int index in indices)
|
|
{
|
|
keyValue = keyValuePair.Value.ElementAt(index);
|
|
if (keyValue.Value.Count == 0)
|
|
continue;
|
|
years.Add(keyValue.Key);
|
|
collection.AddRange(keyValue.Value);
|
|
if (index != lastIndex && years.Count < 6 && years.Sum() > configuration.LocationContainerDistanceGroupMinimum)
|
|
continue;
|
|
if (years.Count == 1)
|
|
key = keyValue.Key.ToString();
|
|
else
|
|
key = $"{years.Min()}-{keyValue.Key}";
|
|
if (collection.Count == 0)
|
|
continue;
|
|
locationContainer = collection[0];
|
|
if (locationContainer.PersonKey is null)
|
|
continue;
|
|
results.Add(new(key, locationContainer.PersonKey.Value, collection.AsReadOnly()));
|
|
collection = [];
|
|
years.Clear();
|
|
}
|
|
}
|
|
return results.AsReadOnly();
|
|
}
|
|
|
|
private static Dictionary<long, Dictionary<int, List<LocationContainer>>> GetPersonKeyTo(Configuration configuration, List<LocationContainer> locationContainers)
|
|
{
|
|
List<LocationContainer>? collection;
|
|
Dictionary<int, List<LocationContainer>>? yearTo;
|
|
Dictionary<long, Dictionary<int, List<LocationContainer>>> personKeyTo = [];
|
|
foreach (LocationContainer locationContainer in locationContainers)
|
|
{
|
|
if (locationContainer.PersonKey is null)
|
|
continue;
|
|
if (!locationContainer.FromDistanceContent)
|
|
continue;
|
|
if (!locationContainer.FilePath.FullName.Contains(configuration.LocationContainerDirectoryPattern))
|
|
continue;
|
|
if (!personKeyTo.TryGetValue(locationContainer.PersonKey.Value, out yearTo))
|
|
{
|
|
personKeyTo.Add(locationContainer.PersonKey.Value, []);
|
|
if (!personKeyTo.TryGetValue(locationContainer.PersonKey.Value, out yearTo))
|
|
throw new Exception();
|
|
}
|
|
if (!yearTo.TryGetValue(locationContainer.CreationDateOnly.Year, out collection))
|
|
{
|
|
yearTo.Add(locationContainer.CreationDateOnly.Year, []);
|
|
if (!yearTo.TryGetValue(locationContainer.CreationDateOnly.Year, out collection))
|
|
throw new Exception();
|
|
}
|
|
collection.Add(locationContainer);
|
|
}
|
|
return personKeyTo;
|
|
}
|
|
|
|
private static int GetTake(int locationContainerDistanceTake, int count)
|
|
{
|
|
int result = locationContainerDistanceTake;
|
|
int subtract = (int)(locationContainerDistanceTake * .05);
|
|
if (subtract < 1)
|
|
subtract = 1;
|
|
if (count > 9000)
|
|
result -= subtract;
|
|
if (count > 8000)
|
|
result -= subtract;
|
|
if (count > 7000)
|
|
result -= subtract;
|
|
if (count > 6000)
|
|
result -= subtract;
|
|
if (count > 5000)
|
|
result -= subtract;
|
|
if (count > 4000)
|
|
result -= subtract;
|
|
if (count > 3000)
|
|
result -= subtract;
|
|
if (count > 2000)
|
|
result -= subtract;
|
|
if (count > 1000)
|
|
result -= subtract;
|
|
if (result < 3)
|
|
result = 3;
|
|
return result;
|
|
}
|
|
|
|
private static string? GetDisplayDirectoryName(ReadOnlyDictionary<long, List<PersonContainer>> readOnlyPersonKeyToPersonContainerCollection, ReadOnlyDictionary<string, PersonContainer> readOnlyPersonKeyFormattedToPersonContainer, long personKey, string personKeyFormatted)
|
|
{
|
|
string? result;
|
|
PersonContainer? personContainer;
|
|
List<PersonContainer>? collection;
|
|
_ = readOnlyPersonKeyToPersonContainerCollection.TryGetValue(personKey, out collection);
|
|
if (collection is not null)
|
|
result = collection[0].DisplayDirectoryName;
|
|
else
|
|
{
|
|
if (!readOnlyPersonKeyFormattedToPersonContainer.TryGetValue(personKeyFormatted, out personContainer))
|
|
result = null;
|
|
else
|
|
result = personContainer.DisplayDirectoryName;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private static void WriteVsCodeFiles(string eDistanceContentDirectory, string? displayDirectoryName, string directory)
|
|
{
|
|
string json;
|
|
string vsCodeDirectory = Path.Combine(directory, ".vscode");
|
|
if (!Directory.Exists(vsCodeDirectory))
|
|
_ = Directory.CreateDirectory(vsCodeDirectory);
|
|
if (displayDirectoryName is not null)
|
|
File.WriteAllText(Path.Combine(directory, $"_ {displayDirectoryName}.txt"), string.Empty);
|
|
json = /*lang=json*/ """{ "[markdown]": { "editor.wordWrap": "off" }, "foam.links.hover.enable": false, "foam.graph.style": { "background": "#202020", "node": { "note": "#f2cb1d", "distance": "green", "image": "orange", "placeholder": "white", } } }""";
|
|
_ = IPath.WriteAllText(Path.Combine(vsCodeDirectory, "settings.json"), json, updateDateWhenMatches: false, compareBeforeWrite: true, updateToWhenMatches: null);
|
|
json = string.Concat("{ \"version\": \"2.0.0\", \"tasks\": [ { \"label\": \"MKLink\", \"type\": \"shell\", \"command\": \"New-Item\", \"args\": [ \"-ItemType\", \"Junction\", \"-Path\", \"'", directory.Replace('\\', '/'), "/()'\", \"-Target\", \"'", eDistanceContentDirectory.Replace('\\', '/'), "'\" ], \"problemMatcher\": [] } ] }");
|
|
_ = IPath.WriteAllText(Path.Combine(vsCodeDirectory, "tasks.json"), json, updateDateWhenMatches: false, compareBeforeWrite: true, updateToWhenMatches: null);
|
|
}
|
|
|
|
private static ReadOnlyDictionary<string, string> GetMoveFiles(Configuration configuration, string key, int take, bool isCounterPersonYear, string? displayDirectoryName, ReadOnlyCollection<RelationContainer> relationContainers)
|
|
{
|
|
ReadOnlyDictionary<string, string> results;
|
|
List<List<string>> linked = [];
|
|
for (int i = 0; i < 25; i++)
|
|
linked.Add([]);
|
|
foreach ((FileHolder fileHolder, ReadOnlyCollection<Relation> relations) in relationContainers)
|
|
{
|
|
foreach (Relation relation in relations.Take(take))
|
|
{
|
|
for (int i = 0; i < 25; i++)
|
|
{
|
|
if (!linked[i].Contains(relation.File))
|
|
{
|
|
linked[i].Add(relation.File);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
results = MoveFiles(configuration, key, isCounterPersonYear, displayDirectoryName, relationContainers, linked);
|
|
return results;
|
|
}
|
|
|
|
private static ReadOnlyDictionary<string, string> MoveFiles(Configuration configuration, string key, bool isCounterPersonYear, string? displayDirectoryName, ReadOnlyCollection<RelationContainer> relationContainers, List<List<string>> linked)
|
|
{
|
|
Dictionary<string, string> results = [];
|
|
string value;
|
|
string checkFile;
|
|
string debugFile;
|
|
string checkDirectory;
|
|
string? yearDirectory;
|
|
string? personNameDirectory;
|
|
string? maybeTicksDirectoryName;
|
|
string? personNameDirectoryName;
|
|
string? personKeyFormattedDirectory;
|
|
foreach ((FileHolder fileHolder, _) in relationContainers)
|
|
{
|
|
personNameDirectory = fileHolder.DirectoryFullPath;
|
|
yearDirectory = Path.GetDirectoryName(personNameDirectory);
|
|
personNameDirectoryName = Path.GetFileName(personNameDirectory);
|
|
personKeyFormattedDirectory = Path.GetDirectoryName(yearDirectory);
|
|
maybeTicksDirectoryName = Path.GetFileName(personKeyFormattedDirectory);
|
|
if (string.IsNullOrEmpty(personNameDirectory) || string.IsNullOrEmpty(yearDirectory) || string.IsNullOrEmpty(personKeyFormattedDirectory) || string.IsNullOrEmpty(personNameDirectoryName))
|
|
continue;
|
|
if (linked[24].Contains(fileHolder.FullName))
|
|
value = "ZZZ";
|
|
else if (linked[23].Contains(fileHolder.FullName))
|
|
value = "YYY";
|
|
else if (linked[22].Contains(fileHolder.FullName))
|
|
value = "XXX";
|
|
else if (linked[21].Contains(fileHolder.FullName))
|
|
value = "WWW";
|
|
else if (linked[20].Contains(fileHolder.FullName))
|
|
value = "VVV";
|
|
else if (linked[19].Contains(fileHolder.FullName))
|
|
value = "UUU";
|
|
else if (linked[18].Contains(fileHolder.FullName))
|
|
value = "TTT";
|
|
else if (linked[17].Contains(fileHolder.FullName))
|
|
value = "SSS";
|
|
else if (linked[16].Contains(fileHolder.FullName))
|
|
value = "RRR";
|
|
else if (linked[15].Contains(fileHolder.FullName))
|
|
value = "QQQ";
|
|
else if (linked[14].Contains(fileHolder.FullName))
|
|
value = "PPP";
|
|
else if (linked[13].Contains(fileHolder.FullName))
|
|
value = "OOO";
|
|
else if (linked[12].Contains(fileHolder.FullName))
|
|
value = "NNN";
|
|
else if (linked[11].Contains(fileHolder.FullName))
|
|
value = "MMM";
|
|
else if (linked[10].Contains(fileHolder.FullName))
|
|
value = "LLL";
|
|
else if (linked[9].Contains(fileHolder.FullName))
|
|
value = "KKK";
|
|
else if (linked[8].Contains(fileHolder.FullName))
|
|
value = "JJJ";
|
|
else if (linked[7].Contains(fileHolder.FullName))
|
|
value = "III";
|
|
else if (linked[6].Contains(fileHolder.FullName))
|
|
value = "HHH";
|
|
else if (linked[5].Contains(fileHolder.FullName))
|
|
value = "GGG";
|
|
else if (linked[4].Contains(fileHolder.FullName))
|
|
value = "FFF";
|
|
else if (linked[3].Contains(fileHolder.FullName))
|
|
value = "EEE";
|
|
else if (linked[2].Contains(fileHolder.FullName))
|
|
value = "DDD";
|
|
else if (linked[1].Contains(fileHolder.FullName))
|
|
value = "CCC";
|
|
else if (linked[0].Contains(fileHolder.FullName))
|
|
value = "BBB";
|
|
else
|
|
value = "AAA";
|
|
if (maybeTicksDirectoryName == configuration.LocationContainerDebugDirectory)
|
|
checkDirectory = Path.Combine(yearDirectory, $"{key}-{value}");
|
|
else
|
|
{
|
|
if (!string.IsNullOrEmpty(configuration.LocationContainerDebugDirectory))
|
|
continue;
|
|
checkDirectory = Path.Combine(personKeyFormattedDirectory, $"{key}-{value}");
|
|
}
|
|
if (maybeTicksDirectoryName != configuration.LocationContainerDebugDirectory)
|
|
{
|
|
if (isCounterPersonYear || string.IsNullOrEmpty(displayDirectoryName))
|
|
checkDirectory = Path.Combine(checkDirectory, personNameDirectoryName);
|
|
else
|
|
checkDirectory = Path.Combine(checkDirectory, displayDirectoryName[0].ToString());
|
|
}
|
|
if (checkDirectory == personNameDirectory)
|
|
continue;
|
|
if (!Directory.Exists(checkDirectory))
|
|
_ = Directory.CreateDirectory(checkDirectory);
|
|
checkFile = Path.Combine(checkDirectory, fileHolder.Name);
|
|
if (File.Exists(checkFile))
|
|
continue;
|
|
results.Add(fileHolder.FullName, checkFile);
|
|
File.Move(fileHolder.FullName, checkFile);
|
|
debugFile = $"{fileHolder.FullName[..^4]}.gif";
|
|
if (File.Exists(debugFile))
|
|
{
|
|
checkFile = Path.Combine(checkDirectory, $"{Path.GetFileName(fileHolder.FullName)[..^4]}.gif");
|
|
if (File.Exists(checkFile))
|
|
continue;
|
|
File.Move(debugFile, checkFile);
|
|
}
|
|
if (maybeTicksDirectoryName == configuration.LocationContainerDebugDirectory && !string.IsNullOrEmpty(displayDirectoryName))
|
|
{
|
|
checkDirectory = Path.Combine(checkDirectory, displayDirectoryName);
|
|
if (!Directory.Exists(checkDirectory))
|
|
_ = Directory.CreateDirectory(checkDirectory);
|
|
}
|
|
}
|
|
return results.AsReadOnly();
|
|
}
|
|
|
|
private static void WriteFile(int take, long personKey, bool isCounterPersonYear, string personKeyFormatted, string? displayDirectoryName, string directory, long ticks, Uri uri, ReadOnlyCollection<RelationContainer> relationContainers, ReadOnlyDictionary<string, string> movedFiles)
|
|
{
|
|
string a;
|
|
string b;
|
|
int years;
|
|
string text;
|
|
string? file;
|
|
Relation relation;
|
|
string markDownFile;
|
|
FileHolder fileHolder;
|
|
string originalString;
|
|
List<string> lines = [];
|
|
string fileNameWithoutExtension;
|
|
foreach ((FileHolder relationFileHolder, ReadOnlyCollection<Relation> relations) in relationContainers)
|
|
{
|
|
lines.Clear();
|
|
if (movedFiles.TryGetValue(relationFileHolder.FullName, out file))
|
|
fileHolder = IFileHolder.Get(file);
|
|
else
|
|
fileHolder = IFileHolder.Get(relationFileHolder.FullName);
|
|
if (!relationFileHolder.Exists || relationFileHolder.CreationTime is null)
|
|
continue;
|
|
if (isCounterPersonYear)
|
|
(years, _) = IAge.GetAge(ticks, relationFileHolder.CreationTime.Value.Ticks);
|
|
else
|
|
(years, _) = IAge.GetAge(relationFileHolder.CreationTime.Value.Ticks, personKey);
|
|
fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fileHolder.NameWithoutExtension);
|
|
markDownFile = $"{fileNameWithoutExtension}.md";
|
|
lines.Add("---");
|
|
lines.Add("type: \"distance\"");
|
|
lines.Add("---");
|
|
lines.Add(string.Empty);
|
|
if (displayDirectoryName is null)
|
|
lines.Add($"## {personKeyFormatted}");
|
|
else
|
|
lines.Add($"## {displayDirectoryName}");
|
|
lines.Add(string.Empty);
|
|
lines.Add($").OriginalString})");
|
|
lines.Add($"- __{fileNameWithoutExtension}__");
|
|
if (isCounterPersonYear)
|
|
lines.Add($"- #{years}yrs-ago");
|
|
else
|
|
lines.Add($"- #{years}yrs-old");
|
|
lines.Add($"- ~~{relations.Count}~~");
|
|
lines.Add(string.Empty);
|
|
for (int i = 0; i < relations.Count; i++)
|
|
{
|
|
relation = relations[i];
|
|
if (movedFiles.TryGetValue(relation.File, out file))
|
|
fileHolder = IFileHolder.Get(file);
|
|
else
|
|
fileHolder = IFileHolder.Get(relation.File);
|
|
if (!fileHolder.Exists || fileHolder.CreationTime is null)
|
|
continue;
|
|
fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fileHolder.NameWithoutExtension);
|
|
originalString = uri.MakeRelativeUri(new(fileHolder.FullName)).OriginalString;
|
|
if (i < take)
|
|
(a, b) = ("[[", "]]");
|
|
else
|
|
(a, b) = ("~~", "~~");
|
|
lines.Add($"{Environment.NewLine}{a}{fileNameWithoutExtension}{b}");
|
|
lines.Add(string.Empty);
|
|
}
|
|
lines.Add("<style>");
|
|
lines.Add("img {");
|
|
lines.Add("min-width: 75px;");
|
|
lines.Add("max-width: 75px;");
|
|
lines.Add("display: block;");
|
|
lines.Add("}");
|
|
lines.Add("</style>");
|
|
text = string.Join(Environment.NewLine, lines);
|
|
File.WriteAllText(Path.Combine(directory, markDownFile), text);
|
|
}
|
|
}
|
|
|
|
private static void AddDisplayDirectoryNames(Configuration configuration, string eDistanceContentDirectory, ReadOnlyDictionary<string, PersonContainer> readOnlyPersonKeyFormattedToPersonContainer, ReadOnlyDictionary<long, List<PersonContainer>> readOnlyPersonKeyToPersonContainerCollection, ReadOnlyCollection<Group> groups)
|
|
{
|
|
bool isCounterPersonYear;
|
|
string personKeyFormatted;
|
|
string? displayDirectoryName;
|
|
string? checkDirectory = Path.Combine(eDistanceContentDirectory, configuration.LocationContainerDebugDirectory);
|
|
_ = IPath.DeleteEmptyDirectories(checkDirectory);
|
|
foreach (Group group in groups)
|
|
{
|
|
if (configuration.LocationContainerDistanceTolerance is null)
|
|
break;
|
|
isCounterPersonYear = IPersonBirthday.IsCounterPersonYear(new DateTime(group.PersonKey).Year);
|
|
if (isCounterPersonYear)
|
|
continue;
|
|
personKeyFormatted = IPersonBirthday.GetFormatted(configuration.PersonBirthdayFormat, group.PersonKey);
|
|
checkDirectory = Path.Combine(eDistanceContentDirectory, configuration.LocationContainerDebugDirectory, personKeyFormatted);
|
|
if (!Directory.Exists(checkDirectory))
|
|
continue;
|
|
displayDirectoryName = GetDisplayDirectoryName(readOnlyPersonKeyToPersonContainerCollection, readOnlyPersonKeyFormattedToPersonContainer, group.PersonKey, personKeyFormatted);
|
|
if (string.IsNullOrEmpty(displayDirectoryName))
|
|
continue;
|
|
foreach (string yearDirectory in Directory.GetDirectories(checkDirectory, "*", SearchOption.TopDirectoryOnly))
|
|
{
|
|
checkDirectory = Path.Combine(yearDirectory, displayDirectoryName);
|
|
if (!Directory.Exists(checkDirectory))
|
|
_ = Directory.CreateDirectory(checkDirectory);
|
|
}
|
|
checkDirectory = Path.Combine(eDistanceContentDirectory, configuration.LocationContainerDebugDirectory, personKeyFormatted, displayDirectoryName);
|
|
if (!Directory.Exists(checkDirectory))
|
|
_ = Directory.CreateDirectory(checkDirectory);
|
|
}
|
|
}
|
|
|
|
} |