using InABox.Configuration; using InABox.Core.Postable; using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Runtime; using System.Text; namespace InABox.Core { public static class PosterUtils { private class EngineType { public Type Engine { get; set; } public Type Entity { get; set; } public Type Poster { get; set; } } private static EngineType[]? _posterEngines; private static Type[]? _posters = null; public static Type[] GetPosters() { _posters ??= CoreUtils.TypeList( AppDomain.CurrentDomain.GetAssemblies(), x => x.IsClass && !x.IsAbstract && !x.IsGenericType && x.HasInterface(typeof(IPoster<,>))).ToArray(); return _posters; } private static EngineType[] GetPosterEngines() { _posterEngines ??= CoreUtils.TypeList( AppDomain.CurrentDomain.GetAssemblies(), x => x.IsClass && !x.IsAbstract && x.GetTypeInfo().GenericTypeParameters.Length == 1 && x.HasInterface(typeof(IPosterEngine<,,>)) ).Select(x => new EngineType { Engine = x, Entity = x.GetInterfaceDefinition(typeof(IPosterEngine<,,>))!.GenericTypeArguments[0], Poster = x.GetInterfaceDefinition(typeof(IPosterEngine<,,>))!.GenericTypeArguments[1].GetGenericTypeDefinition() }).ToArray(); return _posterEngines; } private static PostableSettings FixPostableSettings(PostableSettings settings) where TPostable : Entity, IPostable { if (string.IsNullOrWhiteSpace(settings.PostableType)) { settings.PostableType = typeof(TPostable).EntityName(); } return settings; } public static PostableSettings LoadPostableSettings() where T : Entity, IPostable { return FixPostableSettings(new GlobalConfiguration(typeof(T).Name).Load()); } public static void SavePostableSettings(PostableSettings settings) where T : Entity, IPostable { new GlobalConfiguration(typeof(T).Name).Save(FixPostableSettings(settings)); } private static TSettings FixPosterSettings(TSettings settings) where TPostable : IPostable where TSettings : PosterSettings, new() { if (string.IsNullOrWhiteSpace(settings.PostableType)) { settings.PostableType = typeof(TPostable).EntityName(); } return settings; } private static MethodInfo _loadPosterSettingsMethod = typeof(PosterUtils).GetMethods(BindingFlags.Static | BindingFlags.Public) .Where(x => x.Name == nameof(LoadPosterSettings) && x.IsGenericMethod) .Single(); private static MethodInfo _savePosterSettingsMethod = typeof(PosterUtils).GetMethods(BindingFlags.Static | BindingFlags.Public) .Where(x => x.Name == nameof(SavePosterSettings) && x.IsGenericMethod) .Single(); public static TSettings LoadPosterSettings() where TPostable : IPostable where TSettings : PosterSettings, new() { return FixPosterSettings(new GlobalConfiguration(typeof(TPostable).Name).Load()); } public static PosterSettings LoadPosterSettings(Type TPostable, Type TSettings) { return (_loadPosterSettingsMethod.MakeGenericMethod(TPostable, TSettings).Invoke(null, Array.Empty()) as PosterSettings)!; } public static void SavePosterSettings(TSettings settings) where TPostable : IPostable where TSettings : PosterSettings, new() { new GlobalConfiguration(typeof(TPostable).Name).Save(FixPosterSettings(settings)); } public static void SavePosterSettings(Type TPostable, Type TSettings, PosterSettings settings) { _savePosterSettingsMethod.MakeGenericMethod(TPostable, TSettings).Invoke(null, new object[] { settings }); } /// /// Get the for /// based on the current for . /// /// /// public static Type GetEngine() where T : Entity, IPostable, IRemotable, IPersistent, new() { var settings = LoadPostableSettings(); if (string.IsNullOrWhiteSpace(settings.PosterType)) { throw new MissingSettingsException(typeof(T)); } var poster = GetPosters()?.FirstOrDefault(x => x.EntityName() == settings.PosterType)!; var engines = GetPosterEngines().Where(x => poster.HasInterface(x.Poster)).ToList(); if (!engines.Any()) { throw new Exception("No poster for the given settings."); } else if(engines.Count == 1) { return engines[0].Engine.MakeGenericType(typeof(T)); } else { return engines.Single(x => x.Entity == typeof(T)).Engine.MakeGenericType(typeof(T)); } } public static IPosterEngine CreateEngine() where T : Entity, IPostable, IRemotable, IPersistent, new() { var engine = GetEngine(); return (Activator.CreateInstance(engine) as IPosterEngine)!; } /// /// Process with the currently set /// for . /// /// The type of that needs to be processed. /// /// If there are no items to post. In this case, nothing happens. /// If any of the have already been processed. In this case, nothing happens. /// If the for do not exist. /// If the post has been cancelled by the user. /// if post was unsuccessful. /// public static IPostResult? Process(IDataModel model) where T : Entity, IPostable, IRemotable, IPersistent, new() { return CreateEngine().Process(model); } } }