using System; using System.Collections.Generic; using System.ComponentModel; using System.IO; using System.Linq; using Newtonsoft.Json; namespace InABox.Core { public class UserProperty { [DoNotSerialize] public Type Type { get; set; } public object? Value { get; set; } } [Serializable] public class UserProperties { public delegate void PropertyChangedEventHandler(object sender, string name, object? before, object? after); public UserProperties() { Dictionary = new Dictionary(); //_dictionary = new Dictionary(); } public Dictionary Dictionary { get; set; } //public Type ParentType { get; set; } public object? this[string key] { get => Get(key); set => Set(key, value); } [JsonIgnore] public Dictionary AsDictionary { get { var result = new Dictionary(); foreach (var key in Dictionary.Keys) result[key] = this[key]; return result; } set { Clear(); foreach (var key in value.Keys) this[key] = value[key]; } } [JsonIgnore] public int Count => Dictionary.Count; public override bool Equals(object obj) { if (!(obj is UserProperties other)) return false; if (Dictionary.Count != other.Count) // Require equal count. return false; foreach (var pair in Dictionary) try { var value = other[pair.Key]; if (value == null) { if (pair.Value != null) return false; } else if (!value.Equals(pair.Value)) { return false; } } catch { return false; } return true; } public event PropertyChangedEventHandler? OnPropertyChanged; private object? Get(string key) { var prop = new UserProperty { Type = typeof(string), Value = "" }; if (Dictionary.ContainsKey(key)) prop = Dictionary[key]; if (prop.Type == null) return prop.Value; if (prop.Value == null) return prop.Type == typeof(object) ? null : Activator.CreateInstance(prop.Type); if (prop.Value.GetType() == prop.Type) return prop.Value; var tc = TypeDescriptor.GetConverter(prop.Type); return tc.ConvertFrom(prop.Value); } private void Set(string key, object? obj) { var before = Dictionary.GetValueOrDefault(key); Dictionary[key] = new UserProperty { Type = obj?.GetType() ?? typeof(object), Value = obj }; OnPropertyChanged?.Invoke(this, key, before, obj); } public bool ContainsKey(string key) { return Dictionary.ContainsKey(key); } public void Clear() { Dictionary.Clear(); } public string[] GetKeys() { return Dictionary.Keys.ToArray(); } internal void LoadFromDictionary(Dictionary defaultProperties) { foreach (var pair in defaultProperties) Dictionary[pair.Key] = new UserProperty { Type = pair.Value != null ? pair.Value.GetType() : typeof(object), Value = pair.Value }; } } public class UserPropertiesJsonConverter : JsonConverter { public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) { if (!(value is UserProperties props)) return; writer.WriteStartObject(); foreach (var key in props.GetKeys()) if (props[key] != null) { writer.WritePropertyName(key); writer.WriteValue(props[key] is string ? props[key] as string : props[key]); } writer.WriteEndObject(); } public override object ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) { var result = new UserProperties(); while (reader.TokenType != JsonToken.EndObject && reader.Read()) if (reader.Value != null) { var key = reader.Value.ToString(); reader.Read(); result[key] = reader.Value; } return result; } public override bool CanConvert(Type objectType) { return objectType == typeof(UserProperties); } } }