package mulCal.equationParser;
import java.math.BigDecimal;
import java.text.ParseException;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import mulCal.calendar.Calendar;
import mulCal.currency.Currency;
import mulCal.equationParser.Tokenize.Token;
import mulCal.equationParser.Tokenize.TokenType;
import mulCal.history.History;
import mulCal.util.KeyException;
import static mulCal.equationParser.Tokenize.startWithNumber;
import static mulCal.main.util.removeQuotes;
public class EvalSpecial {
public static final Map<String, BigDecimal> constants;
static {
Map<String, BigDecimal> tmpMap = new HashMap<String, BigDecimal>();
tmpMap.put("PI", new BigDecimal("3.14159265"));
tmpMap.put("E", new BigDecimal("2.71828183"));
constants = Collections.unmodifiableMap(tmpMap);
}
private Currency currency;
public EvalSpecial(Currency currency) {
this.currency = currency;
}
public List<Token> eval(List<Token> tokens, History history) throws KeyException, ParseException {
List<Token> result = new LinkedList<Token>();
for (Token tok : tokens) {
if (tok.type == TokenType.VARIABLE) {
result.add(evalVariable(tok, history));
} else if (tok.type == TokenType.SPECIAL) {
result.add(evalSpecialForm(tok, tokens, history));
} else {
result.add(tok);
}
}
return result;
}
private Token evalVariable(Token tok, History history) throws KeyException {
if (constants.containsKey(tok.text)) {
return new Token(TokenType.NUMBER, constants.get(tok.text).toString());
} else {
return new Token(TokenType.NUMBER, history.get(tok.text).result.toString());
}
}
private Token evalSpecialForm(Token tok, List<Token> tokens, History history) throws KeyException, ParseException {
// it comes in these forms:
// [m 15 USD YEN]
// [m A USD YEN]
// [d weeks 2010/2/4 2010/2/11]
// parse the first as a number or variable then evalVariable if needed
// make sure both currencies are in the list.
// call convert
// return the result as a token
String[] parts = removeQuotes(tok.text).split(" +");
if (parts[0].equals("m")) {
if (parts.length != 4) {
throw new RuntimeException("invalid currency conversion");
}
BigDecimal value;
if(startWithNumber(parts[1])) {
value = new BigDecimal(parts[1]);
} else {
value = new BigDecimal(evalVariable(
new Token(TokenType.NUMBER, parts[1]),
history).text);
}
String from = parts[2];
String to = parts[3];
BigDecimal result = currency.convert(value, from, to);
return new Token(TokenType.NUMBER, result.toPlainString());
} else if (parts[0].equals("d")) {
// [d weeks 2010/2/4 2010/11/29]
String range = parts[1].toLowerCase();
String from = parts[2];
String to = parts[3];
Calendar cal = new Calendar();
cal.setFromDateString(from);
cal.setToDateString(to);
long result;
if (range.equals("days")) {
result = cal.getDateDiff(java.util.Calendar.DAY_OF_MONTH);
} else if (range.equals("weeks")) {
result = cal.getDateDiff(java.util.Calendar.WEEK_OF_YEAR);
} else if (range.equals("months")) {
result = cal.getDateDiff(java.util.Calendar.MONTH);
} else if (range.equals("years")) {
result = cal.getDateDiff(java.util.Calendar.YEAR);
} else {
throw new RuntimeException("invalid calendar range: ".concat(range));
}
return new Token(TokenType.NUMBER, String.format("%d", result));
} else {
throw new RuntimeException("invalid special form: ".concat(parts[0]));
}
}
}