using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Reflection; using Luticate2.Auth.Utils.Business.Utils; using Luticate2.Auth.Utils.Dbo; using Luticate2.Auth.Utils.Dbo.Result; using Luticate2.Auth.Utils.Interfaces; namespace Luticate2.Auth.Utils.Business.Converters.ObjectConverterDescriptor { public class LuObjectConverterDescriptor : ILuObjectConverterDescriptor { protected class LuObjectConverterDescriptorMemberInfo { public LambdaExpression ValueExpression { get; set; } } protected class LuObjectConverterDescriptorMethodInfo { public LambdaExpression ValueExpression { get; set; } } protected delegate LuObjectConverterDescriptorMethodInfo DynamicMethodConverter(MethodInfo methodInfo, ILuConvertersTypeConverter typeConverter); private IDictionary StaticMemberConverters { get; } = new Dictionary(); private IDictionary StaticMethodConverters { get; } = new Dictionary(); private IDictionary DynamicMethodConverters { get; } = new Dictionary(); protected void AddStaticMemberConverter(LambdaExpression memberFrom, LambdaExpression valueExpression) { // TODO: check memberInfo != null var memberInfo = LuExpressionUtils.GetSingleMemberFromExpression(memberFrom); StaticMemberConverters.Add(memberInfo, new LuObjectConverterDescriptorMemberInfo { ValueExpression = LuExpressionUtils.GetFromConvert(valueExpression) }); } protected void AddStaticMethodConverter(LambdaExpression methodFrom, LambdaExpression valueExpression) { // TODO: check methodInfo != null var methodInfo = LuExpressionUtils.GetSingleMethodFromExpression(methodFrom); StaticMethodConverters.Add(methodInfo, new LuObjectConverterDescriptorMethodInfo { ValueExpression = LuExpressionUtils.GetFromConvert(valueExpression) }); } protected void AddDynamicMethodConverter(LambdaExpression methodFrom, DynamicMethodConverter converter) { // TODO: check methodInfo != null var methodInfo = LuExpressionUtils.GetSingleMethodFromExpression(methodFrom); var genericMethodInfo = methodInfo.GetGenericMethodDefinition(); DynamicMethodConverters.Add(genericMethodInfo, converter); } protected void AddDynamicMethodConverterTemplate(LambdaExpression methodFrom) { AddDynamicMethodConverter(methodFrom, (info, converter) => { var genericMethodInfo = info.GetGenericMethodDefinition(); // TODO Handle converter.ConvertType(type) errors var templateMethodInfo = genericMethodInfo.MakeGenericMethod(info.GetGenericArguments().Select(type => converter.ConvertType(type).Data).ToArray()); var lambdaParams = new List { Expression.Parameter(templateMethodInfo.DeclaringType) // TODO what if DeclaringType is static class }; var methodParams = templateMethodInfo.GetParameters().Select(x => Expression.Parameter(x.ParameterType)).ToList(); lambdaParams.AddRange(methodParams); var methodCallExpression = Expression.Call(templateMethodInfo.IsStatic ? null : lambdaParams[0], templateMethodInfo, methodParams); var body = LuExpressionUtils.GetFromConvert(methodCallExpression); var lambda = Expression.Lambda(body, lambdaParams); return new LuObjectConverterDescriptorMethodInfo { ValueExpression = lambda }; } ); } public LuResult GetMemberValueExpression(MemberInfo memberInfo, ILuObjectConverterDescriptorOptions options) { if (StaticMemberConverters.ContainsKey(memberInfo)) { return LuResult.Ok(StaticMemberConverters[memberInfo].ValueExpression); } return LuResult.Error(LuStatus.InternalError.ToInt(), $"Could not get member value expression from member info {memberInfo}"); } public LuResult GetMethodValueExpression(MethodInfo methodInfo, ILuObjectConverterDescriptorOptions options) { if (StaticMethodConverters.ContainsKey(methodInfo)) { return LuResult.Ok(StaticMethodConverters[methodInfo].ValueExpression); } var genericMethodInfo = methodInfo.GetGenericMethodDefinition(); if (DynamicMethodConverters.ContainsKey(genericMethodInfo)) { var result = DynamicMethodConverters[genericMethodInfo](methodInfo, options.TypeConverter); if (result != null) { return LuResult.Ok(result.ValueExpression); } } return LuResult.Error(LuStatus.InternalError.ToInt(), $"Could not get method value expression from method info {methodInfo}"); } } public class LuObjectConverterDescriptor : LuObjectConverterDescriptor, ILuObjectConverterDescriptor { protected void AddStaticMemberConverter(Expression> memberFrom, Expression> valueExpression) { AddStaticMemberConverter((LambdaExpression) memberFrom, valueExpression); } protected void AddNullMemberConverter(Expression> memberFrom) { var nullExp = Expression.Constant(null, typeof(TType)); var param = Expression.Parameter(typeof(TTypeTo)); var lambda = Expression.Lambda(nullExp, param); AddStaticMemberConverter(memberFrom, lambda); } } }