package fitnesse.wikitext.parser;
import fitnesse.html.HtmlUtil;
import java.util.Calendar;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class FormattedExpression {
public static final Pattern formatParser = Pattern.compile("^[ \\t]*((%[-#+ 0,(]*[0-9.]*([a-zA-Z])[^: \\t]*)[ \\t]*:)?[ \\t]*(.*)$");
private String input;
private String format;
private char conversion = '?';
private String expression;
private Maybe<String> formatLocale;
private Locale locale;
public FormattedExpression(String input, Maybe<String> formatLocale) {
this.input = input;
this.formatLocale = formatLocale;
}
public Maybe<String> evaluate() {
parseFormat();
selectLocale();
return !expression.isEmpty() ? evaluateAndFormat() : new Maybe<>("");
}
private void selectLocale() {
if(formatLocale.isNothing() || formatLocale.getValue().isEmpty()) {
locale = Locale.getDefault();
} else {
locale = Locale.forLanguageTag(formatLocale.getValue());
}
}
private void parseFormat() {
Matcher match = formatParser.matcher(input);
if (match.find()) { //match.group(1) is an outer group.
format = (match.group(2) == null) ? null : match.group(2).trim();
conversion = (match.group(3) == null) ? '?' : match.group(3).trim().charAt(0);
expression = (match.group(4) == null) ? "" : match.group(4).trim();
} else {
format = null;
expression = input.trim();
}
}
private Maybe<String> evaluateAndFormat() {
Maybe<Double> evaluation = (new Expression(expression)).evaluate();
if (evaluation.isNothing()) {
return Maybe.nothingBecause("invalid expression: " + expression);
}
Double result = evaluation.getValue();
Long iResult = Math.round(result);
if (format == null)
return new Maybe<>(result.equals(iResult.doubleValue()) ? iResult.toString() : result.toString());
if ("aAdhHoOxX".indexOf(conversion) >= 0) //...use the integer
return new Maybe<>(String.format(locale, format, iResult));
if ("bB".indexOf(conversion) >= 0) //...use boolean
return new Maybe<>(result == 0.0 ? "false" : "true");
if ("sScC".indexOf(conversion) >= 0) { //...string & character formatting; use the double
String sString;
boolean isInt = result.equals(iResult.doubleValue());
if (isInt)
sString = String.format(locale, format, iResult.toString());
else
sString = String.format(locale, format, result.toString());
return new Maybe<>(sString.replaceAll(" ", HtmlUtil.NBSP.html()));
}
if ("tT".indexOf(conversion) >= 0) { //...date
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(iResult);
return new Maybe<>(String.format(locale, format, cal.getTime()));
}
if ("eEfgG".indexOf(conversion) >= 0) //...use the double
return new Maybe<>(String.format(locale, format, result));
return Maybe.nothingBecause("invalid format: " + format);
}
}