package org.hamcrest;

import org.hamcrest.internal.ReflectiveTypeFinder;

/**
 
* Supporting class for matching a feature of an object. Implement <code>featureValueOf()</code>
 
* in a subclass to pull out the feature to be matched against.
 
*
 
* @param <T> The type of the object to be matched
 
* @param <U> The type of the feature to be matched
 
*/

public abstract class FeatureMatcher<T, U> extends TypeSafeDiagnosingMatcher<T> {
  
private static final ReflectiveTypeFinder TYPE_FINDER = new ReflectiveTypeFinder("featureValueOf", 1, 0);
  
private final Matcher<? super U> subMatcher;
  
private final String featureDescription;
  
private final String featureName;
  

  
/**
   
* Constructor
   
* @param subMatcher The matcher to apply to the feature
   
* @param featureDescription Descriptive text to use in describeTo
   
* @param featureName Identifying text for mismatch message
   
*/

  
public FeatureMatcher(Matcher<? super U> subMatcher, String featureDescription, String featureName) {
    
super(TYPE_FINDER);
    
this.subMatcher = subMatcher;
    
this.featureDescription = featureDescription;
    
this.featureName = featureName;
  
}
  

  
/**
   
* Implement this to extract the interesting feature.
   
* @param actual the target object
   
* @return the feature to be matched
   
*/

  
protected abstract U featureValueOf(T actual);

  
@Override
  
protected boolean matchesSafely(T actual, Description mismatch) {
    
final U featureValue = featureValueOf(actual);
    
if (!subMatcher.matches(featureValue)) {
      
mismatch.appendText(featureName).appendText(" ");
      
subMatcher.describeMismatch(featureValue, mismatch);
      
return false;
    
}
    
return true;
  
}
      

  
@Override
  
public final void describeTo(Description description) {
    
description.appendText(featureDescription).appendText(" ")
               
.appendDescriptionOf(subMatcher);
  
}
}