package se.fnord.jamon;

import java.util.HashSet;

public class Matchers {

	public static Matcher not(final Matcher matcher) {
		return new Matcher() {
			@Override
            public boolean match(char ch) {
				return !matcher.match(ch);
            }
		};
	}

	public static Matcher not(char ... chars) {
		return not(match(chars));
	}

	public static Matcher and(final Matcher ... matchers) {
		return new Matcher() {
			@Override
            public boolean match(char ch) {
				for (Matcher matcher : matchers)
					if (!matcher.match(ch))
						return false;
				return true;
            }
		};
	}

	public static Matcher or(final Matcher ... matchers) {
		return new Matcher() {
			@Override
            public boolean match(char ch) {
				for (Matcher matcher : matchers)
					if (matcher.match(ch))
						return true;
				return false;
            }
		};
	}

	public static Matcher newline() {
		return match('\r', '\n');
	}

	public static Matcher letter() {
		return new Matcher() {
			@Override
			public boolean match(char ch) {
				return Character.isLetter(ch);
			}

			@Override
			public String toString() {
			    return "match[alpha]";
			}
		};
	}

	public static Matcher white() {
		return new Matcher() {
			@Override
			public boolean match(char ch) {
				return Character.isWhitespace(ch) && ch != '\n' && ch != '\r';
			}

			@Override
			public String toString() {
			    return "match[white]";
			}
		};
	}

	public static Matcher identifierStart() {
		return new Matcher() {
			@Override
			public boolean match(char ch) {
				return Character.isJavaIdentifierStart(ch);
			}

			@Override
			public String toString() {
			    return "match[identifierStart]";
			}
		};
	}

	public static Matcher identifierPart() {
		return new Matcher() {
			@Override
			public boolean match(char ch) {
				return Character.isJavaIdentifierPart(ch);
			}

			@Override
			public String toString() {
			    return "match[identifierPart]";
			}
		};
	}

	public static Matcher upper() {
		return new Matcher() {
			@Override
			public boolean match(char ch) {
				return Character.isUpperCase(ch);
			}

			@Override
			public String toString() {
			    return "match[uppercase]";
			}
		};
	}

	public static Matcher lower() {
		return new Matcher() {
			@Override
			public boolean match(char ch) {
				return Character.isLowerCase(ch);
			}

			@Override
			public String toString() {
			    return "match[lowercase]";
			}
		};
	}

	public static Matcher digit() {
		return new Matcher() {
			@Override
			public boolean match(char ch) {
				return Character.isDigit(ch);
			}

			@Override
			public String toString() {
			    return "match[digits]";
			}
		};
	}

	public static Matcher digit(final int radix) {
		return new Matcher() {
			@Override
			public boolean match(char ch) {
				return Character.digit(ch, radix) != -1;
			}

			@Override
			public String toString() {
			    return "match[digits of base " + radix + "]";
			}
		};
	}

	public static Matcher control() {
		return new Matcher() {
			@Override
			public boolean match(char ch) {
				return Character.isISOControl(ch);
			}

			@Override
			public String toString() {
				return "match[control]";
			}
		};
	}

	public static Matcher match(char ...chars) {
		final HashSet<Character> characters = new HashSet<Character>(chars.length);
		for (char ch : chars)
			characters.add(ch);
		return new Matcher() {
			@Override
            public boolean match(char ch) {
	            return characters.contains(ch);
            }

			@Override
			public String toString() {
				return "match[" + characters + "]";
			}
		};
	}
}

@@ -18,16 +18,41 @@
 jamon;%0A%0A
+import java.util.Arrays;%0A
 import j
@@ -69,16 +69,16 @@
 ashSet;%0A
-
 %0Apublic 
@@ -265,32 +265,112 @@
 );%0A            %7D
+%0A%0A%09%09%09@Override%0A%09%09%09public String toString() %7B%0A%09%09%09%09return %22not(%22+matcher+%22)%22;%0A%09%09%09%7D
 %0A%09%09%7D;%0A%09%7D%0A%0A%09publi
@@ -687,32 +687,130 @@
 e;%0A            %7D
+%0A%0A%09%09%09@Override%0A%09%09%09public String toString() %7B%0A%09%09%09%09return %22and(%22+Arrays.toString(matchers)+%22)%22;%0A%09%09%09%7D
 %0A%09%09%7D;%0A%09%7D%0A%0A%09publi
@@ -1043,16 +1043,16 @@
  false;%0A
-
         
@@ -1056,16 +1056,113 @@
        %7D
+%0A%0A%09%09%09@Override%0A%09%09%09public String toString() %7B%0A%09%09%09%09return %22or(%22+Arrays.toString(matchers)+%22)%22;%0A%09%09%09%7D
 %0A%09%09%7D;%0A%09%7D

Implement toString() on all Matchers