/**
* Copyright (C) 2011 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.web.server.conversion;
import java.math.BigDecimal;
import java.text.DecimalFormatSymbols;
import com.opengamma.util.ArgumentChecker;
/**
* Abstract base class for formatting double values.
*/
public abstract class DoubleValueFormatter {
private static final int GROUP_SIZE = 3;
private static final char PLAIN_STRING_MINUS_SIGN = '-';
private static final char PLAIN_STRING_DECIMAL_SEPARATOR = '.';
private final char _localeDecimalSeparator;
private final char _localeGroupingSeparator;
private final char _localeMinusSign;
private final boolean _plainStringMatchesLocale;
private final boolean _isCurrencyAmount;
public DoubleValueFormatter(boolean isCurrencyAmount) {
this(isCurrencyAmount, DecimalFormatSymbols.getInstance());
}
public DoubleValueFormatter(boolean isCurrencyAmount, DecimalFormatSymbols formatSymbols) {
_localeGroupingSeparator = formatSymbols.getGroupingSeparator();
_localeDecimalSeparator = formatSymbols.getDecimalSeparator();
_localeMinusSign = formatSymbols.getMinusSign();
_plainStringMatchesLocale = _localeMinusSign == PLAIN_STRING_MINUS_SIGN && _localeDecimalSeparator == PLAIN_STRING_DECIMAL_SEPARATOR;
_isCurrencyAmount = isCurrencyAmount;
}
public boolean isCurrencyAmount() {
return _isCurrencyAmount;
}
/**
* Transforms a {@link BigDecimal} value as required, for example setting the scale and
* precision.
*
* @param value the input value, not null
* @return the processed value, not null
*/
protected abstract BigDecimal process(BigDecimal value);
public BigDecimal getRoundedValue(BigDecimal value) {
return process(value);
}
public String format(BigDecimal value) {
BigDecimal processedValue = process(value);
return transformPlainNumberString(processedValue.toPlainString());
}
/**
* Takes a plain number (rounded appropriately, and using '.' as the decimal separator and '-' if negative) and
* applies locale-specific formatting.
*
* @param plainNumberString the plain number, not null
* @return the transformed number, not null
*/
/* package */ String transformPlainNumberString(String plainNumberString) {
// A plain number string is of the form:
// (-)?[0-9]+(\.[0-9]+)?
// i.e. using '-' for negative numbers and '.' as the decimal separator.
ArgumentChecker.notNull(plainNumberString, "plainNumberString");
int decimalIdx = plainNumberString.indexOf(PLAIN_STRING_DECIMAL_SEPARATOR);
boolean isNegative = plainNumberString.charAt(0) == PLAIN_STRING_MINUS_SIGN;
int integerStartIdx = isNegative ? 1 : 0;
int integerEndIdx = decimalIdx > -1 ? decimalIdx : plainNumberString.length();
String integerPart = plainNumberString.substring(integerStartIdx, integerEndIdx);
int integerPartLength = integerPart.length();
int firstGroupEndIdx = integerPartLength % GROUP_SIZE;
if (firstGroupEndIdx == 0) {
firstGroupEndIdx = GROUP_SIZE;
}
if (firstGroupEndIdx == integerPartLength && _plainStringMatchesLocale) {
// Nothing to group and plain string matches locale formatting
return plainNumberString;
}
StringBuilder sb = new StringBuilder(plainNumberString.length() + integerPartLength / 3);
if (isNegative) {
sb.append(_localeMinusSign);
}
sb.append(integerPart.substring(0, firstGroupEndIdx));
for (int i = firstGroupEndIdx; i < integerPartLength; i += GROUP_SIZE) {
sb.append(_localeGroupingSeparator).append(integerPart.substring(i, i + 3));
}
if (decimalIdx > -1) {
sb.append(_localeDecimalSeparator).append(plainNumberString.substring(decimalIdx + 1));
}
return sb.toString();
}
}