private static Expression MakeAggreagationCondition(FilterNodeModel node, Dictionary <string, ParameterExpression> parameters, IBusinessReflector reflector, Expression parent, Type elementType, Expression filter)
        {
            var expression = parent;

            if (filter != null)
            {
                var whereMethod = typeof(Enumerable).GetMethods().Single(x => x.Name == nameof(Enumerable.Where) &&
                                                                         x.GetParameters().Last().ParameterType.GetGenericArguments().Length == 2);
                whereMethod = whereMethod.MakeGenericMethod(elementType);
                expression  = Expression.Call(null, whereMethod, expression, filter);
            }

            if (node.Operator == FilterOperator.Count)
            {
                var method = typeof(Enumerable).GetMethods().Single(x => x.Name == nameof(Enumerable.Count) && x.GetParameters().Length == 1);
                method     = method.MakeGenericMethod(elementType);
                expression = Expression.Call(null, method, expression);
            }
            else
            {
                var methodName = node.Operator.ToString();
                var selection  = Visit(node.Children[1], parameters, reflector, parent) as LambdaExpression;
                var method     = typeof(Enumerable).GetMethods().Single(x => x.Name == methodName && x.GetParameters().Length == 2 &&
                                                                        x.GetParameters()[1].ParameterType.GetGenericArguments().Last() == selection.ReturnType);
                method     = method.MakeGenericMethod(elementType);
                expression = Expression.Call(null, method, expression, selection);
            }
            return(expression);
        }
        private FilterNodeModel addFilterInfo(ModelDetailDocumentRequestor mdDR, FilterTypes filterType)
        {
            FilterNodeParser fnParser = new FilterNodeParser(mdDR, filterType);
            FilterNodeModel  fnModel  = fnParser.Parse();

            return(fnModel);
        }
        private static Expression VisitProperty(FilterNodeModel node, Dictionary <string, ParameterExpression> parameters, IBusinessReflector reflector, Expression parent)
        {
            var propertyName = node.PropertyName;
            var property     = Expression.Property(parent, propertyName);

            if (node.Children == null || !node.Children.Any() || node.Children.SingleOrDefault() == null)
            {
                return(property);
            }
            return(Visit(node.Children.Single(), parameters, reflector, property));
        }
        public static LambdaExpression ToExpression(this FilterNodeModel node, IBusinessReflector reflector)
        {
            if (node.NodeType != FilterNodeType.Lambda)
            {
                throw new Exception();
            }
            var parameters = new Dictionary <string, ParameterExpression>();
            var expression = Visit(node, parameters, reflector, null);

            return(expression as LambdaExpression);
        }
        private static Expression VisitConstant(FilterNodeModel node, Type type)
        {
            if (node.Values.Length == 1)
            {
                return(Constant(node.Values[0], type));
            }
            var list = Activator.CreateInstance(typeof(List <>).MakeGenericType(type));
            var add  = list.GetType().GetMethod(nameof(IList.Add));

            foreach (var val in node.Values)
            {
                add.Invoke(list, new object[] { ConvertValue(val, type) });
            }
            return(Constant(list, list.GetType()));
        }
        private static Expression VisitLambda(FilterNodeModel node, Dictionary <string, ParameterExpression> parameters, IBusinessReflector reflector, Expression parent)
        {
            if (!parameters.TryGetValue(node.ParameterName, out var parameter))
            {
                parameter = Expression.Parameter(reflector.GetType(node.DataType), node.ParameterName);
                parameters.Add(node.ParameterName, parameter);
            }
            else
            {
                if (parameter.Type != reflector.GetType(node.DataType))
                {
                    throw new Exception("Parameter names are re-used with incompatible types");
                }
            }
            var body = Visit(node.Children[0], parameters, reflector, parameter);

            return(Expression.Lambda(body, parameter));
        }
        private void addFilters(ModelPageCollectorSet modelPageSet, RowModel rm)
        {
            ModelDetailDocumentRequestor mdDR = (ModelDetailDocumentRequestor)modelPageSet.Data;
            FilterNodeModel fnModelAir        = addFilterInfo(mdDR, FilterTypes.Air);

            if (!String.IsNullOrEmpty(fnModelAir.Filters))
            {
                rm.AirFilters          = fnModelAir.Filters;
                rm.AirFilterDimensions = addFilterDimensions(fnModelAir.FilterUrls, FilterTypes.Air);
            }

            FilterNodeModel fnModelOil = addFilterInfo(mdDR, FilterTypes.Oil);

            if (!String.IsNullOrEmpty(fnModelOil.Filters))
            {
                rm.OilFilters          = fnModelOil.Filters;
                rm.OilFilterDimensions = addFilterDimensions(fnModelOil.FilterUrls, FilterTypes.Oil);
            }

            FilterNodeModel fnModelFuel = addFilterInfo(mdDR, FilterTypes.Fuel);

            if (!String.IsNullOrEmpty(fnModelFuel.Filters))
            {
                rm.FuelFilters          = fnModelFuel.Filters;
                rm.FuelFilterDimensions = addFilterDimensions(fnModelFuel.FilterUrls, FilterTypes.Fuel);
            }

            FilterNodeModel fnModelInterior = addFilterInfo(mdDR, FilterTypes.Interior);

            if (!String.IsNullOrEmpty(fnModelInterior.Filters))
            {
                rm.InteriorFilters          = fnModelInterior.Filters;
                rm.InteriorFilterDimensions = addFilterDimensions(fnModelInterior.FilterUrls, FilterTypes.Interior);
            }

            FilterNodeModel fnModelOther = addFilterInfo(mdDR, FilterTypes.Other);

            if (!String.IsNullOrEmpty(fnModelOther.Filters))
            {
                rm.OtherFilters          = fnModelOther.Filters;
                rm.OtherFilterDimensions = addFilterDimensions(fnModelOther.FilterUrls, FilterTypes.Other);
            }
        }
 private static Expression SimplifyEqualToBool(FilterNodeModel node, List <Expression> children)
 {
     if (children[0].Type == typeof(bool) || children[0].Type == typeof(bool?))
     {
         if (node.Operator == null)
         {
             return(children[0]);
         }
         if (children.Count == 2)
         {
             if ((node.Operator == FilterOperator.Equal || node.Operator == FilterOperator.NotEqual) && children[1] is ConstantExpression && (children[1] as ConstantExpression).Value is bool)
             {
                 if (node.Operator == FilterOperator.Equal ^ (bool)(children[1] as ConstantExpression).Value)
                 {
                     return(Expression.Not(children[0]));
                 }
                 return(children[0]);
             }
         }
     }
     return(null);
 }
        private static Expression VisitLogical(FilterNodeModel node, Dictionary <string, ParameterExpression> parameters, IBusinessReflector reflector, Expression parent)
        {
            Expression current = null;

            foreach (var child in node.Children)
            {
                var childExpression = Visit(child, parameters, reflector, parent);
                if (current == null)
                {
                    current = childExpression;
                }
                else
                {
                    if (current.Type == typeof(bool) && childExpression.Type == typeof(bool?))
                    {
                        current = ConvertType(current, typeof(bool?));
                    }
                    if (current.Type == typeof(bool?) && childExpression.Type == typeof(bool))
                    {
                        childExpression = ConvertType(childExpression, typeof(bool?));
                    }
                    switch (node.Operator)
                    {
                    case FilterOperator.And:
                        current = Expression.AndAlso(current, childExpression);
                        break;

                    case FilterOperator.Or:
                        current = Expression.OrElse(current, childExpression);
                        break;

                    default:
                        throw new NotImplementedException();
                    }
                }
            }
            return(current);
        }
        private static Expression VisitNavigationList(FilterNodeModel node, Dictionary <string, ParameterExpression> parameters, IBusinessReflector reflector, Expression parent)
        {
            var elementType         = parent.Type.GetGenericArguments().Single();
            LambdaExpression filter = null;

            if (node.Operator != FilterOperator.IsEmpty && node.Operator != FilterOperator.IsNotEmpty && node.Children[0] != null)
            {
                filter = (LambdaExpression)Visit(node.Children[0], parameters, reflector, parent);
                if (filter.ReturnType == typeof(bool?))
                {
                    filter = Expression.Lambda(ConvertType(filter.Body, typeof(bool)), filter.Parameters);
                }
            }

            if (node.Operator == FilterOperator.Count || node.Operator == FilterOperator.Sum || node.Operator == FilterOperator.Average)
            {
                return(MakeAggreagationCondition(node, parameters, reflector, parent, elementType, filter));
            }

            var methodName     = node.Operator == FilterOperator.All ? nameof(Enumerable.All) : nameof(Enumerable.Any);
            var negate         = node.Operator == FilterOperator.None || node.Operator == FilterOperator.IsEmpty;
            var parameterCount = filter == null ? 1 : 2;
            var method         = typeof(Enumerable).GetMethods()
                                 .Single(x => x.Name == methodName && x.GetParameters().Length == parameterCount);

            method = method.MakeGenericMethod(elementType);
            var expression = Expression.Call(method,
                                             parameterCount == 1
                                ? new Expression[] { parent }
                                : new Expression[] { parent, filter });

            if (negate)
            {
                return(Expression.Not(expression));
            }
            return(expression);
        }
        private static Expression Visit(FilterNodeModel node, Dictionary <string, ParameterExpression> parameters, IBusinessReflector reflector, Expression parent)
        {
            switch (node.NodeType)
            {
            case FilterNodeType.Logical:
                return(VisitLogical(node, parameters, reflector, parent));

            case FilterNodeType.Comparison:
            case FilterNodeType.Arithmetic:
                return(VisitOperator(node, parameters, reflector, parent));

            case FilterNodeType.NavigationList:
                return(VisitNavigationList(node, parameters, reflector, parent));

            case FilterNodeType.Lambda:
                return(VisitLambda(node, parameters, reflector, parent));

            case FilterNodeType.Property:
                return(VisitProperty(node, parameters, reflector, parent));

            default:
                throw new NotImplementedException();
            }
        }
 public static Expression <Func <T, bool> > ToExpression <T>(this FilterNodeModel node, IBusinessReflector reflector)
 {
     return(ToExpression(node, reflector) as Expression <Func <T, bool> >);
 }
        private static Expression SimplifyEqualToBool(FilterNodeModel node, List <Expression> children)
        {
            var first = children[0];

            if (first.Type == typeof(bool?))
            {
                if (children.Count == 1)
                {
                    if (node.Operator == null)
                    {
                        return(Expression.Property(first, nameof(Nullable <bool> .Value)));
                    }
                    else if (node.Operator == FilterOperator.IsNull)
                    {
                        Expression.Not(Expression.Property(first, nameof(Nullable <bool> .Value)));
                    }
                    else if (node.Operator == FilterOperator.IsNotNull)
                    {
                        Expression.Property(first, nameof(Nullable <bool> .Value));
                    }
                }
                else if (children.Count == 2)
                {
                    var second = children[1];
                    if (second is ConstantExpression)
                    {
                        var constant = (second as ConstantExpression);
                        if (constant.Value == null)
                        {
                            first = Expression.Property(first, nameof(Nullable <bool> .HasValue));
                            if (node.Operator == FilterOperator.Equal)
                            {
                                return(Expression.Not(first));
                            }
                            return(first);
                        }
                        else if (constant.Value is bool)
                        {
                            first = Expression.Property(first, nameof(Nullable <bool> .Value));
                            if (node.Operator == FilterOperator.Equal ^ (bool)(children[1] as ConstantExpression).Value)
                            {
                                return(Expression.Not(first));
                            }
                            return(first);
                        }
                    }
                }
            }
            if (first.Type == typeof(bool))
            {
                if (node.Operator == null)
                {
                    return(first);
                }
                if (children.Count == 2)
                {
                    if ((node.Operator == FilterOperator.Equal || node.Operator == FilterOperator.NotEqual) && children[1] is ConstantExpression && (children[1] as ConstantExpression).Value is bool)
                    {
                        if (node.Operator == FilterOperator.Equal ^ (bool)(children[1] as ConstantExpression).Value)
                        {
                            return(Expression.Not(first));
                        }
                        return(first);
                    }
                }
            }
            return(null);
        }
        private static Expression VisitOperator(FilterNodeModel node, Dictionary <string, ParameterExpression> parameters, IBusinessReflector reflector, Expression parent)
        {
            var  children = new List <Expression>(node.Children.Length);
            Type type     = null;

            foreach (var child in node.Children)
            {
                if (child.NodeType == FilterNodeType.Constant)
                {
                    children.Add(VisitConstant(child, type));
                }
                else
                {
                    children.Add(Visit(child, parameters, reflector, parent));
                }
                if (children.Count == 1)
                {
                    type = children[0].Type;
                }
            }
            children = UnifyDataTypes(children, null).ToList();
            var simplified = SimplifyEqualToBool(node, children);

            if (simplified != null)
            {
                return(simplified);
            }
            switch (node.Operator)
            {
            case FilterOperator.Contains:
            case FilterOperator.EndsWith:
            case FilterOperator.StartsWith:
                return(MakeStringContainment(node.Operator.Value, children));

            case FilterOperator.Equal:
            case FilterOperator.NotEqual:
            case FilterOperator.IsNull:
            case FilterOperator.IsNotNull:
                return(MakeEquality(node.Operator.Value, children));

            case FilterOperator.GreaterThan:
            case FilterOperator.greaterThanOrEqual:
            case FilterOperator.LessThan:
            case FilterOperator.LessThanOrEqual:
            case FilterOperator.Between:
                if (children[0].Type == typeof(string))
                {
                    return(MakeStringComparison(node.Operator.Value, children));
                }
                return(MakeComparison(node.Operator.Value, children));

            case FilterOperator.Abs:
                return(MakeUnaryArithmetic(node.Operator.Value, children.Single()));

            case FilterOperator.Add:
            case FilterOperator.Multiply:
                return(MakeMultyArithmetic(node.Operator.Value, children));

            case FilterOperator.Subtract:
            case FilterOperator.Divide:
            case FilterOperator.Power:
            case FilterOperator.Log:
                return(MakeBinaryArithmetic(node.Operator.Value, children));

            default:
                throw new NotImplementedException();
            }
        }