public static MutatorsConfigurator <TRoot, TChild, TValue> Required <TRoot, TChild, TValue>(
            this MutatorsConfigurator <TRoot, TChild, TValue> configurator,
            Expression <Func <TChild, TValue, MultiLanguageTextBase> > message,
            int priority = 0,
            ValidationResultType type = ValidationResultType.Error)
        {
            var methodReplacer = new MethodReplacer(MutatorsHelperFunctions.EachMethod, MutatorsHelperFunctions.CurrentMethod);
            var pathToValue    = (Expression <Func <TRoot, TValue> >)methodReplacer.Visit(configurator.PathToValue);
            var pathToChild    = (Expression <Func <TRoot, TChild> >)methodReplacer.Visit(configurator.PathToChild);

            configurator.SetMutator(RequiredIfConfiguration.Create(MutatorsCreator.Sharp, priority, null, pathToValue, message.Merge(pathToChild, pathToValue), type));
            return(configurator);
        }
        protected StaticValidatorConfiguration(Type type, MutatorsCreator creator, string name, int priority,
                                               LambdaExpression condition, LambdaExpression pathToNode, LambdaExpression pathToValue, LambdaExpression validator)
            : base(type, creator, priority)
        {
            Name      = name;
            Condition = condition;
            var replacer = new MethodReplacer(MutatorsHelperFunctions.EachMethod, MutatorsHelperFunctions.CurrentMethod);

            PathToNode        = (LambdaExpression)replacer.Visit(pathToNode);
            PathToValue       = (LambdaExpression)replacer.Visit(pathToValue);
            validator         = Prepare(validator);
            this.validator    = validator;
            validatorFromRoot = pathToNode.Merge(validator);
        }
        public static MutatorsConfigurator <TRoot, TChild, string> IsLike <TRoot, TChild>(
            this MutatorsConfigurator <TRoot, TChild, string> configurator,
            string pattern,
            Expression <Func <TChild, MultiLanguageTextBase> > message,
            int priority = 0,
            ValidationResultType type = ValidationResultType.Error)
        {
            var methodReplacer = new MethodReplacer(MutatorsHelperFunctions.EachMethod, MutatorsHelperFunctions.CurrentMethod);
            var pathToValue    = (Expression <Func <TRoot, string> >)methodReplacer.Visit(configurator.PathToValue);
            var pathToChild    = (Expression <Func <TRoot, TChild> >)methodReplacer.Visit(configurator.PathToChild);

            configurator.SetMutator(RegexValidatorConfiguration.Create(MutatorsCreator.Sharp, priority, pathToValue, null, pathToChild.Merge(message), pattern, type));
            return(configurator);
        }
        public static MutatorsConfigurator <TRoot, TChild, TValue> MustBeEqualTo <TRoot, TChild, TValue>(
            this MutatorsConfigurator <TRoot, TChild, TValue> configurator,
            Expression <Func <TChild, TValue> > expectedValue,
            Expression <Func <TChild, MultiLanguageTextBase> > message,
            int priority = 0,
            ValidationResultType type = ValidationResultType.Error)
        {
            var methodReplacer = new MethodReplacer(MutatorsHelperFunctions.EachMethod, MutatorsHelperFunctions.CurrentMethod);
            var pathToValue    = (Expression <Func <TRoot, TValue> >)methodReplacer.Visit(configurator.PathToValue);
            var pathToChild    = (Expression <Func <TRoot, TChild> >)methodReplacer.Visit(configurator.PathToChild);
            var condition      = Expression.Convert(Expression.NotEqual(pathToValue.ReplaceParameter(pathToChild.Parameters[0]).Body, pathToChild.Merge(expectedValue).Body), typeof(bool?));

            configurator.SetMutator(InvalidIfConfiguration.Create(MutatorsCreator.Sharp, priority, Expression.Lambda <Func <TRoot, bool?> >(condition, pathToChild.Parameters), pathToChild.Merge(message), type));
            return(configurator);
        }
        private static IEnumerable <Expression> GetArrays(Type rootType, Expression path, IEnumerable <MutatorConfiguration> mutators)
        {
            var arrays          = new List <Dictionary <Type, List <Expression> > >();
            var arraysExtractor = new ArraysExtractor(arrays);

            arraysExtractor.GetArrays(path);
            foreach (var mutator in mutators)
            {
                mutator.GetArrays(arraysExtractor);
            }
            var result   = new List <Expression>();
            var replacer = new MethodReplacer(MutatorsHelperFunctions.CurrentMethod, MutatorsHelperFunctions.EachMethod);

            for (var i = 1; i < arrays.Count; ++i)
            {
                var dict = arrays[i];
                if (dict.Count > 1)
                {
                    throw new InvalidOperationException("Too many root types");
                }
                List <Expression> list;
                if (!dict.TryGetValue(rootType, out list))
                {
                    throw new InvalidOperationException("Invalid root type");
                }
                var arraysOfCurrentLevel = list.GroupBy(exp => new ExpressionWrapper(replacer.Visit(exp), false)).Select(grouping => grouping.First()).ToArray();
                if (arraysOfCurrentLevel.Length > 1)
                {
                    throw new NotSupportedException("Iteration over more than one array is not supported");
                }
                result.Add(arraysOfCurrentLevel[0]);
            }

            return(result);
        }
        public static MutatorsConfigurator <TRoot, TChild, TValue> IfFilledMustBelongTo <TRoot, TChild, TValue>(
            this MutatorsConfigurator <TRoot, TChild, TValue> configurator,
            IEnumerable <TValue> values,
            Expression <Func <TChild, TValue, MultiLanguageTextBase> > message,
            int priority = 0,
            ValidationResultType type = ValidationResultType.Error)
        {
            var methodReplacer = new MethodReplacer(MutatorsHelperFunctions.EachMethod, MutatorsHelperFunctions.CurrentMethod);
            var pathToValue    = (Expression <Func <TRoot, TValue> >)methodReplacer.Visit(configurator.PathToValue);
            var pathToChild    = (Expression <Func <TRoot, TChild> >)methodReplacer.Visit(configurator.PathToChild);
            var contains       = Expression.Call(containsMethod.MakeGenericMethod(typeof(TValue)), Expression.Constant(values), pathToValue.Body);
            var condition      = Expression.Convert(Expression.AndAlso(Expression.NotEqual(pathToValue.Body, Expression.Constant(null, typeof(TValue))), Expression.Not(contains)), typeof(bool?));

            configurator.SetMutator(InvalidIfConfiguration.Create(MutatorsCreator.Sharp, priority, Expression.Lambda <Func <TRoot, bool?> >(condition, pathToValue.Parameters), message.Merge(pathToChild, pathToValue), type));
            return(configurator);
        }
        public static MutatorsConfigurator <TRoot, TChild, TValue> MustBeEqualTo <TRoot, TChild, TValue>(
            this MutatorsConfigurator <TRoot, TChild, TValue> configurator,
            Expression <Func <TChild, TValue> > expectedValue,
            IEqualityComparer <TValue> comparer = null,
            int priority = 0,
            ValidationResultType type = ValidationResultType.Error)
        {
            var methodReplacer = new MethodReplacer(MutatorsHelperFunctions.EachMethod, MutatorsHelperFunctions.CurrentMethod);
            var pathToChild    = (Expression <Func <TRoot, TChild> >)methodReplacer.Visit(configurator.PathToChild);
            var pathToValue    = ((Expression <Func <TRoot, TValue> >)methodReplacer.Visit(configurator.PathToValue)).ReplaceParameter(pathToChild.Parameters[0]).Body;
            var equal          = comparer == null
                            ? (Expression)Expression.Equal(pathToValue, pathToChild.Merge(expectedValue).Body)
                            : Expression.Call(Expression.Constant(comparer, typeof(IEqualityComparer <TValue>)), "Equals", Type.EmptyTypes, pathToValue, pathToChild.Merge(expectedValue).Body);
            var condition = Expression.Convert(Expression.Not(equal), typeof(bool?));
            var message   = Expression.MemberInit(Expression.New(typeof(ValueMustBeEqualToText)),
                                                  Expression.Bind(valueMustBeEqualToTextExpectedValueProperty, Expression.Convert(expectedValue.Body, typeof(object))),
                                                  Expression.Bind(valueMustBeEqualToTextActualValueProperty, Expression.Convert(pathToValue, typeof(object))));

            configurator.SetMutator(InvalidIfConfiguration.Create(MutatorsCreator.Sharp, priority, Expression.Lambda <Func <TRoot, bool?> >(condition, pathToChild.Parameters), pathToChild.Merge(Expression.Lambda <Func <TChild, MultiLanguageTextBase> >(message, expectedValue.Parameters)), type));
            return(configurator);
        }
        public static MutatorsConfigurator <TRoot, TChild, TValue> MustBelongTo <TRoot, TChild, TValue>(
            this MutatorsConfigurator <TRoot, TChild, TValue> configurator,
            IEnumerable <TValue> values,
            IEqualityComparer <TValue> comparer = null,
            int priority = 0,
            ValidationResultType type = ValidationResultType.Error)
        {
            var        methodReplacer = new MethodReplacer(MutatorsHelperFunctions.EachMethod, MutatorsHelperFunctions.CurrentMethod);
            var        pathToValue    = (Expression <Func <TRoot, TValue> >)methodReplacer.Visit(configurator.PathToValue);
            var        pathToChild    = (Expression <Func <TRoot, TChild> >)methodReplacer.Visit(configurator.PathToChild);
            Expression contains       = comparer == null
                                      ? Expression.Call(containsMethod.MakeGenericMethod(typeof(TValue)), Expression.Constant(values), pathToValue.Body)
                                      : Expression.Call(containsWithComparerMethod.MakeGenericMethod(typeof(TValue)), Expression.Constant(values), pathToValue.Body, Expression.Constant(comparer));

            var condition = Expression.Convert(Expression.Not(contains), typeof(bool?));
            var message   = Expression.MemberInit(Expression.New(typeof(ValueMustBelongToText)),
                                                  Expression.Bind(typeof(ValueMustBelongToText).GetMember("Value").Single(), pathToValue.Body),
                                                  Expression.Bind(typeof(ValueMustBelongToText).GetMember("Values").Single(), Expression.Constant(values.Cast <object>().ToArray())));

            configurator.SetMutator(InvalidIfConfiguration.Create(MutatorsCreator.Sharp, priority, Expression.Lambda <Func <TRoot, bool?> >(condition, pathToValue.Parameters), Expression.Lambda <Func <TRoot, MultiLanguageTextBase> >(message, pathToChild.Parameters), type));
            return(configurator);
        }
        public static MutatorsConfigurator <TRoot, TChild, string> LengthExactly <TRoot, TChild>(this MutatorsConfigurator <TRoot, TChild, string> configurator, int length, MultiLanguageTextBase title,
                                                                                                 int priority = 0,
                                                                                                 ValidationResultType type = ValidationResultType.Error)
        {
            var methodReplacer = new MethodReplacer(MutatorsHelperFunctions.EachMethod, MutatorsHelperFunctions.CurrentMethod);
            var pathToValue    = (Expression <Func <TRoot, string> >)methodReplacer.Visit(configurator.PathToValue);
            var condition      = Expression.Convert(Expression.NotEqual(Expression.MakeMemberAccess(pathToValue.Body, stringLengthProperty), Expression.Constant(length)), typeof(bool?));
            var message        = Expression.Lambda <Func <TRoot, MultiLanguageTextBase> >(Expression.MemberInit(
                                                                                              Expression.New(typeof(LengthNotExactlyEqualsText)),
                                                                                              Expression.Bind(lengthNotExactlyEqualsTextExacltyProperty, Expression.Constant(length, typeof(int?))),
                                                                                              Expression.Bind(lengthNotExactlyEqualsTextTitleProperty, Expression.Constant(title, typeof(MultiLanguageTextBase))),
                                                                                              Expression.Bind(lengthNotExactlyEqualsTextValueProperty, pathToValue.Body)), pathToValue.Parameters);

            configurator.SetMutator(InvalidIfConfiguration.Create(MutatorsCreator.Sharp, priority, Expression.Lambda <Func <TRoot, bool?> >(condition, pathToValue.Parameters), message, type));
            return(configurator);
        }
        public static ConverterConfigurator <TSourceRoot, TSourceChild, TDestRoot, TDestChild, TTarget> Set <TSourceRoot, TSourceChild, TDestRoot, TDestChild, TTarget>(
            this ConverterConfigurator <TSourceRoot, TSourceChild, TDestRoot, TDestChild, TTarget> configurator,
            Expression <Func <TSourceChild, TTarget> > value)
        {
            var methodReplacer             = new MethodReplacer(MutatorsHelperFunctions.EachMethod, MutatorsHelperFunctions.CurrentMethod);
            var pathToSourceChild          = (Expression <Func <TSourceRoot, TSourceChild> >)methodReplacer.Visit(configurator.PathToSourceChild);
            LambdaExpression valueFromRoot = pathToSourceChild.Merge(value);

            configurator.SetMutator(EqualsToConfiguration.Create(typeof(TDestRoot), valueFromRoot, null));
            return(configurator);
        }
        public static ConverterConfigurator <TSourceRoot, TSourceChild, TDestRoot, TDestChild, TDestValue> Set <TSourceRoot, TSourceChild, TSourceNode, TSourceValue, TDestRoot, TDestChild, TDestValue>(
            this ConverterConfigurator <TSourceRoot, TSourceChild, TDestRoot, TDestChild, TDestValue> configurator,
            Expression <Func <TSourceChild, TSourceNode> > node,
            Expression <Func <TSourceNode, TSourceValue> > value,
            Expression <Func <TSourceValue, TDestValue> > converter,
            Expression <Func <TSourceNode, ValidationResult> > validator,
            int priority = 0)
        {
            var methodReplacer         = new MethodReplacer(MutatorsHelperFunctions.EachMethod, MutatorsHelperFunctions.CurrentMethod);
            var pathToSourceChild      = (Expression <Func <TSourceRoot, TSourceChild> >)methodReplacer.Visit(configurator.PathToSourceChild);
            var nodeFromRoot           = pathToSourceChild.Merge(node);
            var valueFromRoot          = nodeFromRoot.Merge(value);
            var convertedValue         = converter == null ? (LambdaExpression)valueFromRoot : valueFromRoot.Merge(converter);
            var validatorConfiguration = validator == null
                                             ? null
                                             : StaticValidatorConfiguration.Create(MutatorsCreator.Sharp, "SetWithValidator", priority,
                                                                                   null, nodeFromRoot, valueFromRoot, validator);

            configurator.SetMutator(EqualsToConfiguration.Create(typeof(TDestRoot), convertedValue, validatorConfiguration));
            return(configurator);
        }
        public static void BatchSet <TSourceRoot, TSourceChild, TDestRoot, TDestChild, TDestValue>(
            this ConverterConfigurator <TSourceRoot, TSourceChild, TDestRoot, TDestChild, TDestValue> configurator,
            Expression <Func <TDestValue, TSourceChild, Batch> > batch)
        {
            var        methodReplacer    = new MethodReplacer(MutatorsHelperFunctions.EachMethod, MutatorsHelperFunctions.CurrentMethod);
            var        pathToSourceChild = (Expression <Func <TSourceRoot, TSourceChild> >)methodReplacer.Visit(configurator.PathToSourceChild);
            var        pathToChild       = (Expression <Func <TDestRoot, TDestChild> >)methodReplacer.Visit(configurator.PathToChild);
            var        merger            = new ExpressionMerger(pathToSourceChild);
            var        initializers      = ((ListInitExpression)batch.Body).Initializers;
            Expression primaryKeyIsEmpty = null;

            foreach (var initializer in initializers)
            {
                Expression dest        = initializer.Arguments[0];
                var        clearedDest = ClearNotNull(dest);
                if (clearedDest != null)
                {
                    var current = Expression.Equal(clearedDest, Expression.Constant(null, clearedDest.Type));
                    primaryKeyIsEmpty = primaryKeyIsEmpty == null ? current : Expression.AndAlso(primaryKeyIsEmpty, current);
                }

                dest = clearedDest ?? dest;
                if (dest.Type != typeof(object))
                {
                    dest = Expression.Convert(dest, typeof(object));
                }
                Expression source = methodReplacer.Visit(initializer.Arguments[1]);
//                if(source.Type != typeof(object))
//                    source = Expression.Convert(source, typeof(object));
                LambdaExpression value = merger.Merge(Expression.Lambda(source, batch.Parameters[1]));
                if (dest.NodeType == ExpressionType.Convert)
                {
                    dest = ((UnaryExpression)dest).Operand;
                }
                dest = pathToChild.Merge(Expression.Lambda(dest, batch.Parameters[0])).Body;
                configurator.ToRoot().SetMutator(dest, EqualsToConfiguration.Create(typeof(TDestRoot), value, null));
                //configurator.Target(Expression.Lambda<Func<TDestValue, object>>(dest, batch.Parameters[0])).SetMutator(EqualsToConfiguration.Create(typeof(TDestRoot), value, null));
            }

            if (primaryKeyIsEmpty == null)
            {
                return;
            }
            var condition = (Expression <Func <TDestRoot, bool?> >)pathToChild.Merge(Expression.Lambda(Expression.Convert(methodReplacer.Visit(primaryKeyIsEmpty), typeof(bool?)), batch.Parameters[0]));

            foreach (var initializer in initializers)
            {
                Expression dest = initializer.Arguments[0];
                if (ClearNotNull(dest) != null)
                {
                    continue;
                }
                if (dest.Type != typeof(object))
                {
                    dest = Expression.Convert(dest, typeof(object));
                }
                if (dest.NodeType == ExpressionType.Convert)
                {
                    dest = ((UnaryExpression)dest).Operand;
                }
                dest = pathToChild.Merge(Expression.Lambda(dest, batch.Parameters[0])).Body;
                configurator.ToRoot().SetMutator(dest, NullifyIfConfiguration.Create(condition));

                //configurator.Target(Expression.Lambda<Func<TDestValue, object>>(dest, batch.Parameters[0])).SetMutator(NullifyIfConfiguration.Create(condition));
            }
        }