// Path: src/main/java/com/lastcalc/parsers/UserDefinedParserParser.java
// public static class UserDefinedParser extends Parser {
// 	private static final long serialVersionUID = -4928516936219533258L;
// 
// 	public final TokenList after;
// 
// 	private final TokenList template;
// 
// 	private final TokenList before;
// 
// 	public final Set<String> variables;
// 
// 	public UserDefinedParser(final TokenList before, final TokenList after, final Set<String> variables) {
// 		this.before = before;
// 		this.after = after;
// 		this.variables = variables;
// 		final List<Object> tpl = Lists.newArrayList();
// 
// 		for (final Object o : before) {
// 			if (variables.contains(o)) {
// 				final String var = (String) o;
// 				if (var.endsWith("List")) {
// 					tpl.add(List.class);
// 				} else if (var.endsWith("Map")) {
// 					tpl.add(Map.class);
// 				} else if (var.endsWith("Num") || var.endsWith("Number")) {
// 					tpl.add(Number.class);
// 				} else if (var.endsWith("Bool") || var.endsWith("Boolean")) {
// 					tpl.add(Boolean.class);
// 				} else if (var.endsWith("Amount")) {
// 					tpl.add(Amount.class);
// 				} else if (var.endsWith("Fun") || var.endsWith("Function")) {
// 					tpl.add(UserDefinedParser.class);
// 					tpl.add(Amount.class);
// 				} else {
// 					tpl.add(Object.class);
// 				}
// 			} else if (o instanceof String) {
// 				tpl.add(o);
// 			} else if (o instanceof MapWithTail || o instanceof Map) {
// 				tpl.add(Map.class);
// 			} else if (o instanceof ListWithTail || o instanceof List) {
// 				tpl.add(List.class);
// 			} else {
// 				tpl.add(o.getClass());
// 			}
// 		}
// 		template = TokenList.create(tpl);
// 
// 	}
// 
// 	@Override
// 	public ParseResult parse(final TokenList tokens, final int templatePos, final ParserContext context) {
// 		if (tokens.get(PreParser.findEdgeOrObjectBackwards(tokens, templatePos, "then")).equals("then"))
// 			return ParseResult.fail();
// 
// 		final List<Object> result = Lists.newArrayListWithCapacity(after.size() + 2);
// 		final boolean useBrackets = tokens.size() > template.size();
// 		if (useBrackets) {
// 			result.add("(");
// 		}
// 		final TokenList input = tokens.subList(templatePos, templatePos + template.size());
// 		final Map<String, Object> varMap = Maps.newHashMapWithExpectedSize(variables.size());
// 		try {
// 			bind(before, input, variables, varMap);
// 			for (final Object o : after) {
// 				final Object val = varMap.get(o);
// 				if (val != null) {
// 					result.add(val);
// 				} else {
// 					result.add(o);
// 				}
// 			}
// 		} catch (final BindException e) {
// 			return ParseResult.fail();
// 		}
// 		if (useBrackets) {
// 			result.add(")");
// 		}
// 		final TokenList resultTL = TokenList.create(result);
// 		final TokenList flattened = PreParser.flatten(resultTL);
// 		return ParseResult.success(
// 				tokens.replaceWithTokenList(templatePos, templatePos + template.size(), flattened),
// 				Math.min(0, -flattened.size())
// 				);
// 	}
// 
// 	@Override
// 	public TokenList getTemplate() {
// 		return template;
// 	}
// 
// 	@Override
// 	public String toString() {
// 		return before + " = " + after;
// 	}
// 
// 	@Override
// 	public int hashCode() {
// 		final int prime = 31;
// 		int result = 1;
// 		result = prime * result + ((after == null) ? 0 : after.hashCode());
// 		result = prime * result + ((before == null) ? 0 : before.hashCode());
// 		return result;
// 	}
// 
// 	@Override
// 	public boolean equals(final Object obj) {
// 		if (this == obj)
// 			return true;
// 		if (obj == null)
// 			return false;
// 		if (!(obj instanceof UserDefinedParser))
// 			return false;
// 		final UserDefinedParser other = (UserDefinedParser) obj;
// 		if (after == null) {
// 			if (other.after != null)
// 				return false;
// 		} else if (!after.equals(other.after))
// 			return false;
// 		if (before == null) {
// 			if (other.before != null)
// 				return false;
// 		} else if (!before.equals(other.before))
// 			return false;
// 		return true;
// 	}
// 
// 	public boolean hasVariables() {
// 		return !variables.isEmpty();
// 	}
// }


import java.util.*;
import com.lastcalc.parsers.*;
import com.lastcalc.parsers.UserDefinedParserParser.UserDefinedParser;
package com.lastcalc.engines;



/**
 * A set for parsers where the UserDefinedParser that shortens the token
 * list most comes first.  For use in ParserPickerFactories.
 * 
 * @author Ian Clarke <ian.clarke@gmail.com>
 *
 */
public class ParserSet extends TreeSet<Parser> {
	private static final long serialVersionUID = -6285593762627218550L;

	public ParserSet() {
		super(new Comparator<Parser>() {

			@Override
			public int compare(final Parser o1, final Parser o2) {
				if (o1 instanceof UserDefinedParser && !(o2 instanceof UserDefinedParser))
					return -1;
				else if (o2 instanceof UserDefinedParser && !(o1 instanceof UserDefinedParser))
					return 1;
				else if (o1 instanceof UserDefinedParser && o2 instanceof UserDefinedParser) {
					final UserDefinedParser udp1 = (UserDefinedParser) o1;
					final UserDefinedParser udp2 = (UserDefinedParser) o2;
					final int sizeRed1 = udp1.after.size() - udp1.getTemplate().size();
					final int sizeRed2 = udp2.after.size() - udp2.getTemplate().size();
// Path: src/main/java/com/lastcalc/parsers/UserDefinedParserParser.java
// public static class UserDefinedParser extends Parser {
// 	private static final long serialVersionUID = -4928516936219533258L;
// 
// 	public final TokenList after;
// 
// 	private final TokenList template;
// 
// 	private final TokenList before;
// 
// 	public final Set<String> variables;
// 
// 	public UserDefinedParser(final TokenList before, final TokenList after, final Set<String> variables) {
// 		this.before = before;
// 		this.after = after;
// 		this.variables = variables;
// 		final List<Object> tpl = Lists.newArrayList();
// 
// 		for (final Object o : before) {
// 			if (variables.contains(o)) {
// 				final String var = (String) o;
// 				if (var.endsWith("List")) {
// 					tpl.add(List.class);
// 				} else if (var.endsWith("Map")) {
// 					tpl.add(Map.class);
// 				} else if (var.endsWith("Num") || var.endsWith("Number")) {
// 					tpl.add(Number.class);
// 				} else if (var.endsWith("Bool") || var.endsWith("Boolean")) {
// 					tpl.add(Boolean.class);
// 				} else if (var.endsWith("Amount")) {
// 					tpl.add(Amount.class);
// 				} else if (var.endsWith("Fun") || var.endsWith("Function")) {
// 					tpl.add(UserDefinedParser.class);
// 					tpl.add(Amount.class);
// 				} else {
// 					tpl.add(Object.class);
// 				}
// 			} else if (o instanceof String) {
// 				tpl.add(o);
// 			} else if (o instanceof MapWithTail || o instanceof Map) {
// 				tpl.add(Map.class);
// 			} else if (o instanceof ListWithTail || o instanceof List) {
// 				tpl.add(List.class);
// 			} else {
// 				tpl.add(o.getClass());
// 			}
// 		}
// 		template = TokenList.create(tpl);
// 
// 	}
// 
// 	@Override
// 	public ParseResult parse(final TokenList tokens, final int templatePos, final ParserContext context) {
// 		if (tokens.get(PreParser.findEdgeOrObjectBackwards(tokens, templatePos, "then")).equals("then"))
// 			return ParseResult.fail();
// 
// 		final List<Object> result = Lists.newArrayListWithCapacity(after.size() + 2);
// 		final boolean useBrackets = tokens.size() > template.size();
// 		if (useBrackets) {
// 			result.add("(");
// 		}
// 		final TokenList input = tokens.subList(templatePos, templatePos + template.size());
// 		final Map<String, Object> varMap = Maps.newHashMapWithExpectedSize(variables.size());
// 		try {
// 			bind(before, input, variables, varMap);
// 			for (final Object o : after) {
// 				final Object val = varMap.get(o);
// 				if (val != null) {
// 					result.add(val);
// 				} else {
// 					result.add(o);
// 				}
// 			}
// 		} catch (final BindException e) {
// 			return ParseResult.fail();
// 		}
// 		if (useBrackets) {
// 			result.add(")");
// 		}
// 		final TokenList resultTL = TokenList.create(result);
// 		final TokenList flattened = PreParser.flatten(resultTL);
// 		return ParseResult.success(
// 				tokens.replaceWithTokenList(templatePos, templatePos + template.size(), flattened),
// 				Math.min(0, -flattened.size())
// 				);
// 	}
// 
// 	@Override
// 	public TokenList getTemplate() {
// 		return template;
// 	}
// 
// 	@Override
// 	public String toString() {
// 		return before + " = " + after;
// 	}
// 
// 	@Override
// 	public int hashCode() {
// 		final int prime = 31;
// 		int result = 1;
// 		result = prime * result + ((after == null) ? 0 : after.hashCode());
// 		result = prime * result + ((before == null) ? 0 : before.hashCode());
// 		return result;
// 	}
// 
// 	@Override
// 	public boolean equals(final Object obj) {
// 		if (this == obj)
// 			return true;
// 		if (obj == null)
// 			return false;
// 		if (!(obj instanceof UserDefinedParser))
// 			return false;
// 		final UserDefinedParser other = (UserDefinedParser) obj;
// 		if (after == null) {
// 			if (other.after != null)
// 				return false;
// 		} else if (!after.equals(other.after))
// 			return false;
// 		if (before == null) {
// 			if (other.before != null)
// 				return false;
// 		} else if (!before.equals(other.before))
// 			return false;
// 		return true;
// 	}
// 
// 	public boolean hasVariables() {
// 		return !variables.isEmpty();
// 	}
// }


// Path: src/main/java/com/lastcalc/engines/ParserSet.java
import java.util.*;
import com.lastcalc.parsers.*;
import com.lastcalc.parsers.UserDefinedParserParser.UserDefinedParser;

package com.lastcalc.engines;



/**
 * A set for parsers where the UserDefinedParser that shortens the token
 * list most comes first.  For use in ParserPickerFactories.
 * 
 * @author Ian Clarke <ian.clarke@gmail.com>
 *
 */
public class ParserSet extends TreeSet<Parser> {
	private static final long serialVersionUID = -6285593762627218550L;

	public ParserSet() {
		super(new Comparator<Parser>() {

			@Override
			public int compare(final Parser o1, final Parser o2) {
				if (o1 instanceof UserDefinedParser && !(o2 instanceof UserDefinedParser))
					return -1;
				else if (o2 instanceof UserDefinedParser && !(o1 instanceof UserDefinedParser))
					return 1;
				else if (o1 instanceof UserDefinedParser && o2 instanceof UserDefinedParser) {
					final UserDefinedParser udp1 = (UserDefinedParser) o1;
					final UserDefinedParser udp2 = (UserDefinedParser) o2;
					final int sizeRed1 = udp1.after.size() - udp1.getTemplate().size();
					final int sizeRed2 = udp2.after.size() - udp2.getTemplate().size();
					return compareInts(sizeRed1, sizeRed2, compareInts(o1.hashCode(), o2.hashCode(), 0));