package scaffolding;

import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeDiagnosingMatcher;

import java.util.List;

public class ExactCountMatcher extends TypeSafeDiagnosingMatcher<List<String>> {
    private final Matcher<String> stringMatcher;
    private int expectedCount;

    private ExactCountMatcher(Matcher<String> stringMatcher, int expectedCount) {
        this.stringMatcher = stringMatcher;
        this.expectedCount = expectedCount;
    }

    @Override
    protected boolean matchesSafely(List<String> items, Description mismatchDescriptor) {
        int count = 0;
        for (String item : items) {
            if (stringMatcher.matches(item)) {
                count++;
            }
        }
        boolean okay = count == expectedCount;
        if (!okay) {
            mismatchDescriptor.appendText("was matched " + count + " times in the following list:");
            String separator = String.format("%n") + "          ";
            mismatchDescriptor.appendValueList(separator, separator, "", items);

        }
        return okay;
    }

    @Override
    public void describeTo(Description description) {
        description.appendDescriptionOf(stringMatcher).appendText(" " + expectedCount + " times");
    }

    public static Matcher<? super List<String>> noneOf(Matcher<String> stringMatcher) {
        return new ExactCountMatcher(stringMatcher, 0);
    }

    public static Matcher<? super List<String>> oneOf(Matcher<String> stringMatcher) {
        return new ExactCountMatcher(stringMatcher, 1);
    }

    public static Matcher<? super List<String>> twoOf(Matcher<String> stringMatcher) {
        return new ExactCountMatcher(stringMatcher, 2);
    }

    public static Matcher<? super List<String>> threeOf(Matcher<String> stringMatcher) {
        return new ExactCountMatcher(stringMatcher, 3);
    }
    
    public static Matcher<? super List<String>> fourOf(Matcher<String> stringMatcher) {
        return new ExactCountMatcher(stringMatcher, 4);
    }
}
