using System.Collections; using System.Collections.Immutable; using System.Diagnostics; using System.Reactive.Subjects; using InnovEnergy.Lib.Protocols.DBus.Protocol.DataTypes; namespace InnovEnergy.Lib.Victron.VeDBus; public class VeProperties : IEnumerable { // Thread safe private ImmutableDictionary _Dict = ImmutableDictionary.Empty; private readonly Subject _PropertyChanged = new(); private readonly Subject> _PropertiesChanged = new(); public IObservable PropertyChanged => _PropertyChanged; public IObservable> PropertiesChanged => _PropertiesChanged; public Variant GetValueOfAllProperties(String prefix = "") { return _Dict .Where(p => p.Key.Path.StartsWith(prefix)) .ToDictionary(p => p.Key.Path, p => p.Value.Value.Variant()) .Variant(); } public Dictionary GetTextOfAllProperties(String prefix = "") { return _Dict .Where(p => p.Key.Path.StartsWith(prefix)) .ToDictionary(p => p.Key.Path, p => p.Value.Text); } public Dictionary> GetAllItems(String prefix = "") { return _Dict .Where(p => p.Key.Path.StartsWith(prefix)) .ToDictionary(p => p.Key.Path, p => p.Value.GetItem()); } public VeProperty? Get(ObjectPath path) { return _Dict.TryGetValue(path, out var v) ? v : null; } public Boolean Set(ObjectPath path, Object value, String? text = null) { var txt = text ?? (value is Variant v ? v.Value.ToString() : value.ToString()); var p = new VeProperty(path, value, txt!); return Set(p); } public Boolean Set(ObjectPath path, Object value, Boolean writable, String? text = null) { var txt = text ?? (value is Variant v ? v.Value.ToString() : value.ToString()); var p = new VeProperty(path, value, Text:txt!, writable); return Set(p); } public Boolean Set(VeProperty prop) { // TODO: reenable optimization? // var p = Get(prop.ObjectPath); // // if (p.HasValue && p.Value == prop) // return false; Debug.WriteLine($"Property changed: {prop.ObjectPath} {prop.Value} {prop.Text}"); _Dict = _Dict.SetItem(prop.ObjectPath, prop); // thread safe _PropertiesChanged.OnNext(_Dict); _PropertyChanged.OnNext(prop); return true; } #region Collection initializer public Boolean Add(ObjectPath path, Object value, String? text = null) => Set(path, value, text:text); public Boolean Add(VeProperty prop) => Set(prop); public IEnumerator GetEnumerator() => _Dict.Values.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); #endregion Collection initializer }