/// <summary>Uses the subject for rule violation.</summary>
        /// <typeparam name="TContext">The type of the context.</typeparam>
        /// <typeparam name="TSubject">The type of the subject.</typeparam>
        /// <typeparam name="TContextObject">The type of the context object.</typeparam>
        /// <param name="ruleBuilder">The rule builder.</param>
        /// <param name="propertyExpression">The property expression.</param>
        /// <returns>A Context Object Provider Rule Builder.</returns>
        public static IContextObjectProviderRuleBuilder <TContext, TSubject, TContextObject> UseSubjectForRuleViolation <TContext, TSubject, TContextObject> (
            this IContextObjectProviderRuleBuilder <TContext, TSubject, TContextObject> ruleBuilder,
            Expression <Func <TSubject, object> > propertyExpression)
            where TContext : RuleEngineContext <TSubject>
        {
            ruleBuilder.ElseThen(
                (s, ctx) =>
            {
                var failedConstraints = ctx.WorkingMemory.GetContextObject <List <IConstraint> > (ruleBuilder.Rule.Name);
                foreach (var constraint in failedConstraints)
                {
                    if (!(constraint is IHandleAddingRuleViolations))
                    {
                        var propertyName = ctx.NameProvider.GetName(s, propertyExpression);

                        var formatedMessage = constraint.Message.FormatRuleEngineMessage(propertyName);

                        var ruleViolation = new RuleViolation(
                            ruleBuilder.Rule,
                            s,
                            formatedMessage,
                            PropertyUtil.ExtractPropertyName(propertyExpression));
                        ctx.RuleViolationReporter.Report(ruleViolation);
                    }
                }
                failedConstraints.Clear();
            });
            return(ruleBuilder);
        }
 /// <summary>
 /// Adds an <see cref="InlineConstraint{TContextObject}"/> to the Rule.
 /// </summary>
 /// <typeparam name="TContext">The type of the context.</typeparam>
 /// <typeparam name="TSubject">The type of the subject.</typeparam>
 /// <typeparam name="TContextObject">The type of the context object.</typeparam>
 /// <param name="ruleBuilder">The rule builder.</param>
 /// <param name="predicate">The predicate.</param>
 /// <param name="message">The message.</param>
 /// <returns>A <see cref="IContextObjectProviderRuleBuilder{TContext,TSubject,TContextObject}"/></returns>
 public static IContextObjectProviderRuleBuilder <TContext, TSubject, TContextObject> Constrain <TContext, TSubject, TContextObject> (
     this IContextObjectProviderRuleBuilder <TContext, TSubject, TContextObject> ruleBuilder, Predicate <object> predicate, string message)
     where TContext : RuleEngineContext <TSubject>
 {
     ruleBuilder.Constrain(new InlineConstraint <object> (predicate, message));
     return(ruleBuilder);
 }
        /// <summary>
        /// Adds a WhenClause to the rule checking for duplicates, and Adds A ThenCluase that will report the violation if it occurs.
        /// </summary>
        /// <typeparam name="TContext">The type of the context.</typeparam>
        /// <typeparam name="TSubject">The type of the subject.</typeparam>
        /// <typeparam name="TContextObject">The type of the context object.</typeparam>
        /// <param name="ruleBuilder">The rule builder.</param>
        /// <param name="collectionFunc">The collection func.</param>
        /// <returns>A <see cref="IRuleBuilder{TContext,TSubject}"/></returns>
        public static IRuleBuilder <TContext, TSubject> NoDuplicates <TContext, TSubject, TContextObject> (
            this IContextObjectProviderRuleBuilder <TContext, TSubject, TContextObject> ruleBuilder,
            Func <TContext, IEnumerable <TContextObject> > collectionFunc)
            where TContext : RuleEngineContext <TSubject>
        {
            if (ruleBuilder.Constraints.Count() > 0)
            {
                throw new InvalidRuleException("Cannot use NoDuplicates after a constraint has already been added to the Rule.");
            }

            return(ruleBuilder.When(
                       (s, ctx) =>
            {
                var collection = collectionFunc(ctx);
                var contextObject = ruleBuilder.GetContextObject(ctx.WorkingMemory);
                bool isDuplicate;
                if (contextObject is IValuesEquatable)
                {
                    var aggregateNodeValueObject = (contextObject as IValuesEquatable);
                    isDuplicate = collection.Any(item => aggregateNodeValueObject.ValuesEqual(item));
                }
                else
                {
                    isDuplicate = collection.Any(item => item.Equals(contextObject));
                }
                return isDuplicate;
            })
                   .ThenReportRuleViolation(
                       (s, ctx) =>
                       string.Format(
                           "Cannot have duplicate {0}.", ctx.NameProvider.GetName(ruleBuilder.GetContextObject(ctx.WorkingMemory)))));
        }
 /// <summary>
 /// Adds an <see cref="InlineConstraint{TProperty}"/> of GreaterThan todays date to the Rule.
 /// </summary>
 /// <typeparam name="TContext">Type of <see cref="IRuleEngineContext"/> of the rule.</typeparam>
 /// <typeparam name="TSubject">Type of subject of the rule.</typeparam>
 /// <typeparam name="TContextObject">Type of property of the subject of the rule.</typeparam>
 /// <param name="ruleBuilder"><see cref="IContextObjectProviderRuleBuilder{TContext,TSubject,TContextObject}"/> currently configuring the rule.</param>
 /// <returns>A <see cref="IContextObjectProviderRuleBuilder{TContext,TSubject,TContextObject}"/></returns>
 public static IContextObjectProviderRuleBuilder <TContext, TSubject, TContextObject> CannotBeFutureDate <TContext, TSubject, TContextObject> (
     this IContextObjectProviderRuleBuilder <TContext, TSubject, TContextObject> ruleBuilder)
     where TContext : RuleEngineContext <TSubject>
 {
     ruleBuilder.GreaterThan(DateTime.Today);
     return(ruleBuilder);
 }
        /// <summary>
        /// Adds an <see cref="InlineConstraint{TContextObject}"/> of MinLength to the Rule.
        /// </summary>
        /// <typeparam name="TContext">Type of <see cref="IRuleEngineContext"/> of the rule.</typeparam>
        /// <typeparam name="TSubject">Type of subject of the rule.</typeparam>
        /// <typeparam name="TContextObject">Type of property of the subject of the rule.</typeparam>
        /// <param name="ruleBuilder"><see cref="IContextObjectProviderRuleBuilder{TContext,TSubject,TContextObject}"/> currently configuring the rule.</param>
        /// <param name="minLength">Min Length property value can be.</param>
        /// <returns>A <see cref="IContextObjectProviderRuleBuilder{TContext,TSubject,TContextObject}"/></returns>
        public static IContextObjectProviderRuleBuilder <TContext, TSubject, TContextObject> MinLength <TContext, TSubject, TContextObject> (
            this IContextObjectProviderRuleBuilder <TContext, TSubject, TContextObject> ruleBuilder, int minLength)
            where TContext : RuleEngineContext <TSubject>
        {
            var message = Messages.Constraint_MinLength_Message.FormatCompareRuleEngineMessage(minLength, string.Empty);

            ruleBuilder.Constrain(new InlineConstraint <object> (lhs => lhs.ToString().Length >= minLength, message));
            return(ruleBuilder);
        }
 /// <summary>
 /// Adds a WhenClause to the rule that checks the context object against a rule collection that returns true if a rule violation occurs from rule collection.
 /// </summary>
 /// <typeparam name="TContext">The type of the context.</typeparam>
 /// <typeparam name="TSubject">The type of the subject.</typeparam>
 /// <typeparam name="TContextObject">The type of the context object.</typeparam>
 /// <param name="ruleBuilder">The rule builder.</param>
 /// <param name="ruleCollection">The rule collection.</param>
 /// <param name="ruleSelector">The rule selector.</param>
 /// <returns>
 /// A <see cref="IRuleBuilder{TContext,TSubject}"/>
 /// </returns>
 public static IRuleBuilder <TContext, TSubject> WithCollection <TContext, TSubject, TContextObject> (
     this IContextObjectProviderRuleBuilder <TContext, TSubject, TContextObject> ruleBuilder,
     IRuleCollection <TContextObject> ruleCollection,
     IRuleSelector ruleSelector = null)
     where TContext : RuleEngineContext <TSubject>
 {
     ruleBuilder.Constrain(new RuleCollectionConstraint <TContextObject> (ruleCollection, ruleSelector));
     return(ruleBuilder);
 }
        /// <summary>
        /// Adds an <see cref="InlineConstraint{TContextObject}"/> of NotEqualTo to the Rule.
        /// </summary>
        /// <typeparam name="TContext">Type of <see cref="IRuleEngineContext"/> of the rule.</typeparam>
        /// <typeparam name="TSubject">Type of subject of the rule.</typeparam>
        /// <typeparam name="TContextObject">Type of property of the subject of the rule.</typeparam>
        /// <param name="ruleBuilder"><see cref="IContextObjectProviderRuleBuilder{TContext,TSubject,TContextObject}"/> currently configuring the rule.</param>
        /// <param name="compareValue">Value to compare to value of property.</param>
        /// <returns>A <see cref="IContextObjectProviderRuleBuilder{TContext,TSubject,TContextObject}"/></returns>
        public static IContextObjectProviderRuleBuilder <TContext, TSubject, TContextObject> NotEqualTo <TContext, TSubject, TContextObject> (
            this IContextObjectProviderRuleBuilder <TContext, TSubject, TContextObject> ruleBuilder, IComparable compareValue)
            where TContext : RuleEngineContext <TSubject>
        {
            var message = Messages.Constraints_Comparison_Message.FormatCompareRuleEngineMessage(compareValue, "!=");

            ruleBuilder.Constrain(new InlineConstraint <object> (lhs => compareValue.CompareTo(lhs) != 0, message));
            return(ruleBuilder);
        }
 /// <summary>
 /// Adds a propertyExpression to the Context Object in the Rule Builder.
 /// </summary>
 /// <typeparam name="TContext">The type of the context.</typeparam>
 /// <typeparam name="TSubject">The type of the subject.</typeparam>
 /// <typeparam name="TContextObject">The type of the context object.</typeparam>
 /// <param name="ruleBuilder">The rule builder.</param>
 /// <param name="propertyExpression">The property expression.</param>
 /// <returns>A <see cref="IContextObjectProviderRuleBuilder{TContext,TSubject,TContextObject}"/></returns>
 public static IContextObjectProviderRuleBuilder <TContext, TSubject, TContextObject> WithProperty <TContext, TSubject, TContextObject> (
     this IContextObjectProviderRuleBuilder <TContext, TSubject, TContextObject> ruleBuilder,
     Expression <Func <TContextObject, object> > propertyExpression)
     where TContext : RuleEngineContext <TSubject>
 {
     return(new ContextObjectProviderRuleBuilder <TContext, TSubject, TContextObject> (
                ruleBuilder.Rule as Rule,
                ruleBuilder.ContextObjectName,
                propertyExpression));
 }
        /// <summary>
        /// Adds an <see cref="InlineConstraint{TContextObject}"/> of Regex Match to the Rule.
        /// </summary>
        /// <typeparam name="TContext">Type of <see cref="IRuleEngineContext"/> of the rule.</typeparam>
        /// <typeparam name="TSubject">Type of subject of the rule.</typeparam>
        /// <typeparam name="TContextObject">Type of property of the subject of the rule.</typeparam>
        /// <param name="ruleBuilder"><see cref="IContextObjectProviderRuleBuilder{TContext,TSubject,TContextObject}"/> currently configuring the rule.</param>
        /// <param name="regexString">Regex string to check match on property value.</param>
        /// <returns>A <see cref="IContextObjectProviderRuleBuilder{TContext,TSubject,TContextObject}"/></returns>
        public static IContextObjectProviderRuleBuilder <TContext, TSubject, TContextObject> MatchesRegex <TContext, TSubject, TContextObject> (
            this IContextObjectProviderRuleBuilder <TContext, TSubject, TContextObject> ruleBuilder, string regexString)
            where TContext : RuleEngineContext <TSubject>
        {
            var message =
                Messages.Constraints_Regex_Message.FormatRuleEngineMessage(new Dictionary <string, string> {
                { "RegexString", regexString }
            });

            ruleBuilder.Constrain(new InlineConstraint <object> (lhs => Regex.IsMatch(lhs.ToString(), regexString), message));
            return(ruleBuilder);
        }
        /// <summary>
        /// Adds an <see cref="InlineConstraint{TContextObject}"/> of Specification to the Rule.
        /// </summary>
        /// <typeparam name="TContext">Type of <see cref="IRuleEngineContext"/> of the rule.</typeparam>
        /// <typeparam name="TSubject">Type of subject of the rule.</typeparam>
        /// <typeparam name="TContextObject">Type of property of the subject of the rule.</typeparam>
        /// <param name="ruleBuilder"><see cref="IContextObjectProviderRuleBuilder{TContext,TSubject,TContextObject}"/> currently configuring the rule.</param>
        /// <param name="specification"><see cref="ISpecification{TEntity}"/> to use in Constraint.</param>
        /// <param name="violationMessage">Violation message to use in Constraint.</param>
        /// <returns>A <see cref="IContextObjectProviderRuleBuilder{TContext,TSubject,TContextObject}"/></returns>
        public static IContextObjectProviderRuleBuilder <TContext, TSubject, TContextObject> MeetsSpecification <TContext, TSubject, TContextObject> (
            this IContextObjectProviderRuleBuilder <TContext, TSubject, TContextObject> ruleBuilder,
            ISpecification <object> specification,
            string violationMessage = null) where TContext : RuleEngineContext <TSubject>
        {
            var message = violationMessage
                          ??
                          Messages.Constraint_Specification_Message.FormatRuleEngineMessage(
                new Dictionary <string, string> {
                { "Specification", specification.ToString() }
            });

            ruleBuilder.Constrain(new InlineConstraint <object> (specification.IsSatisfiedBy, message));
            return(ruleBuilder);
        }
        /// <summary>
        /// Adds an <see cref="InlineConstraint{TContextObject}"/> of ExclusiveBetween to the Rule.
        /// </summary>
        /// <typeparam name="TContext">Type of <see cref="IRuleEngineContext"/> of the rule.</typeparam>
        /// <typeparam name="TSubject">Type of subject of the rule.</typeparam>
        /// <typeparam name="TContextObject">Type of property of the subject of the rule.</typeparam>
        /// <param name="ruleBuilder"><see cref="IContextObjectProviderRuleBuilder{TContext,TSubject,TContextObject}"/> currently configuring the rule.</param>
        /// <param name="startValue">Start Value to use in comparison to property value.</param>
        /// <param name="endValue">End Value to use in comparison to property value.</param>
        /// <returns>A <see cref="IContextObjectProviderRuleBuilder{TContext,TSubject,TContextObject}"/></returns>
        public static IContextObjectProviderRuleBuilder <TContext, TSubject, TContextObject> ExclusiveBetween <TContext, TSubject, TContextObject> (
            this IContextObjectProviderRuleBuilder <TContext, TSubject, TContextObject> ruleBuilder,
            IComparable startValue,
            IComparable endValue) where TContext : RuleEngineContext <TSubject>
        {
            var message =
                Messages.Constraints_ExclusiveBetween_Message.FormatRuleEngineMessage(
                    new Dictionary <string, string> {
                { "StartValue", startValue.ToString() }, { "EndValue", startValue.ToString() }
            });

            ruleBuilder.Constrain(
                new InlineConstraint <object> (lhs => startValue.CompareTo(lhs) < 0 && endValue.CompareTo(lhs) > 0, message));
            return(ruleBuilder);
        }
 /// <summary>
 /// Adds a <see cref="NotEmptyConstraint"/> to the Rule.
 /// </summary>
 /// <typeparam name="TContext">Type of <see cref="IRuleEngineContext"/> of the rule.</typeparam>
 /// <typeparam name="TSubject">Type of subject of the rule.</typeparam>
 /// <typeparam name="TContextObject">Type of property of the subject of the rule.</typeparam>
 /// <param name="ruleBuilder"><see cref="IContextObjectProviderRuleBuilder{TContext,TSubject,TContextObject}"/> currently configuring the rule.</param>
 /// <returns>A <see cref="IContextObjectProviderRuleBuilder{TContext,TSubject,TContextObject}"/></returns>
 public static IContextObjectProviderRuleBuilder <TContext, TSubject, TContextObject> NotEmpty <TContext, TSubject, TContextObject> (
     this IContextObjectProviderRuleBuilder <TContext, TSubject, TContextObject> ruleBuilder) where TContext : RuleEngineContext <TSubject>
 {
     ruleBuilder.Constrain(new NotEmptyConstraint());
     return(ruleBuilder);
 }