using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; namespace InABox.Core { /// /// Class to manage the storing of form data, including the separation of blob and form data. /// public class DFSaveStorage { public Dictionary FormData { get; private set; } public Dictionary BlobData { get; private set; } public DFSaveStorage() { FormData = new Dictionary(); BlobData = new Dictionary(); } public int Count() => FormData.Count(); public void AddValue(string key, object? value) { FormData.Add(key, value); } public void AddBlobValue(string key, object? value) { if(value != null) { var id = Guid.NewGuid().ToString(); BlobData.Add(id, value); FormData.Add(key, id); } } public object? GetValue(string key) => FormData.GetValueOrDefault(key); public DFSaveStorageEntry GetEntry(string key) { return new DFSaveStorageEntry(this, key); } public DFLoadStorage ToLoadStorage() { return new DFLoadStorage(FormData, BlobData); } } public class DFSaveStorageEntry { private readonly DFSaveStorage storage; private readonly string key; public DFSaveStorageEntry(DFSaveStorage storage, string key) { this.storage = storage; this.key = key; } public object? GetValue() => storage.GetValue(key); public object? GetValue(string subKey) => storage.GetValue($"{key}.{subKey}"); public void SetValue(object? value) { storage.AddValue(key, value); } public void AddValue(string subKey, object? value) { storage.AddValue($"{key}.{subKey}", value); } public void SetBlobValue(object? value) { storage.AddBlobValue(key, value); } public void AddBlobValue(string subKey, object? value) { storage.AddBlobValue($"{key}.{subKey}", value); } } public class DFLoadStorage { public Dictionary FormData { get; private set; } = new Dictionary(); public DFLoadStorage() : this(new Dictionary(), null) { } public DFLoadStorage(Dictionary formData, Dictionary? blobData) { Load(formData, blobData); } public void Load(Dictionary formData, Dictionary? blobData) { FormData = formData; if (blobData != null) { var updates = new List>(); foreach (var (key, value) in FormData) { if ((value is string str && blobData.TryGetValue(str, out var blob)) || (value is Guid guid && blobData.TryGetValue(guid.ToString(), out blob))) { updates.Add(new Tuple(key, blob)); } } foreach (var (key, value) in updates) { FormData[key] = value; } } } public void Clear() => FormData.Clear(); public int Count() => FormData.Count(); /// /// Get a value from the storage, returning if the key does not exist. /// /// /// public object? GetValue(string key) { return FormData.GetValueOrDefault(key); } [return: MaybeNull] public T GetValue(string key) { if(FormData.TryGetValue(key, out var value)) { if(value is T t) { return t; } else if(value is string str) { if(Guid.TryParse(str, out var id)) { if(id is T) { return (T)(object)id; } else { return default; } } try { return Serialization.Deserialize(str, strict: true); } catch { return CoreUtils.ChangeType(value); } } else if(value is JToken jToken) { return Serialization.Deserialize(jToken); } else { return CoreUtils.ChangeType(value); } } return default; } public bool HasValue(string key) { return FormData.ContainsKey(key); } public DFLoadStorageEntry GetEntry(string key) { return new DFLoadStorageEntry(this, key); } public IEnumerable> Items() { return FormData; } } public class DFLoadStorageEntry { private readonly DFLoadStorage storage; private readonly string key; public DFLoadStorageEntry(DFLoadStorage storage, string key) { this.storage = storage; this.key = key; } /// /// Gets the value from the storage entry, returning if it does not exist. /// /// /// public object? GetValue() { return storage.GetValue(key); } [return: MaybeNull] public T GetValue() { return storage.GetValue(key); } /// /// Gets a sub-value from the storage entry, returning if it does not exist. /// /// /// public object? GetValue(string subKey) { return storage.GetValue($"{key}.{subKey}"); } [return: MaybeNull] public T GetValue(string subKey) { return storage.GetValue($"{key}.{subKey}"); } public bool HasValue() => storage.HasValue(key); public bool HasValue(string subKey) => storage.HasValue($"{key}.{subKey}"); public IEnumerable> SubItems() { var prefix = $"{key}."; foreach(var (key, value) in storage.Items()) { if (key.StartsWith(prefix)) { yield return new KeyValuePair(key[prefix.Length..], value); } } } } }