using System.Linq.Expressions;
namespace langguanApi.Extensions
{
    /// 
    /// linq extension
    /// 
    public static class WhereIfExtension
    {
        public static IQueryable WhereIf(this IQueryable source, bool condition, Expression> predicate)
        {
            return condition ? source.Where(predicate) : source;
        }
        public static IQueryable WhereIf(this IQueryable source, Expression> predicate, bool condition)
        {
            return condition ? source.Where(predicate) : source;
        }
        public static IEnumerable WhereIf(this IEnumerable source, bool condition, Func predicate)
        {
            return condition ? source.Where(predicate) : source;
        }
        public static Expression> And(
        this Expression> first,
        Expression> second)
        {
            return first.AndAlso(second, Expression.AndAlso);
        }
        /// 
        /// 合并表达式以及参数
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        private static Expression> AndAlso(
        this Expression> expr1,
        Expression> expr2,
        Func func)
        {
            var parameter = Expression.Parameter(typeof(T));
            var leftVisitor = new ReplaceExpressionVisitor(expr1.Parameters[0], parameter);
            var left = leftVisitor.Visit(expr1.Body);
            var rightVisitor = new ReplaceExpressionVisitor(expr2.Parameters[0], parameter);
            var right = rightVisitor.Visit(expr2.Body);
            return Expression.Lambda>(
                func(left, right), parameter);
        }
        private class ReplaceExpressionVisitor
: ExpressionVisitor
        {
            private readonly Expression _oldValue;
            private readonly Expression _newValue;
            public ReplaceExpressionVisitor(Expression oldValue, Expression newValue)
            {
                _oldValue = oldValue;
                _newValue = newValue;
            }
            public override Expression Visit(Expression node)
            {
                if (node == _oldValue)
                    return _newValue;
                return base.Visit(node);
            }
        }
    }
}