package com.dhemery.express;

import org.hamcrest.Matcher;
import org.hamcrest.SelfDescribing;

import java.util.function.BooleanSupplier;
import java.util.function.Function;
import java.util.function.Predicate;

/**
 * Expressive methods to evaluate composed conditions.
 *
 * @see PolledExpressions
 * @see Named
 */

public interface Expressions {
    /**
     * Assert that the condition is satisfied.
     *
     * @param condition
     *         the condition to evaluate
     */
    static <C extends BooleanSupplier & SelfDescribing>
    void assertThat(C condition) {
        if (!condition.getAsBoolean())
            throw new AssertionError(Diagnosis.of(condition));
    }

    /**
     * Assert that the predicate accepts the subject.
     *
     * @param <T>
     *         the type of the subject
     * @param subject
     *         the subject to evaluate
     * @param predicate
     *         the predicate that evaluates the subject
     */
    static <T, P extends Predicate<? super T> & SelfDescribing>
    void assertThat(T subject, P predicate) {
        if (!predicate.test(subject))
            throw new AssertionError(Diagnosis.of(subject, predicate));
    }

    /**
     * Assert that the matcher accepts the subject.
     *
     * @param <T>
     *         the type of the subject
     * @param subject
     *         the subject to evaluate
     * @param matcher
     *         the matcher that evaluates the subject
     */
    static <T>
    void assertThat(T subject, Matcher<? super T> matcher) {
        if (!matcher.matches(subject))
            throw new AssertionError(Diagnosis.of(subject, matcher));
    }

    /**
     * Assert that the predicate accepts the value that the function derives
     * from the subject.
     *
     * @param <T>
     *         the type of the subject
     * @param <R>
     *         the type of the result of the function
     * @param subject
     *         the subject to evaluate
     * @param function
     *         the function that derives the value of interest
     * @param predicate
     *         the predicate that evaluates the derived value
     */
    static <T, R, F extends Function<? super T, R> & SelfDescribing, P extends Predicate<? super R> & SelfDescribing>
    void assertThat(T subject, F function, P predicate) {
        R value = function.apply(subject);
        if (!predicate.test(value))
            throw new AssertionError(Diagnosis.of(subject, function, predicate, value));
    }

    /**
     * Assert that the matcher accepts the value that the function derives from
     * the subject.
     *
     * @param <T>
     *         the type of the subject
     * @param <R>
     *         the type of the result of the function
     * @param subject
     *         the subject to evaluate
     * @param function
     *         the function that derives the value of interest
     * @param matcher
     *         the matcher that evaluates the derived value
     */
    static <T, F extends Function<? super T, R> & SelfDescribing, R>
    void assertThat(T subject, F function, Matcher<? super R> matcher) {
        R value = function.apply(subject);
        if (!matcher.matches(value))
            throw new AssertionError(Diagnosis.of(subject, function, matcher, value));
    }

    /**
     * Indicate whether the condition is satisfied.
     *
     * @param condition
     *         the condition to evaluate
     */
    static boolean satisfiedThat(BooleanSupplier condition) {
        return condition.getAsBoolean();
    }

    /**
     * Indicate whether the predicate accepts the subject.
     *
     * @param <T>
     *         the type of the subject
     * @param subject
     *         the subject to evaluate
     * @param predicate
     *         the predicate that evaluates the subject
     */
    static <T>
    boolean satisfiedThat(T subject, Predicate<? super T> predicate) {
        return predicate.test(subject);
    }

    /**
     * Indicate whether the matcher accepts the subject.
     *
     * @param <T>
     *         the type of the subject
     * @param subject
     *         the subject to evaluate
     * @param matcher
     *         the matcher that evaluates the subject
     */
    static <T>
    boolean satisfiedThat(T subject, Matcher<? super T> matcher) {
        return matcher.matches(subject);
    }

    /**
     * Indicate whether the predicate accepts the value that the function
     * derives from the subject.
     *
     * @param <T>
     *         the type of the subject
     * @param <R>
     *         the type of the result of the function
     * @param subject
     *         the subject to evaluate
     * @param function
     *         the function that derives the value of interest
     * @param predicate
     *         the predicate that evaluates the derived value
     */
    static <T, R>
    boolean satisfiedThat(T subject, Function<? super T, R> function, Predicate<? super R> predicate) {
        return predicate.test(function.apply(subject));
    }

    /**
     * Indicate whether the matcher accepts the value that the function derives
     * from the subject.
     *
     * @param <T>
     *         the type of the subject
     * @param <R>
     *         the type of the result of the function
     * @param subject
     *         the subject to evaluate
     * @param function
     *         the function that derives the value of interest
     * @param matcher
     *         the matcher that evaluates the derived value
     */
    static <T, R>
    boolean satisfiedThat(T subject, Function<? super T, R> function, Matcher<? super R> matcher) {
        return matcher.matches(function.apply(subject));
    }
}

@@ -55,44 +55,8 @@
 her;
-%0Aimport org.hamcrest.SelfDescribing;
 %0A%0Aim
@@ -458,74 +458,53 @@
 tic 
-%3CC extends BooleanSupplier & SelfDescribing%3E%0A    void assertThat(C
+void assertThat(SelfDescribingBooleanSupplier
  con
@@ -914,91 +914,71 @@
 c %3CT
-, P extends Predicate%3C? super T%3E & SelfDescribing%3E%0A    void assertThat(T subject, P
+%3E void assertThat(T subject, SelfDescribingPredicate%3C? super T%3E
  pre
@@ -1387,20 +1387,16 @@
 atic %3CT%3E
-%0A   
  void as
@@ -2064,28 +2064,59 @@
 ic %3CT, R
-, F extends 
+%3E void assertThat(T subject, SelfDescribing
 Function
@@ -2122,33 +2122,41 @@
 n%3C? super T, R%3E 
-&
+function,
  SelfDescribing,
@@ -2158,20 +2158,8 @@
 bing
-, P extends 
 Pred
@@ -2178,71 +2178,8 @@
 r R%3E
- & SelfDescribing%3E%0A    void assertThat(T subject, F function, P
  pre
@@ -2863,94 +2863,74 @@
 %3CT, 
-F extends Function%3C? super T, R%3E & SelfDescribing, R%3E%0A    void assertThat(T subject, F
+R%3E void assertThat(T subject, SelfDescribingFunction%3C? super T, R%3E
  fun

Remove multiple bindings from Expressions parameter types.