123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462 |
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.Linq;
- using System.Linq.Expressions;
- using System.Reflection;
- namespace InABox.Core
- {
- public interface ILookupDefinition<TLookup> where TLookup : BaseObject, new()
- {
- Filter<TLookup> DefineFilter();
- Columns<TLookup> DefineColumns();
- Columns<TLookup> RequiredColumns();
- SortOrder<TLookup> DefineSortOrder();
- string FormatLookup(Dictionary<string, object> values, IEnumerable<string> exclude);
- }
- public interface ILookupDefinition<TLookup, TEntity> where TLookup : Entity
- {
- Filter<TLookup> DefineFilter(TEntity[] items);
- }
- public interface IStaticLookupDefinition<TEntity>
- {
- Dictionary<object, object> DefineLookups(PropertyInfo property);
- }
- public static class LookupFactory
- {
- #region LookupCache
- private class LookupCacheEntry
- {
- public LookupCacheEntry(object factory)
- {
- DefaultFactory = factory;
- CustomFactories = new Dictionary<Type, object>();
- StaticFactory = null;
- }
- public object DefaultFactory { get; }
- public Dictionary<Type, object> CustomFactories { get; }
- public object StaticFactory { get; set; }
- public object GetFactory(Type type = null)
- {
- if (type == null)
- return DefaultFactory;
- if (CustomFactories.ContainsKey(type))
- return CustomFactories[type];
- return DefaultFactory;
- }
- }
- private class LookupCache
- {
- private static Dictionary<Type, LookupCacheEntry> _cache;
- public LookupCache()
- {
- _cache = new Dictionary<Type, LookupCacheEntry>();
- // Load up the default types
- var defaulttypes = CoreUtils.TypeList(
- AppDomain.CurrentDomain.GetAssemblies(),
- x => !x.IsAbstract &&
- x.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition().Equals(typeof(ILookupDefinition<>))
- )
- );
- foreach (var type in defaulttypes)
- try
- {
- var intfs = type.GetInterfaces().Where(i =>
- i.IsGenericType
- && i.GetGenericTypeDefinition().Equals(typeof(ILookupDefinition<>))
- );
- foreach (var intf in intfs)
- _cache[intf.GenericTypeArguments.First()] = new LookupCacheEntry(Activator.CreateInstance(type));
- }
- catch (Exception e)
- {
- Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));
- }
- // Now load up the specific types
- var specifictypes = CoreUtils.TypeList(
- AppDomain.CurrentDomain.GetAssemblies(),
- x =>
- !x.IsAbstract &&
- x.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition().Equals(typeof(ILookupDefinition<,>))
- )
- );
- foreach (var type in specifictypes)
- {
- var intfs = type.GetInterfaces().Where(i =>
- i.IsGenericType
- && i.GetGenericTypeDefinition().Equals(typeof(ILookupDefinition<,>))
- );
- foreach (var intf in intfs)
- {
- var lookuptype = intf.GenericTypeArguments.First();
- var entitytype = intf.GenericTypeArguments.Last();
- if (!_cache.ContainsKey(lookuptype))
- _cache[lookuptype] = new LookupCacheEntry(null);
- _cache[lookuptype].CustomFactories[entitytype] = Activator.CreateInstance(type);
- }
- }
- // Load up the static lookups
- var staticlookups = CoreUtils.TypeList(
- AppDomain.CurrentDomain.GetAssemblies(),
- x =>
- !x.IsAbstract &&
- x.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition().Equals(typeof(IStaticLookupDefinition<>))
- )
- );
- foreach (var type in staticlookups)
- {
- var intf = type.GetInterfaces().First(i =>
- i.IsGenericType
- && i.GetGenericTypeDefinition().Equals(typeof(IStaticLookupDefinition<>))
- );
- var iType = intf.GenericTypeArguments.First();
- if (!_cache.ContainsKey(iType))
- _cache[iType] = new LookupCacheEntry(null);
- _cache[iType].StaticFactory = Activator.CreateInstance(type);
- }
- }
- public object GetFactory(Type lookup, Type entity = null)
- {
- if (!_cache.ContainsKey(lookup))
- return null;
- if (entity == null)
- return _cache[lookup].DefaultFactory;
- if (_cache[lookup].CustomFactories.ContainsKey(entity))
- return _cache[lookup].CustomFactories[entity];
- return null;
- }
- public object GetStaticFactory(Type lookup)
- {
- if (!_cache.ContainsKey(lookup))
- return null;
- return _cache[lookup].StaticFactory;
- }
- }
- private static readonly LookupCache _cache = new LookupCache();
- #endregion
- #region General Factory Methods
- private static object DoInvoke(Type TLookup, Type TResult, string Method)
- {
- var factory = _cache.GetFactory(TLookup);
- if (factory != null)
- {
- var filtertype = TResult.MakeGenericType(TLookup);
- var method = factory.GetType().GetMethods().FirstOrDefault(m =>
- m.Name.Equals(Method)
- && !m.GetParameters().Any()
- && m.ReturnType == filtertype
- );
- if (method != null)
- try
- {
- object[] parameters = { };
- return method.Invoke(factory, parameters);
- }
- catch (Exception e)
- {
- Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));
- }
- }
- return null;
- }
- // If a specific Entity/Lookup match can't be found,
- // this will fall back to the global Lookup filter (if there is one)
- // Otherwise, it will return null
- private static object DoInvoke(Type TLookup, Type TEntity, IEnumerable items, Type TResult, string Method)
- {
- var factory = _cache.GetFactory(TLookup, TEntity);
- if (factory != null)
- {
- var filtertype = typeof(Filter<>).MakeGenericType(TLookup);
- var method = factory.GetType().GetMethods().FirstOrDefault(m =>
- m.Name.Equals("DefineFilter")
- && m.GetParameters().Any()
- && m.ReturnType == filtertype
- && m.GetParameters().First().ParameterType == items.GetType()
- );
- if (method != null)
- try
- {
- object[] parameters = { items };
- return method.Invoke(factory, parameters);
- }
- catch (Exception e)
- {
- Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));
- }
- }
- return DoInvoke(TLookup, TResult, Method);
- }
- private static Dictionary<object, object> DoInvoke(Type TLookup, PropertyInfo property, string Method)
- {
- var factory = _cache.GetStaticFactory(TLookup);
- if (factory != null)
- {
- var method = factory.GetType().GetMethods().Where(m =>
- m.Name.Equals(Method) &&
- m.GetParameters().SingleOrDefault() != null &&
- m.ReturnType.Equals(typeof(Dictionary<object, object>))
- ).FirstOrDefault();
- if (method != null)
- try
- {
- object[] parameters = { property };
- return method.Invoke(factory, parameters) as Dictionary<object, object>;
- }
- catch (Exception e)
- {
- Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));
- }
- }
- return null;
- }
- private static object DoInvoke(Type TLookup, Type TReturn, string Method, params object[] args)
- {
- var factory = _cache.GetFactory(TLookup);
- if (factory != null)
- {
- var method = factory.GetType().GetMethods().Where(m =>
- m.Name.Equals(Method) &&
- m.GetParameters().Length == args.Length &&
- m.ReturnType.Equals(TReturn)
- ).FirstOrDefault();
- if (method != null)
- try
- {
- return method.Invoke(factory, args);
- }
- catch (Exception e)
- {
- Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));
- }
- }
- return null;
- }
- #endregion
- #region Formats
- public static string DefaultFormatLookup(Dictionary<string, object> values, IEnumerable<string> exclude)
- {
- return string.Join(": ",
- values.Where(x => x.Value != null && x.Value.GetType() != typeof(Guid) && (exclude == null || !exclude.Contains(x.Key)))
- .Select(p => p.Value));
- }
- public static string FormatLookup(Type TLookup, Dictionary<string, object> values, IEnumerable<string> exclude)
- {
- return DoInvoke(TLookup, typeof(string), "FormatLookup", values, exclude) as string;
- }
- public static string FormatLookup<TLookup>(Dictionary<string, object> values, IEnumerable<string> exclude)
- {
- return FormatLookup(typeof(TLookup), values, exclude);
- }
- #endregion
- #region Filters
- public static IFilter DefineFilter(Type TLookup)
- {
- return DoInvoke(TLookup, typeof(Filter<>), "DefineFilter") as IFilter;
- //var factory =_cache.GetFactory(TLookup);
- //if (factory != null)
- //{
- // Type filtertype = typeof(Filter<>).MakeGenericType(TLookup);
- // var method = factory.GetType().GetMethods().Where(m =>
- // m.Name.Equals("DefineFilter") &&
- // m.GetParameters().Any() &&
- // m.GetParameters().First().ParameterType.IsByRef &&
- // m.GetParameters().First().ParameterType.GetElementType().Equals(filtertype)).FirstOrDefault();
- // if (method != null)
- // {
- // try
- // {
- // object[] parameters = new object[] { null };
- // method.Invoke(factory, parameters);
- // return parameters[0];
- // }
- // catch (Exception e)
- // {
- // }
- // }
- //}
- //return null;
- }
- public static Filter<TLookup> DefineFilter<TLookup>()
- {
- return DefineFilter(typeof(TLookup)) as Filter<TLookup>;
- }
- public static IFilter DefineFilter(Type TLookup, Type TEntity, IEnumerable items)
- {
- return DoInvoke(TLookup, TEntity, items, typeof(Filter<>), "DefineFilter") as IFilter;
- }
- public static IFilter DefineFilter<TEntity>(IEnumerable<TEntity> items, Type TLookup)
- {
- return DoInvoke(TLookup, typeof(TEntity), items, typeof(Filter<>), "DefineFilter") as IFilter;
- }
- public static Filter<TLookup> DefineFilter<TEntity, TLookup>(TEntity[] items) where TEntity : Entity where TLookup : Entity
- {
- return DefineFilter(items, typeof(TLookup)) as Filter<TLookup>;
- }
-
- #endregion
- #region Columns
- public static IColumns DefineColumns(Type TLookup)
- {
- var result = DoInvoke(TLookup, typeof(Columns<>), "DefineColumns") as IColumns;
- if (result == null)
- {
- var type = typeof(Columns<>).MakeGenericType(TLookup);
- result = Activator.CreateInstance(type) as IColumns;
- result = result.DefaultColumns();
- }
- return result;
- }
- public static Columns<TLookup> DefineColumns<TLookup>()
- {
- return DefineColumns(typeof(TLookup)) as Columns<TLookup>;
- }
-
- #endregion
-
- #region RequiredColumns
- public static IColumns RequiredColumns(Type TLookup)
- {
- var result = DoInvoke(TLookup, typeof(Columns<>), "RequiredColumns") as IColumns;
- if (result == null)
- {
- var type = typeof(Columns<>).MakeGenericType(TLookup);
- result = Activator.CreateInstance(type) as IColumns;
- result = result.DefaultColumns();
- }
- return result;
- }
- public static Columns<TLookup> RequiredColumns<TLookup>()
- {
- return RequiredColumns(typeof(TLookup)) as Columns<TLookup>;
- }
-
- #endregion
- #region SortOrder
- public static ISortOrder DefineSort(Type TLookup)
- {
- return DoInvoke(TLookup, typeof(SortOrder<>), "DefineSortOrder") as ISortOrder;
- }
- public static SortOrder<TLookup> DefineSort<TLookup>()
- {
- return DefineSort(typeof(TLookup)) as SortOrder<TLookup>;
- }
-
- #endregion
- #region Static Lookups
- public static Dictionary<object, object> DefineLookups(Type type, PropertyInfo property)
- {
- return DoInvoke(type, property, "DefineLookups");
- }
- public static Dictionary<object, object> DefineLookups<TLookup>(Expression<Func<TLookup, object>> property)
- {
- return DefineLookups(typeof(TLookup), CoreUtils.GetPropertyFromExpression(property));
- }
- #endregion
- }
- public abstract class BaseObjectLookup<TLookup> : ILookupDefinition<TLookup> where TLookup : BaseObject, new()
- {
- public virtual string FormatLookup(Dictionary<string, object> values, IEnumerable<string> exclude)
- {
- var filtered = new Dictionary<string, object>();
- var cols = DefineColumns();
- foreach (var col in cols.Items)
- if (values.ContainsKey(col.Property) && values[col.Property] != null && values[col.Property].GetType() != typeof(Guid))
- filtered[col.Property] = values[col.Property];
- return LookupFactory.DefaultFormatLookup(filtered, exclude);
- }
- public abstract Columns<TLookup> DefineColumns();
- public abstract Columns<TLookup> RequiredColumns();
- public abstract Filter<TLookup> DefineFilter();
- public abstract SortOrder<TLookup> DefineSortOrder();
- }
- public abstract class EntityLookup<TLookup> : BaseObjectLookup<TLookup> where TLookup : Entity, new()
- {
- public override Columns<TLookup> DefineColumns()
- {
- return new Columns<TLookup>(x => x.ID);
- }
- public override Columns<TLookup> RequiredColumns()
- {
- var result = new Columns<TLookup>();
- var props = DatabaseSchema.Properties(typeof(TLookup)).Where(x => x.Required);
-
- //CoreUtils.PropertyList(typeof(TLookup), (p) => p.GetCustomAttribute<RequiredColumnAttribute>() != null, true);
- foreach (var prop in props)
- result.Add(prop.Name);
- return result;
- }
- }
- }
|