using Castle.Core.Logging; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; namespace Pilz.Configuration; public class Settings : ISettings { protected readonly Dictionary settingsJson = []; protected readonly Dictionary settings = []; protected JsonSerializerSettings serializerSettings; public virtual IReadOnlyCollection Childs => settings.Values; public virtual ILogger Logger { get; set; } = NullLogger.Instance; public virtual T Get() where T : ISettingsNode, ISettingsIdentifier { // Find existing one if (settings.TryGetValue(T.Identifier, out var valueExisting) && valueExisting is T settingsExisting) return settingsExisting; // Create new & reset if (Activator.CreateInstance() is T settingsNew) settingsNew.Reset(); else { settingsNew = default; Logger.WarnFormat("Not able to create new settings node instance {0}.", T.Identifier); } // Try deserialize if (settingsJson.TryGetValue(T.Identifier, out var valueRaw)) { var serializer = JsonSerializer.CreateDefault(serializerSettings); // Populate if (settingsNew != null) { try { serializer.Populate(valueRaw.CreateReader(), settingsNew); Logger.InfoFormat("Populated settings node {0}.", T.Identifier); } catch (Exception ex) { Logger.Error("Error populating settings node instance.", ex); } } // Deserialize (fallback) else if (valueRaw.ToObject() is T settingsDeserialized) { try { settingsNew = settingsDeserialized; Logger.WarnFormat("Deserialied settings node {0} via fallback variant.", T.Identifier); } catch (Exception ex) { Logger.Error("Error deserializing settings node instance.", ex); } } } // Remember if (settingsNew != null) settings[T.Identifier] = settingsNew; // Return return settingsNew; } public void Reset() { foreach (var s in settings.Values) s.Reset(); } public virtual string Save(JsonSerializerSettings serializerSettings) { this.serializerSettings = serializerSettings; var serializer = JsonSerializer.CreateDefault(serializerSettings); foreach (var kvp in settings) { var raw = JObject.FromObject(kvp.Value, serializer); if (!settingsJson.TryAdd(kvp.Key, raw)) settingsJson[kvp.Key] = raw; } var objList = new JObject(); foreach (var kvp in settingsJson) objList.Add(kvp.Key, kvp.Value); var objSettings = new JObject { { "Settings", objList } }; return objSettings.ToString(serializer.Formatting); } public virtual bool Load(JsonSerializerSettings serializerSettings, string raw) { this.serializerSettings = serializerSettings; var objSettings = JObject.Parse(raw); if (!objSettings.TryGetValue("Settings", out var tokenList) || tokenList is not JObject objList) return false; settingsJson.Clear(); settings.Clear(); foreach (var child in objList) { if (child.Value is not JObject value) continue; settingsJson.Add(child.Key, value); } return true; } protected virtual JToken Serialize(object o, JsonSerializer jsonSerializer) { using JTokenWriter jTokenWriter = new JTokenWriter(); jsonSerializer.Serialize(jTokenWriter, o, o.GetType()); return jTokenWriter.Token; } }