/*******************************************************************************
* Copyright 2014 JHC Systems Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
package jhc.redsniff.internal.finders;
import jhc.redsniff.core.Describer;
import jhc.redsniff.core.MFinder;
import jhc.redsniff.internal.core.CollectionOf;
import jhc.redsniff.internal.locators.MatcherLocator;
import jhc.redsniff.internal.matchers.FilterResult;
import jhc.redsniff.internal.matchers.MatcherFilter;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.SelfDescribing;
public class MFinderThatHasCondition<E, C> extends BaseMFinder<E, C> {
private final MFinder<E, C> wrappedFinder;
protected final MatcherFilterer<E> matcherFilterer;
private Matcher<? super E> matcher;
protected boolean optimized = false;
public MFinderThatHasCondition(MFinder<E, C> wrappedFinder,
Matcher<? super E> matcher) {
this.wrappedFinder = wrappedFinder;
this.matcher = matcher;
this.matcherFilterer = createMatcherFiltererFor(wrappedFinder, matcher);
}
protected MFinderThatHasCondition(MFinder<E, C> wrappedFinder,
Matcher<? super E> matcher, boolean optimized) {
this.wrappedFinder = wrappedFinder;
this.matcher = matcher;
this.optimized = optimized;
this.matcherFilterer = createMatcherFiltererFor(wrappedFinder, matcher);
}
//if both matcherLocators then specificity wins
//if only one is, then that one wins
// this wins by default
//return true only if other > this
@SuppressWarnings("unchecked")
private boolean isMoreSpecificThanCurrent(
Matcher<? super E> other) {
if (other instanceof MatcherLocator
&& this.matcher instanceof MatcherLocator) {
int thisSpecificity = ((MatcherLocator<E,C>) other).specifity();
int otherSpecificity = ((MatcherLocator<E,C>) this.matcher).specifity();
return thisSpecificity > otherSpecificity ;
} else
return (other instanceof MatcherLocator);
}
@Override
public MFinder<E, C> asOptimizedFinder(){
return wrappedFinder.asOptimizedFinder().optimizedWith(this.matcher);
}
@Override
public MFinder<E, C> optimizedWith(Matcher<? super E> outerMatcher) {
if (isMoreSpecificThanCurrent(outerMatcher))
return ((BaseMFinder<E, C>) wrappedFinder.optimizedWith(outerMatcher)).thatOpt(this.matcher);
else
return ((BaseMFinder<E, C>) wrappedFinder.optimizedWith(this.matcher)).thatOpt(outerMatcher);
}
@Override
public CollectionOf<E> findFrom(C context, Description notFoundDescription) {
Description innerNotFoundDescription = Describer.newDescription();
CollectionOf<E> elements =
wrappedFinder.findFrom(context, innerNotFoundDescription);
FilterResult<E> filterResult =
matcherFilterer.filter(innerNotFoundDescription, elements);
CollectionOf<E> filteredElements = filterResult.foundElements();
if (filteredElements.isEmpty())
notFoundDescription.appendDescriptionOf(filterResult);
return filteredElements;
}
@Override
public void describeTo(Description description) {
wrappedFinder.describeTo(description);
description
.appendText(" that ")
.appendDescriptionOf(matcherFilterer);
}
@Override
public MFinder<E, C> that(Matcher<? super E> elementMatcher) {
return new MFinderThatHasConditionThatHasCondition<>(this, elementMatcher, false);
}
@Override
protected MFinder<E, C> thatOpt(Matcher<? super E> elementMatcher) {
return new MFinderThatHasConditionThatHasCondition<>(this, elementMatcher, true);
}
protected MatcherFilterer<E> createMatcherFiltererFor(
SelfDescribing baseWithoutThisMatcher,
Matcher<? super E> matcher) {
return new SimpleMatcherFilterer<E>(baseWithoutThisMatcher, new MatcherFilter<E>(matcher), optimized);
}
protected void describeAsWrappedTo(Description description) {
wrappedFinder.describeTo(description);
description
.appendText(" that: {")
.appendDescriptionOf(matcherFilterer);
}
private static class MFinderThatHasConditionThatHasCondition<E,C> extends MFinderThatHasCondition<E,C>{
private final MFinderThatHasCondition<E, C> rewrappedFinder;
public MFinderThatHasConditionThatHasCondition(MFinderThatHasCondition<E, C> rewrappedFinder,
Matcher<? super E> matcher, boolean optimized) {
super(rewrappedFinder, matcher, true);
this.rewrappedFinder = rewrappedFinder;
}
@Override
protected void describeAsWrappedTo(Description description) {
rewrappedFinder
.describeAsWrappedTo(description);
description
.appendText(" and ")
.appendDescriptionOf(matcherFilterer);
}
@Override
public void describeTo(Description description) {
rewrappedFinder
.describeAsWrappedTo(description);
description
.appendText(" and ")
.appendDescriptionOf(matcherFilterer)
.appendText("}");
}
@Override
protected MatcherFilterer<E> createMatcherFiltererFor(
SelfDescribing baseWithoutThisMatcher,
Matcher<? super E> matcher) {
return new WrappingMatcherFilterer<E>(baseWithoutThisMatcher, new MatcherFilter<E>(matcher), this.optimized);
}
}
}