using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; namespace Tango.BL { public abstract class ObservableEntityDTO : IObservableEntityDTO, IEquatable where T : IObservableEntity where DTO : ObservableEntityDTO { public int ID { get; set; } public String Guid { get; set; } public DateTime LastUpdated { get; set; } public static DTO FromObservable(T observable) { if (observable == null) return null; var dto = Activator.CreateInstance(); foreach (var prop in typeof(DTO).GetProperties()) { var observableProp = typeof(T).GetProperty(prop.Name); if (observableProp != null) { if (prop.PropertyType.IsPrimitive || prop.PropertyType.IsValueType || prop.PropertyType == typeof(String)) { prop.SetValue(dto, observableProp.GetValue(observable)); } else if (!prop.PropertyType.IsGenericType) { prop.SetValue(dto, prop.PropertyType.GetMethod(nameof(FromObservable), BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy).Invoke(null, new object[] { observableProp.GetValue(observable) })); } else { IList collection = Activator.CreateInstance(prop.PropertyType) as IList; IList source = observableProp.GetValue(observable) as IList; foreach (var item in source) { collection.Add(prop.PropertyType.GenericTypeArguments[0].GetMethod(nameof(FromObservable), BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy).Invoke(null, new object[] { item })); } prop.SetValue(dto, collection); } } } return dto; } public T ToObservable() { T observable = Activator.CreateInstance(); MapToObservable(observable); return observable; } public void MapToObservable(T observable) { foreach (var prop in typeof(DTO).GetProperties()) { var observableProp = typeof(T).GetProperty(prop.Name); if (observableProp != null) { if (prop.PropertyType.IsPrimitive || prop.PropertyType.IsValueType || prop.PropertyType == typeof(String)) { observableProp.SetValue(observable, prop.GetValue(this)); } else if (!prop.PropertyType.IsGenericType) { var propInstance = prop.GetValue(this); if (propInstance != null) { var observableInstance = observableProp.GetValue(observable); if (observableInstance == null) { observableInstance = Activator.CreateInstance(observableProp.PropertyType); observableProp.SetValue(observable, observableInstance); } var method = prop.PropertyType.GetRuntimeMethod(nameof(MapToObservable), new Type[] { observableProp.PropertyType }); method.Invoke(propInstance, new object[] { observableInstance }); } } else { IList collection = prop.GetValue(this) as IList; IList observableCollection = observableProp.GetValue(observable) as IList; if (collection != null) { foreach (var item in collection) { bool found = false; foreach (var o in observableCollection) { var dtoItem = item as IObservableEntityDTO; var observableItem = o as IObservableEntity; if (dtoItem.Guid.Equals(observableItem.Guid)) { var method = dtoItem.GetType().GetRuntimeMethod(nameof(MapToObservable), new Type[] { observableItem.GetType() }); method.Invoke(dtoItem, new object[] { observableItem }); found = true; break; } } if (!found) { var observableItem = Activator.CreateInstance(observableProp.PropertyType.GenericTypeArguments[0]); var method = item.GetType().GetRuntimeMethod(nameof(MapToObservable), new Type[] { observableItem.GetType() }); method.Invoke(item, new object[] { observableItem }); observableCollection.Add(observableItem); } } } } } } } public bool EqualsToObservable(T observable) { if (observable == null) return false; foreach (var prop in typeof(DTO).GetProperties()) { var observableProp = typeof(T).GetProperty(prop.Name); if (observableProp != null) { if (prop.PropertyType.IsPrimitive || prop.PropertyType.IsValueType || prop.PropertyType == typeof(String)) { var observableValue = observableProp.GetValue(observable); var dtoValue = prop.GetValue(this); if (dtoValue == null && observableValue != null) return false; if (dtoValue != null && observableValue == null) return false; if (dtoValue != null && observableValue != null) { if (!dtoValue.Equals(observableValue)) { return false; } } } else if (!prop.PropertyType.IsGenericType) { var propInstance = prop.GetValue(this); var observableInstance = observableProp.GetValue(observable); if (propInstance == null && observableInstance != null) return false; if (propInstance != null) { var method = prop.PropertyType.GetRuntimeMethod(nameof(EqualsToObservable), new Type[] { observableInstance.GetType() }); if (!((bool)method.Invoke(propInstance, new object[] { observableInstance }))) { return false; } } } else { IList source = observableProp.GetValue(observable) as IList; IList collection = prop.GetValue(this) as IList; if (collection == null && source != null) return false; if (source == null && collection != null) return false; if (source != null && collection != null) { if (source.Count != collection.Count) return false; for (int i = 0; i < source.Count; i++) { var item = collection[i]; var itemSource = source[i]; var method = item.GetType().GetRuntimeMethod(nameof(EqualsToObservable), new Type[] { itemSource.GetType() }); if (item == null && itemSource != null) return false; if (!((bool)method.Invoke(item, new object[] { itemSource }))) { return false; } } } } } } return true; } public bool Equals(T observable) { return EqualsToObservable(observable); } } }