using HopFrame.Web.Admin.Models; using HopFrame.Web.Admin.Providers; namespace HopFrame.Web.Admin.Generators.Implementation; internal class AdminContextGenerator : IAdminContextGenerator { private readonly IDictionary _adminPages = new Dictionary(); public IAdminPageGenerator Page() { if (_adminPages.TryGetValue(typeof(TModel), out var pageGenerator)) return pageGenerator as IAdminPageGenerator; var generator = Activator.CreateInstance(typeof(IAdminPageGenerator)) as AdminPageGenerator; generator?.ApplyConfigurationFromAttributes(typeof(TModel).GetCustomAttributes(false)); _adminPages.Add(typeof(TModel), generator); return generator; } public AdminPage CompilePage() { var generator = _adminPages[typeof(TModel)]; if (generator is null) return null; return (generator as AdminPageGenerator)?.Compile(); } public TContext CompileContext() where TContext : AdminPagesContext { var type = typeof(TContext); var compileMethod = typeof(AdminContextGenerator).GetMethod(nameof(CompilePage)); var properties = type.GetProperties(); var context = Activator.CreateInstance(); foreach (var property in properties) { var propertyType = property.PropertyType.GenericTypeArguments[0]; var pageGeneratorType = typeof(AdminPageGenerator<>).MakeGenericType(propertyType); var generatorInstance = Activator.CreateInstance(pageGeneratorType, [property.Name]); // Calls constructor with title attribute var populatorMethod = pageGeneratorType.GetMethod(nameof(AdminPageGenerator.ApplyConfigurationFromAttributes)); populatorMethod?.Invoke(generatorInstance, [propertyType.GetCustomAttributes(false)]); _adminPages.Add(propertyType, generatorInstance); } context.OnModelCreating(this); foreach (var property in properties) { var modelType = property.PropertyType.GenericTypeArguments[0]; var method = compileMethod?.MakeGenericMethod(modelType); property.SetValue(context, method?.Invoke(this, [])); } return context; } public static void RegisterPages(AdminPagesContext context, IAdminPagesProvider provider) { var properties = context.GetType().GetProperties(); foreach (var property in properties) { var page = property.GetValue(context) as AdminPage; if (page is null) continue; provider.RegisterAdminPage(page.Title.ToLower(), page); } } }