package org.hamcrest;

/**
 
* A Condition implements part of a multi-step match. We sometimes need to write matchers
 
* that have a sequence of steps, where each step depends on the result of the previous
 
* step and we can stop processing as soon as a step fails. These classes provide
 
* infrastructure for writing such a sequence.
 
*
 
* Based on https://github.com/npryce/maybe-java
 
* @author Steve Freeman 2012 http://www.hamcrest.com
 
*/


public abstract class Condition<T> {
    
public static final NotMatched<Object> NOT_MATCHED = new NotMatched<Object>();

    
public interface Step<I, O> {
        
Condition<O> apply(I value, Description mismatch);
    
}

    
private Condition() { }

    
public abstract boolean matching(Matcher<T> match, String message);
    
public abstract <U> Condition<U> and(Step<? super T, U> mapping);

    
public final boolean matching(Matcher<T> match) { return matching(match, ""); }
    
public final <U> Condition<U> then(Step<? super T, U> mapping) { return and(mapping); }

    
@SuppressWarnings("unchecked")
    
public static <T> Condition<T> notMatched() {
        
return (Condition<T>) NOT_MATCHED;
    
}

    
public static <T> Condition<T> matched(final T theValue, final Description mismatch) {
        
return new Matched<T>(theValue, mismatch);
    
}

    
private static final class Matched<T> extends Condition<T> {
        
private final T theValue;
        
private final Description mismatch;

        
private Matched(T theValue, Description mismatch) {
            
this.theValue = theValue;
            
this.mismatch = mismatch;
        
}

        
@Override
        
public boolean matching(Matcher<T> matcher, String message) {
            
if (matcher.matches(theValue)) {
                
return true;
            
}
            
mismatch.appendText(message);
            
matcher.describeMismatch(theValue, mismatch);
            
return false;
        
}

        
@Override
        
public <U> Condition<U> and(Step<? super T, U> next) {
            
return next.apply(theValue, mismatch);
        
}
    
}

    
private static final class NotMatched<T> extends Condition<T> {
        
@Override public boolean matching(Matcher<T> match, String message) { return false; }

        
@Override public <U> Condition<U> and(Step<? super T, U> mapping) {
            
return notMatched();
        
}
    
}
}