package de.onyxbits.tradetrax.services; import java.math.BigDecimal; import java.text.NumberFormat; import java.text.ParseException; import java.util.Currency; import java.util.Locale; import de.onyxbits.jbee.Evaluator; /** * Handles internal and external representation of monetary values as well as * parsing user input. * <p> * Since floating point numbers are prone to loss of precision, all money values * are stored as integers in the database. Fractional values are dealt with by * scaling the money value according to the number of fractional digits of the * desired currency. * * @author patrick * */ public class MoneyRepresentationImpl implements MoneyRepresentation { private NumberFormat numberFormat; private NumberFormat numberFormatPrecise; private String currencySymbol; private SettingsStore settingsStore; /** * Create a new converter * * @param decimals * number of digits after the decimal point. * * @param symbol * currency symbol to use * * @param suffixSymbol * whether to append or prepend the currency symbol. */ public MoneyRepresentationImpl(SettingsStore settings) { this.settingsStore = settings; Locale locale = Locale.getDefault(); Currency c = Currency.getInstance(locale); numberFormat = NumberFormat.getInstance(locale); numberFormat.setMinimumFractionDigits(c.getDefaultFractionDigits()); numberFormat.setMaximumFractionDigits(c.getDefaultFractionDigits()); numberFormatPrecise = NumberFormat.getInstance(locale); numberFormatPrecise.setMinimumFractionDigits(c.getDefaultFractionDigits()); numberFormatPrecise.setMaximumFractionDigits(4); currencySymbol = c.getSymbol(); } /* * (non-Javadoc) * * @see de.onyxbits.tradetrax.services.MoneyRepresention#getCurrencySymbol() */ public String getCurrencySymbol() { return settingsStore.get(SettingsStore.CURRENCYSYMBOL, currencySymbol); } /* * (non-Javadoc) * * @see * de.onyxbits.tradetrax.services.MoneyRepresention#userToDatabase(java.lang * .String, int) */ public synchronized long userToDatabase(String value, int units) throws ParseException { if (value == null) { return 0; } try { Evaluator e = new Evaluator(); BigDecimal val = e.evaluateOrThrow(value); if (units!=0) { val=val.divide(new BigDecimal(units)); } return val.multiply(new BigDecimal(FACTOR)).longValue(); } catch (Exception e) { throw new ParseException(value,0); } } /* * (non-Javadoc) * * @see de.onyxbits.tradetrax.services.MoneyRepresention#databaseToUser(long, * boolean, boolean) */ public synchronized String databaseToUser(long value, boolean precise, boolean addSymbol) { String ret = "BUG!"; checkSettings(); if (precise) { ret = numberFormatPrecise.format(((double) value) / FACTOR); } else { ret = numberFormat.format(((double) value) / FACTOR); } if (addSymbol) { // FIXME: This is wrong! Some currencies put the symbol between number and // sign. ret += " " + getCurrencySymbol(); } return ret; } private void checkSettings() { String old = numberFormat.getMaximumFractionDigits() + ""; String digits = settingsStore.get(SettingsStore.DECIMALS, old); if (!old.equals(digits)) { try { int count = Integer.parseInt(digits); numberFormat.setMaximumFractionDigits(count); numberFormat.setMinimumFractionDigits(count); numberFormatPrecise.setMinimumFractionDigits(count); } catch (Exception e) { e.printStackTrace(); } } } }