using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.ComponentModel; using System.Security.Cryptography; using System.Reflection; using ln.types.btree; using ln.json; using ln.logging; using ln.json.mapping; namespace ln.manage { public abstract class ManagedObjectProvider { public Type ManagedType { get; } ManagedObjectProvider container; public ManagedObjectProvider Container { get => container; set { if (Object.Equals(container, this)) throw new ArgumentOutOfRangeException(nameof(value)); container?.RemoveChildProvider(this); container = value; container?.AddChildProvider(this); if (!Object.ReferenceEquals(null,container)) { List path = new List(); fillpath(path); pathlist = PathList.ToArray(); } else { pathlist = new string[0]; } } } public string Name { get; private set; } public string[] pathlist = new string[0]; public string[] PathList => (string[])pathlist.Clone(); public string Path => String.Join("/", PathList); protected MappingBTree propertyDescriptors = new MappingBTree((mopd)=>mopd.PropertyName); public virtual IEnumerable PropertyDescriptors => propertyDescriptors.Values; public String UniqueIdentifierPropertyName { get; protected set; } Dictionary children = new Dictionary(); public IEnumerable Children => children.Values; public ManagedObjectProvider(Type type): this(type, type.Name, null) { } public ManagedObjectProvider(Type type, String name) : this(type, name, null) { } public ManagedObjectProvider(Type type, String name, ManagedObjectProvider container) : this(true, type, name, container) { } protected ManagedObjectProvider(bool buildPropertyDescriptors,Type type,String name,ManagedObjectProvider container) { ManagedType = type; Name = name; Container = container; if (buildPropertyDescriptors) BuildPropertyDescriptors(); } private void AddChildProvider(ManagedObjectProvider childProvider) { children.Add(childProvider.Name, childProvider); childProvider.container = this; } private void RemoveChildProvider(ManagedObjectProvider childProvider) { if (children.TryGetValue(childProvider.Name, out ManagedObjectProvider child) && Object.Equals(child, childProvider)) { children.Remove(childProvider.Name); childProvider.container = null; } else throw new KeyNotFoundException(); } protected virtual void CollectObjects(ISet> set) { CollectLocalObjects(set); CollectChildObjects(set); } protected virtual void CollectChildObjects(ISet> set) { foreach (ManagedObjectProvider childProvider in Children) { if (childProvider.ManagedType.IsSubclassOf(ManagedType)) { foreach (Tuple childObject in childProvider.EnumerateProviderItems()) set.Add(childObject); } } } protected virtual void CollectLocalObjects(ISet> set) { } public virtual IEnumerable EnumerateItems() => EnumerateProviderItems().Select((arg) => arg.Item2); public virtual IEnumerable> EnumerateProviderItems() { HashSet> childObjects = new HashSet>(); CollectObjects(childObjects); return childObjects; } public abstract object GetManagedObject(object uniqueIdentifier); public abstract ManagedObjectState GetManagedObjectState(object o); public virtual object CreateManagedObject(IEnumerable> properties) => throw new NotSupportedException(); public virtual object CreateManagedObject() => CreateManagedObject(null); public virtual void ChangeObject(object o, IEnumerable> properties) { try { foreach (KeyValuePair property in properties) propertyDescriptors[property.Key].SetValue(o, property.Value); } catch (Exception e) { Logging.Log(e); throw e; } } public abstract void RemoveObject(object o); public abstract void Enable(object o); public abstract void Disable(object o); private void fillpath(List path) { if (Container != null) Container.fillpath(path); path.Add(Name); } protected void BuildPropertyDescriptors() { if (ManagedType == null) return; foreach (FieldInfo fieldInfo in ManagedType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) { if (fieldInfo.IsPublic || fieldInfo.GetCustomAttribute() != null) { propertyDescriptors.Add(new ManagedObjectPropertyDescriptor(this, fieldInfo)); } } foreach (PropertyInfo propertyInfo in ManagedType.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) { if (propertyInfo.GetMethod.IsPublic || propertyInfo.GetCustomAttribute() != null) { propertyDescriptors.Add(new ManagedObjectPropertyDescriptor(this, propertyInfo)); } } } public virtual JSONObject CreateJsonDescriptor() { JSONObject descriptor = new JSONObject(); descriptor["name"] = Name; descriptor["readonly"] = false; descriptor["cosmetic"] = false; descriptor["hint"] = ""; descriptor["key"] = UniqueIdentifierPropertyName; JSONObject jproperties = new JSONObject(); foreach (ManagedObjectPropertyDescriptor propertyDescriptor in PropertyDescriptors) jproperties[propertyDescriptor.PropertyName] = propertyDescriptor.CreateJsonDescriptor(); descriptor["properties"] = jproperties; JSONObject jchildren = new JSONObject(); foreach (ManagedObjectProvider managedObjectProvider in Children) jchildren[managedObjectProvider.Name] = managedObjectProvider.CreateJsonDescriptor(); descriptor["children"] = jchildren; return descriptor; } public virtual JSONObject CreateJsonObject(object o) { if (!ManagedType.Equals(o.GetType()) && !ManagedType.IsSubclassOf(o.GetType())) throw new ArgumentException(); JSONObject jObject = new JSONObject(); jObject["provider"] = this.Path; //jObject["state"] = GetManagedObjectState(o); JSONObject jProperties = new JSONObject(); foreach (ManagedObjectPropertyDescriptor descriptor in PropertyDescriptors) jProperties[descriptor.PropertyName] = JSONMapper.DefaultMapper.ToJson(descriptor.GetValue(o)); jObject["properties"] = jProperties; return jObject; } } }