using System.Diagnostics.CodeAnalysis; using System.Text.Json; using System.Text.Json.Nodes; using Artemis.Core; using Artemis.Storage.Entities.Workshop; namespace Artemis.WebClient.Workshop.Models; public class InstalledEntry : CorePropertyChanged, IEntrySummary { private Dictionary _metadata = new(); private long _id; private string _author; private bool _isOfficial; private string _name; private string _summary; private EntryType _entryType; private long _downloads; private DateTimeOffset _createdAt; private long? _latestReleaseId; private IReadOnlyList _categories; private long _releaseId; private string _releaseVersion = string.Empty; private bool _autoUpdate; internal InstalledEntry(EntryEntity entity) { Entity = entity; Load(); } public InstalledEntry(IEntrySummary entry, IRelease release) { Entity = new EntryEntity(); ApplyEntrySummary(entry); InstalledAt = DateTimeOffset.Now; ReleaseId = release.Id; ReleaseVersion = release.Version; AutoUpdate = true; } internal EntryEntity Entity { get; } public DateTimeOffset InstalledAt { get; set; } public long ReleaseId { get => _releaseId; set => SetAndNotify(ref _releaseId, value); } public string ReleaseVersion { get => _releaseVersion; set => SetAndNotify(ref _releaseVersion, value); } public bool AutoUpdate { get => _autoUpdate; set => SetAndNotify(ref _autoUpdate, value); } internal void Load() { Id = Entity.EntryId; Author = Entity.Author; IsOfficial = Entity.IsOfficial; Name = Entity.Name; Summary = Entity.Summary; EntryType = (EntryType) Entity.EntryType; Downloads = Entity.Downloads; CreatedAt = Entity.CreatedAt; LatestReleaseId = Entity.LatestReleaseId; Categories = Entity.Categories?.Select(c => new GetDependantEntries_Entries_Items_Categories_Category(c.Name, c.Icon)).ToList() ?? []; ReleaseId = Entity.ReleaseId; ReleaseVersion = Entity.ReleaseVersion; InstalledAt = Entity.InstalledAt; AutoUpdate = Entity.AutoUpdate; _metadata = Entity.Metadata != null ? new Dictionary(Entity.Metadata) : []; } internal void Save() { Entity.EntryId = Id; Entity.EntryType = (int) EntryType; Entity.Author = Author; Entity.IsOfficial = IsOfficial; Entity.Name = Name; Entity.Summary = Summary; Entity.Downloads = Downloads; Entity.CreatedAt = CreatedAt; Entity.LatestReleaseId = LatestReleaseId; Entity.Categories = Categories.Select(c => new EntryCategoryEntity(c.Name, c.Icon)).ToList(); Entity.ReleaseId = ReleaseId; Entity.ReleaseVersion = ReleaseVersion; Entity.InstalledAt = InstalledAt; Entity.AutoUpdate = AutoUpdate; Entity.Metadata = new Dictionary(_metadata); } /// /// Gets the metadata value associated with the specified key. /// /// The key of the value to get. /// When this method returns, contains the value associated with the specified key, if the key is found and of type ; /// otherwise, the default value for the type of the value parameter. This parameter is passed uninitialized. /// The type of the value. /// if the metadata contains an element with the specified key; otherwise, . public bool TryGetMetadata(string key, [NotNullWhen(true)] out T? value) { if (!_metadata.TryGetValue(key, out JsonNode? element)) { value = default; return false; } value = element.GetValue(); return value != null; } /// /// Sets metadata with the provided key to the provided value. /// /// The key of the value to set /// The value to set. public void SetMetadata(string key, object value) { _metadata[key] = JsonSerializer.SerializeToNode(value) ?? throw new InvalidOperationException(); } /// /// Removes metadata with the provided key. /// /// The key of the metadata to remove /// if the element is successfully found and removed; otherwise, . public bool RemoveMetadata(string key) { return _metadata.Remove(key); } /// /// Returns the directory info of the entry, where any files would be stored if applicable. /// /// The directory info of the directory. public DirectoryInfo GetDirectory() { return new DirectoryInfo(Path.Combine(Constants.WorkshopFolder, $"{Id}-{StringUtilities.UrlFriendly(Name)}")); } /// /// Returns the directory info of a release of this entry, where any files would be stored if applicable. /// /// The release to use, if none provided the current release is used. /// The directory info of the directory. public DirectoryInfo GetReleaseDirectory(IRelease? release = null) { return new DirectoryInfo(Path.Combine(GetDirectory().FullName, StringUtilities.UrlFriendly(release?.Version ?? ReleaseVersion))); } /// /// Applies the provided release to the installed entry. /// /// The release to apply. public void ApplyRelease(IRelease release) { ReleaseId = release.Id; ReleaseVersion = release.Version; InstalledAt = DateTimeOffset.UtcNow; } public void ApplyEntrySummary(IEntrySummary entry) { Id = entry.Id; Author = entry.Author; IsOfficial = entry.IsOfficial; Name = entry.Name; Summary = entry.Summary; EntryType = entry.EntryType; Downloads = entry.Downloads; CreatedAt = entry.CreatedAt; LatestReleaseId = entry.LatestReleaseId; Categories = entry.Categories; } #region Implementation of IEntrySummary /// public long Id { get => _id; private set => SetAndNotify(ref _id, value); } /// public string Author { get => _author; private set => SetAndNotify(ref _author, value); } /// public bool IsOfficial { get => _isOfficial; private set => SetAndNotify(ref _isOfficial, value); } /// public string Name { get => _name; private set => SetAndNotify(ref _name, value); } /// public string Summary { get => _summary; private set => SetAndNotify(ref _summary, value); } /// public EntryType EntryType { get => _entryType; private set => SetAndNotify(ref _entryType, value); } /// public long Downloads { get => _downloads; private set => SetAndNotify(ref _downloads, value); } /// public DateTimeOffset CreatedAt { get => _createdAt; private set => SetAndNotify(ref _createdAt, value); } /// public long? LatestReleaseId { get => _latestReleaseId; private set => SetAndNotify(ref _latestReleaseId, value); } /// public IReadOnlyList Categories { get => _categories; private set => SetAndNotify(ref _categories, value); } #endregion /// public override string ToString() { return $"[{EntryType}] {Id} - {Name}"; } }