using System.ComponentModel; using System.Linq.Expressions; using System.Reflection; using HopFrame.Web.Admin.Attributes; using HopFrame.Web.Admin.Attributes.Classes; using HopFrame.Web.Admin.Models; namespace HopFrame.Web.Admin.Generators.Implementation; internal sealed class AdminPageGenerator : IAdminPageGenerator, IGenerator> { public readonly AdminPage Page; private readonly Dictionary _propertyGenerators; public AdminPageGenerator() { Page = new AdminPage { Permissions = new AdminPagePermissions(), ModelType = typeof(TModel) }; _propertyGenerators = new Dictionary(); var type = typeof(TModel); var properties = type.GetProperties(); var generatorType = typeof(AdminPropertyGenerator<,>); foreach (var property in properties) { var attributes = property.GetCustomAttributes(false); var genericType = generatorType.MakeGenericType(property.PropertyType, type); var generator = Activator.CreateInstance(genericType, [property.Name, property.PropertyType]); var method = genericType .GetMethod(nameof(AdminPropertyGenerator.ApplyConfigurationFromAttributes))? .MakeGenericMethod(type); method?.Invoke(generator, [this, attributes, property]); _propertyGenerators.Add(property.Name, generator); } } public IAdminPageGenerator Title(string title) { Page.Title = title; return this; } public IAdminPageGenerator Description(string description) { Page.Description = description; return this; } public IAdminPageGenerator ViewPermission(string permission) { Page.Permissions.View = permission; return this; } public IAdminPageGenerator CreatePermission(string permission) { Page.Permissions.Create = permission; return this; } public IAdminPageGenerator UpdatePermission(string permission) { Page.Permissions.Update = permission; return this; } public IAdminPageGenerator DeletePermission(string permission) { Page.Permissions.Delete = permission; return this; } public IAdminPageGenerator ShowCreateButton(bool show) { Page.ShowCreateButton = show; return this; } public IAdminPageGenerator ShowDeleteButton(bool show) { Page.ShowDeleteButton = show; return this; } public IAdminPageGenerator ShowUpdateButton(bool show) { Page.ShowUpdateButton = show; return this; } public IAdminPageGenerator DefaultSort(Expression> propertyExpression, ListSortDirection direction) { var property = GetPropertyInfo(propertyExpression); Page.DefaultSortPropertyName = property.Name; Page.DefaultSortDirection = direction; return this; } public IAdminPageGenerator ConfigureProvider() where TRepository : ModelProvider { Page.RepositoryProvider = typeof(TRepository); return this; } public IAdminPropertyGenerator Property(Expression> propertyExpression) { var property = GetPropertyInfo(propertyExpression); if (_propertyGenerators.TryGetValue(property.Name, out var propertyGenerator)) return propertyGenerator as AdminPropertyGenerator; var generator = Activator.CreateInstance(typeof(AdminPropertyGenerator), new { property.Name, property.PropertyType }) as AdminPropertyGenerator; generator?.ApplyConfigurationFromAttributes(this, property.GetCustomAttributes(false), property); _propertyGenerators.Add(property.Name, generator); return generator; } public IAdminPageGenerator ListingProperty(Expression> propertyExpression) { var property = GetPropertyInfo(propertyExpression); Page.ListingProperty = property.Name; return this; } public AdminPage Compile() { var properties = new List(); foreach (var generator in _propertyGenerators.Values) { var method = generator.GetType().GetMethod(nameof(AdminPropertyGenerator.Compile)); var prop = method?.Invoke(generator, []) as AdminPageProperty; properties.Add(prop); } Page.Properties = properties; return Page; } public static PropertyInfo GetPropertyInfo(Expression> propertyLambda) { if (propertyLambda.Body is not MemberExpression member) { throw new ArgumentException($"Expression '{propertyLambda}' refers to a method, not a property."); } if (member.Member is not PropertyInfo propInfo) { throw new ArgumentException($"Expression '{propertyLambda}' refers to a field, not a property."); } Type type = typeof(TSource); if (propInfo.ReflectedType != null && type != propInfo.ReflectedType && !type.IsSubclassOf(propInfo.ReflectedType)) { throw new ArgumentException($"Expression '{propertyLambda}' refers to a property that is not from type {type}."); } if (propInfo.Name is null) throw new ArgumentException($"Expression '{propertyLambda}' refers a not existing property."); return propInfo; } public void ApplyConfigurationFromAttributes(object[] attributes) { if (attributes.Any(a => a is AdminNameAttribute)) { var attribute = attributes.Single(a => a is AdminNameAttribute) as AdminNameAttribute; Title(attribute?.Name); } if (attributes.Any(a => a is AdminDescriptionAttribute)) { var attribute = attributes.Single(a => a is AdminDescriptionAttribute) as AdminDescriptionAttribute; Description(attribute?.Description); } if (attributes.Any(a => a is AdminPermissionsAttribute)) { var attribute = attributes.Single(a => a is AdminPermissionsAttribute) as AdminPermissionsAttribute; CreatePermission(attribute?.Permissions.Create); UpdatePermission(attribute?.Permissions.Update); ViewPermission(attribute?.Permissions.View); DeletePermission(attribute?.Permissions.Delete); } if (attributes.Any(a => a is AdminButtonConfigAttribute)) { var attribute = attributes.Single(a => a is AdminButtonConfigAttribute) as AdminButtonConfigAttribute; ShowCreateButton(attribute?.ShowCreateButton == true); ShowUpdateButton(attribute?.ShowUpdateButton == true); ShowDeleteButton(attribute?.ShowDeleteButton == true); } } }