/******************************************************************************* * LastCalc - The last calculator you'll ever need * Copyright (C) 2011, 2012 Uprizer Labs LLC * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published * by the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Affero General Public License for more * details. ******************************************************************************/ package com.lastcalc; import com.google.common.collect.Lists; import com.lastcalc.cache.DocumentWrapper; import com.lastcalc.parsers.UserDefinedParserParser.UserDefinedParser; import com.lastcalc.parsers.amounts.UnitParser; import com.lastcalc.parsers.math.Radix; import org.jscience.economics.money.Currency; import org.jscience.physics.amount.Amount; import org.jsoup.nodes.Element; import org.jsoup.nodes.TextNode; import org.jsoup.parser.Tag; import javax.measure.quantity.Quantity; import javax.measure.quantity.Temperature; import javax.measure.unit.NonSI; import javax.measure.unit.SI; import javax.measure.unit.TransformedUnit; import javax.measure.unit.Unit; import java.text.DecimalFormat; import java.text.Format; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.logging.Level; import java.util.logging.Logger; public class Renderers { private static final Logger log = Logger.getLogger(Renderers.class.getName()); private static Format currencyFormat = new DecimalFormat("###,###.####"); private static ArrayList<String> variableColors = Lists.newArrayList("red", "green", "blue", "orange", "rosy", "pink"); public static Element toHtml(final String baseUri, final TokenList tokens) { return toHtml(baseUri, tokens, Collections.<String, Integer>emptyMap()); } public static Element toHtml(final String baseUri, final TokenList tokens, final Map<String, Integer> variables) { final Element ret = new Element(Tag.valueOf("span"), baseUri); for (final Object obj : tokens) { renderObject(baseUri, variables, ret, obj); } return ret; } private static void renderObject(final String baseUri, final Map<String, Integer> variables, final Element renderTo, final Object obj) { renderTo.append(" "); if (obj instanceof Map) { final Map<Object, Object> map = (Map<Object, Object>) obj; final int mapSize = map.size(); final Element mapSpan = renderTo.appendElement("span").addClass("map"); mapSpan.append("{"); int count = 0; for (final Entry<Object, Object> e : map.entrySet()) { renderObject(baseUri, variables, mapSpan, e.getKey()); mapSpan.append(" :"); renderObject(baseUri, variables, mapSpan, e.getValue()); if (count < mapSize - 1) { mapSpan.append(", "); } count++; } mapSpan.append("}"); final int textLength = mapSpan.text().length(); if (textLength > 120) { mapSpan.html("{ too big (" + textLength + " chars) }"); } } else if (obj instanceof List) { final List<Object> list = (List<Object>) obj; final int listSize = list.size(); final Element listSpan = renderTo.appendElement("span").addClass("map"); listSpan.append("["); int count = 0; for (final Object e : list) { renderObject(baseUri, variables, listSpan, e); if (count < listSize - 1) { listSpan.append(", "); } count++; } listSpan.append("]"); final int textLength = listSpan.text().length(); if (textLength > 120) { listSpan.html("[ too big (" + textLength + " chars) ]"); } } else if (obj instanceof Amount) { final Amount<?> amount = (Amount<?>) obj; Unit<? extends Quantity> unit = amount.getUnit(); log.log(Level.INFO, "Amount: " + amount + ", unit type: " + unit.getClass().getCanonicalName()); final Element amountSpan = renderTo.appendElement("span").addClass("amount"); final double estimatedValue = amount.getEstimatedValue(); if (unit instanceof Currency) { final Element currencySpan = amountSpan.appendElement("span").addClass("currency"); final Currency currency = (Currency) unit; if (currency.getCode().equalsIgnoreCase("USD")) { currencySpan.html("US$" + currencyFormat.format(estimatedValue)); } else if (currency.getCode().equalsIgnoreCase("GBP")) { currencySpan.html("£" + currencyFormat.format(estimatedValue)); } else if (currency.getCode().equalsIgnoreCase("EUR")) { currencySpan.html("€" + currencyFormat.format(estimatedValue)); } else if (currency.getCode().equalsIgnoreCase("JPY")) { currencySpan.html("¥" + currencyFormat.format(estimatedValue)); } else { currencySpan.text(currencyFormat.format(estimatedValue) + currency.getCode()); } } else if (unit.equals(NonSI.FAHRENHEIT) || unit.equals(SI.CELSIUS) || unit.equals(SI.KELVIN)) { // Avoid "33 fahrenheits" final Element temperatureSpan = amountSpan.appendElement("span").addClass("temperature"); temperatureSpan.text(estimatedValue + unit.toString()); } else { final String numStr = Misc.numberFormat.format(estimatedValue); amountSpan.appendElement("span").addClass("number").text(numStr); amountSpan.appendText(" "); if (!unit.equals(Unit.ONE)) { final Element unitSpan = amountSpan.appendElement("span").addClass("recognized"); final String verboseName = estimatedValue == 1.0 ? UnitParser.verboseNamesSing.get(unit) : UnitParser.verboseNamesPlur.get(unit); if (verboseName != null) { unitSpan.text(verboseName); } else { unitSpan.text(unit.toString()); } } } } else if (obj instanceof org.jscience.mathematics.number.Number) { final org.jscience.mathematics.number.Number<?> num = (org.jscience.mathematics.number.Number<?>) obj; final String numStr = Misc.numberFormat.format(num.doubleValue()); renderTo.appendElement("span").addClass("number").text(numStr); } else if (obj instanceof Radix) { renderTo.appendElement("span").addClass("number").text(obj.toString()); } else if (obj instanceof UserDefinedParser) { renderTo.appendChild(toHtml(baseUri, ((UserDefinedParser) obj).after)); } else if (variables.containsKey(obj)) { final String color = variableColors.get(variables.get(obj) % variableColors.size()); renderTo.appendElement("span").addClass("highlighted").addClass("variable").addClass(color) .text((String) obj); } else if (obj instanceof String && Character.isUpperCase(((String) obj).charAt(0))) { renderTo.appendElement("span").addClass("highlighted").addClass("variable").addClass("white") .text((String) obj); } else if (obj instanceof DocumentWrapper) { renderTo.append("<html>" + ((DocumentWrapper) obj).title() + " ... </html>"); } else { renderTo.appendChild(new TextNode(obj.toString(), baseUri)); } } }