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 { #region Postable Settings private static PostableSettings FixPostableSettings(Type TPostable, PostableSettings settings) { if (string.IsNullOrWhiteSpace(settings.PostableType)) { settings.PostableType = TPostable.EntityName(); } return settings; } public static PostableSettings LoadPostableSettings() where T : Entity, IPostable { return FixPostableSettings(typeof(T), new GlobalConfiguration(typeof(T).Name).Load()); } public static void SavePostableSettings(PostableSettings settings) where T : Entity, IPostable { new GlobalConfiguration(typeof(T).Name).Save(FixPostableSettings(typeof(T), settings)); } #endregion #region Poster 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 }); } #endregion #region Global Poster Settings private static MethodInfo _loadGlobalPosterSettingsMethod = typeof(PosterUtils).GetMethods(BindingFlags.Static | BindingFlags.Public) .Where(x => x.Name == nameof(LoadGlobalPosterSettings) && x.IsGenericMethod) .Single(); private static MethodInfo _saveGlobalPosterSettingsMethod = typeof(PosterUtils).GetMethods(BindingFlags.Static | BindingFlags.Public) .Where(x => x.Name == nameof(SaveGlobalPosterSettings) && x.IsGenericMethod) .Single(); public static IGlobalPosterSettings LoadGlobalPosterSettings(Type TGlobalSettings) { return (_loadGlobalPosterSettingsMethod.MakeGenericMethod(TGlobalSettings).Invoke(null, Array.Empty()) as IGlobalPosterSettings)!; } public static TGlobalSettings LoadGlobalPosterSettings() where TGlobalSettings : BaseObject, IGlobalPosterSettings, new() { return new GlobalConfiguration().Load(); } public static void SaveGlobalPosterSettings(TGlobalSettings settings) where TGlobalSettings : BaseObject, IGlobalPosterSettings, new() { new GlobalConfiguration().Save(settings); } public static void SaveGlobalPosterSettings(Type TGlobalSettings, IGlobalPosterSettings settings) { _saveGlobalPosterSettingsMethod.MakeGenericMethod(TGlobalSettings).Invoke(null, new object[] { settings }); } #endregion #region Poster Engines 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; } /// /// 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)!; } #endregion #region Auto-Refresh /// /// Check if needs to be reposted; if it does, will be set to /// once this function is finished. /// /// /// This will only do something if the currently set poster for this type has the interface. /// /// /// if the item's status has been updated and needs to be reposted. public static bool CheckPostedStatus(PostableSettings settings, T item) where T : BaseObject { if (!(item is IPostable postable)) { return false; } if (postable.PostedStatus != PostedStatus.Posted || item?.HasOriginalValue(nameof(IPostable.PostedStatus)) == true) { return false; } settings = FixPostableSettings(typeof(T), settings); if (settings.PosterType.IsNullOrWhiteSpace()) { return false; } var poster = GetPosters()?.FirstOrDefault(x => x.EntityName() == settings.PosterType); if (poster is null) { return false; } var iautoRefresh = poster.GetInterfaceDefinition(typeof(IAutoRefreshPoster<,>)); if(iautoRefresh != null) { var autoRefresher = Activator.CreateInstance(iautoRefresh.GenericTypeArguments[1]) as IAutoRefresher; if (autoRefresher != null && autoRefresher.ShouldRepost(item)) { postable.PostedStatus = PostedStatus.RequiresRepost; return true; } } return false; } #endregion #region Process /// /// 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); } #endregion } }