using System.Text.Json.Serialization; using View_by_Distance.Shared.Models; using View_by_Distance.Shared.Models.Properties; namespace View_by_Distance.Property.Models; public class Item { protected readonly bool? _Abandoned; protected readonly bool? _Changed; protected List _Closest; protected List _Faces; protected readonly FileHolder? _ImageFileHolder; protected bool? _Moved; protected List _Named; protected readonly bool? _NoJson; protected A_Property? _Property; protected readonly string _RelativePath; protected FileHolder? _ResizedFileHolder; protected readonly string _SourceDirectoryFile; protected bool _ValidImageFormatExtension; public bool? Abandoned => _Abandoned; public bool? Changed => _Changed; public List Closest => _Closest; public List Faces => _Faces; public FileHolder? ImageFileHolder => _ImageFileHolder; public bool? Moved => _Moved; public bool? NoJson => _NoJson; public List Named => _Named; public A_Property? Property => _Property; public string RelativePath => _RelativePath; public FileHolder? ResizedFileHolder => _ResizedFileHolder; public string SourceDirectoryFile => _SourceDirectoryFile; public bool ValidImageFormatExtension => _ValidImageFormatExtension; [JsonConstructor] public Item(bool? abandoned, bool? changed, List closest, List faces, FileHolder? imageFileHolder, bool? moved, List named, bool? noJson, A_Property? property, string relativePath, FileHolder? resizedFileHolder, string sourceDirectoryFile, bool validImageFormatExtension) { _Abandoned = abandoned; _Changed = changed; _Closest = closest; _Faces = faces; _ImageFileHolder = imageFileHolder; _Moved = moved; _Named = named; _NoJson = noJson; _Property = property; _RelativePath = relativePath; _ResizedFileHolder = resizedFileHolder; _SourceDirectoryFile = sourceDirectoryFile; _ValidImageFormatExtension = validImageFormatExtension; } public Item(string sourceDirectoryFile, string relativePath, FileHolder? imageFileInfo, bool isValidImageFormatExtension, A_Property? property, bool? abandoned, bool? changed) { _Faces = new(); _Named = new(); _Closest = new(); _Changed = changed; _Property = property; _Abandoned = abandoned; _NoJson = abandoned is null; _RelativePath = relativePath; _ImageFileHolder = imageFileInfo; _SourceDirectoryFile = sourceDirectoryFile; _ValidImageFormatExtension = isValidImageFormatExtension; if (relativePath.EndsWith(".json")) throw new ArgumentException("Can not be a *.json file!"); if (imageFileInfo is not null && imageFileInfo.ExtensionLowered is ".json") throw new ArgumentException("Can not be a *.json file!"); } internal void SetMoved(bool moved) => _Moved = moved; public static string GetWrongYearFlag(bool? isWrongYear) => isWrongYear is null ? "#" : isWrongYear.Value ? "~" : "="; public void SetResizedFileHolder(FileHolder fileHolder) => _ResizedFileHolder = fileHolder; public bool Any() => (_Abandoned.HasValue && _Abandoned.Value) || (_Changed.HasValue && _Changed.Value) || (_Moved.HasValue && _Moved.Value) || (_NoJson.HasValue && _NoJson.Value); public void Update(A_Property property) => _Property = property; public (bool?, string[]) IsWrongYear() { (bool?, string[]) result; if (_Property is null || _ImageFileHolder is null) throw new NullReferenceException(); DateTime? minimumDateTime = Stateless.A_Property.GetMinimumDateTime(_Property); result = _Property.IsWrongYear(_ImageFileHolder.FullName, minimumDateTime); return result; } public static void AddToNamed(PropertyLogic propertyLogic, List items) { bool? isWrongYear; DateTime minimumDateTime; PersonBirthday? personBirthday; float deterministicHashCodeKey; List personKeys = new(); foreach (Item item in items) { if (item.ImageFileHolder is null) continue; if (item.Property?.Id is null || item.ResizedFileHolder is null) continue; foreach (IFace face in item.Faces) { personKeys.Clear(); if (face.LocationIndex is null) continue; deterministicHashCodeKey = Models.Named.GetDeterministicHashCodeKey(item, face); if (!propertyLogic.NamedDeterministicHashCodeKeyValuePairs.ContainsKey(deterministicHashCodeKey)) continue; minimumDateTime = Stateless.A_Property.GetMinimumDateTime(item.Property); personKeys.AddRange(propertyLogic.NamedDeterministicHashCodeKeyValuePairs[deterministicHashCodeKey]); (isWrongYear, _) = item.Property.IsWrongYear(item.ImageFileHolder.FullName, minimumDateTime); for (int i = 0; i < personKeys.Count; i++) { personBirthday = Shared.Models.Stateless.Methods.IPersonBirthday.GetPersonBirthday(personKeys[i]); if (personBirthday is null) continue; item.Named.Add(new(isWrongYear, minimumDateTime, face.Location.NormalizedPixelPercentage, personBirthday)); } } if (!personKeys.Any()) { if (!propertyLogic.NamedFaceInfoDeterministicHashCodeKeyValuePairs.ContainsKey(item.Property.Id.Value)) continue; minimumDateTime = Stateless.A_Property.GetMinimumDateTime(item.Property); personKeys.AddRange(propertyLogic.NamedFaceInfoDeterministicHashCodeKeyValuePairs[item.Property.Id.Value]); (isWrongYear, _) = item.Property.IsWrongYear(item.ImageFileHolder.FullName, minimumDateTime); for (int i = 0; i < personKeys.Count; i++) { personBirthday = Shared.Models.Stateless.Methods.IPersonBirthday.GetPersonBirthday(personKeys[i]); if (personBirthday is null) continue; item.Named.Add(new(isWrongYear, minimumDateTime, personBirthday)); } } } } public static List<(Item, (string, IFace?, (string, string, string, string))[])> GetCollection(PropertyLogic propertyLogic, List items, string dFacesContentDirectory) { List<(Item, (string, IFace?, (string, string, string, string))[])> results = new(); Item item; string[] keys; string directory; string personKey; bool? isWrongYear; const int zero = 0; TimeSpan? timeSpan; string copyFileName; string copyDirectory; string? relativePath; string isWrongYearFlag; string shortcutFileName; string subDirectoryName; List indices = new(); DateTime? minimumDateTime; List faceCollection; PersonBirthday? personBirthday; List<(string, IFace?, (string, string, string, string))> collection; for (int i = 0; i < items.Count; i++) { indices.Clear(); copyFileName = string.Empty; copyDirectory = string.Empty; item = items[i]; if (item.ImageFileHolder is null) continue; relativePath = Path.GetDirectoryName($"C:{item.RelativePath}"); if (string.IsNullOrEmpty(relativePath) || relativePath.Length < 3) continue; if (item.Property?.Id is null || item.ResizedFileHolder is null) continue; collection = new(); if (!propertyLogic.NamedFaceInfoDeterministicHashCodeKeyValuePairs.ContainsKey(item.Property.Id.Value)) { faceCollection = new(); personKey = string.Empty; directory = Path.Combine(dFacesContentDirectory, $"Unnamed{relativePath[2..]}"); } else { faceCollection = item.Faces; keys = propertyLogic.NamedFaceInfoDeterministicHashCodeKeyValuePairs[item.Property.Id.Value]; minimumDateTime = Stateless.A_Property.GetMinimumDateTime(item.Property); if (minimumDateTime is null) continue; (isWrongYear, _) = item.Property.IsWrongYear(item.ImageFileHolder.FullName, minimumDateTime.Value); isWrongYearFlag = GetWrongYearFlag(isWrongYear); subDirectoryName = $"{isWrongYearFlag}{minimumDateTime.Value:yyyy}"; if (!faceCollection.Any()) { personKey = string.Empty; directory = Path.Combine(dFacesContentDirectory, $"None{relativePath[2..]}", subDirectoryName); } else if (keys.Length != 1) { personKey = string.Empty; directory = Path.Combine(dFacesContentDirectory, $"Not Supported{relativePath[2..]}", subDirectoryName); } else if (faceCollection.Count != 1) { personKey = string.Empty; directory = Path.Combine(dFacesContentDirectory, $"Many{relativePath[2..]}", subDirectoryName); } else { indices.Add(zero); personKey = keys[zero]; personBirthday = Shared.Models.Stateless.Methods.IPersonBirthday.GetPersonBirthday(personKey); if (personBirthday is null) continue; timeSpan = Shared.Models.Stateless.Methods.IPersonBirthday.GetTimeSpan(minimumDateTime.Value, isWrongYear, personBirthday); if (timeSpan.HasValue) { if (timeSpan.Value.Ticks < 0) subDirectoryName = "!---"; else subDirectoryName = $"^{Math.Floor(timeSpan.Value.TotalDays / 365):000}"; } directory = Path.Combine(dFacesContentDirectory, "Shortcuts", personKey, subDirectoryName); if (faceCollection[zero].Populated) copyDirectory = Path.Combine(dFacesContentDirectory, "Images", personKey, subDirectoryName); else copyDirectory = Path.Combine(dFacesContentDirectory, "ImagesBut", personKey, subDirectoryName); copyFileName = Path.Combine(copyDirectory, $"{item.Property.Id.Value}{item.ResizedFileHolder.ExtensionLowered}"); } } shortcutFileName = Path.Combine(directory, $"{item.Property.Id.Value}.lnk"); if (string.IsNullOrEmpty(personKey) || !indices.Any()) collection.Add(new(personKey, null, (directory, copyDirectory, copyFileName, shortcutFileName))); else { foreach (int index in indices) collection.Add(new(personKey, faceCollection[index], (directory, copyDirectory, copyFileName, shortcutFileName))); } results.Add(new(item, collection.ToArray())); } return results; } public static string GetKey(DateTime minimumDateTime, bool? isWrongYear, PersonBirthday personBirthday) { string result; string personKey = Shared.Models.Stateless.Methods.IPersonBirthday.GetFormatted(personBirthday); TimeSpan? timeSpan = Shared.Models.Stateless.Methods.IPersonBirthday.GetTimeSpan(minimumDateTime, isWrongYear, personBirthday); if (timeSpan.HasValue && timeSpan.Value.Ticks < 0) result = string.Concat(personKey, "!---"); else if (timeSpan.HasValue) result = string.Concat(personKey, $"^{Math.Floor(timeSpan.Value.TotalDays / 365):000}"); else { string isWrongYearFlag = GetWrongYearFlag(isWrongYear); result = string.Concat(personKey, $"{isWrongYearFlag}{minimumDateTime:yyyy}"); } return result; } public static string GetDirectory(string directory, string subDirectory, DateTime minimumDateTime, bool? isWrongYear, PersonBirthday personBirthday, string personKey) { string result; TimeSpan? timeSpan = Shared.Models.Stateless.Methods.IPersonBirthday.GetTimeSpan(minimumDateTime, isWrongYear, personBirthday); if (timeSpan.HasValue && timeSpan.Value.Ticks < 0) result = Path.Combine(directory, subDirectory, personKey, "!---"); else if (timeSpan.HasValue) result = Path.Combine(directory, subDirectory, personKey, $"^{Math.Floor(timeSpan.Value.TotalDays / 365):000}"); else { string isWrongYearFlag = GetWrongYearFlag(isWrongYear); result = Path.Combine(directory, subDirectory, personKey, $"{isWrongYearFlag}{minimumDateTime:yyyy}"); } return result; } public static Dictionary> GetKeyValuePairs(string argZero, List containers) { Dictionary> results = new(); string key; foreach (Container container in containers) { if (!container.Items.Any()) continue; if (!container.SourceDirectory.StartsWith(argZero)) continue; foreach (Item item in container.Items) { if (item.ImageFileHolder is null || item.Property is null || !item.Named.Any()) continue; foreach (Named named in item.Named) { if (named.NormalizedPixelPercentage is null && (item.Named.Count != 1 || item.Faces.Count != 1)) continue; foreach (IFace face in item.Faces) { if (!face.Populated) continue; if (named.PersonBirthday is null) continue; if (named.NormalizedPixelPercentage.HasValue && named.NormalizedPixelPercentage.Value != face.Location.NormalizedPixelPercentage) continue; key = GetKey(named.MinimumDateTime, named.IsWrongYear, named.PersonBirthday); if (!results.ContainsKey(key)) results.Add(key, new()); results[key].Add(new(named.MinimumDateTime, named.IsWrongYear, named.PersonBirthday, face)); if (named.NormalizedPixelPercentage is null) break; } } } } return results; } }