package name.abuchen.portfolio.money;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
public abstract class Values<E>
{
public static final class MoneyValues extends Values<Money>
{
private MoneyValues()
{
super("#,##0.00", 100D, 100); //$NON-NLS-1$
}
@Override
public String format(Money amount)
{
return String.format("%s %,.2f", amount.getCurrencyCode(), amount.getAmount() / divider()); //$NON-NLS-1$
}
public String format(Money amount, String skipCurrencyCode)
{
if (skipCurrencyCode.equals(amount.getCurrencyCode()))
return String.format("%,.2f", amount.getAmount() / divider()); //$NON-NLS-1$
else
return format(amount);
}
@Override
public String formatNonZero(Money amount)
{
return amount.isZero() ? null : format(amount);
}
@Override
public String formatNonZero(Money amount, double threshold)
{
boolean isNotZero = Math.abs(amount.getAmount()) >= threshold;
return isNotZero ? format(amount) : null;
}
public String formatNonZero(Money amount, String skipCurrencyCode)
{
return amount.isZero() ? null : format(amount, skipCurrencyCode);
}
}
public static final class QuoteValues extends Values<Long>
{
private static final String QUOTE_PATTERN = "#,##0.00##"; //$NON-NLS-1$
private static final ThreadLocal<DecimalFormat> QUOTE_FORMAT = new ThreadLocal<DecimalFormat>()
{
@Override
protected DecimalFormat initialValue()
{
return new DecimalFormat(QUOTE_PATTERN);
}
};
private QuoteValues()
{
super(QUOTE_PATTERN, 10000D, 10000);
}
@Override
public String format(Long quote)
{
return QUOTE_FORMAT.get().format(quote / divider());
}
public String format(String currencyCode, long quote, String skipCurrency)
{
if (currencyCode == null || skipCurrency.equals(currencyCode))
return format(quote);
else
return format(currencyCode, quote);
}
public String format(String currencyCode, long quote)
{
return currencyCode + " " + format(quote); //$NON-NLS-1$
}
public String format(Quote quote)
{
return format(quote.getCurrencyCode(), quote.getAmount());
}
public String format(Quote quote, String skipCurrency)
{
return format(quote.getCurrencyCode(), quote.getAmount(), skipCurrency);
}
/**
* Factor by which to multiply a monetary amount to convert it into a
* quote amount. Monetary amounts have 2 decimal digits while quotes
* have 4 digits.
*/
public int factorToMoney()
{
return factor() / Values.Money.factor();
}
/**
* Divider by which to divide a quote amount to convert it into a
* monetary amount. Monetary amounts have 2 decimal digits while quotes
* have 4 digits.
*/
public double dividerToMoney()
{
return divider() / Values.Money.divider();
}
}
public static final Values<Long> Amount = new Values<Long>("#,##0.00", 100D, 100) //$NON-NLS-1$
{
@Override
public String format(Long amount)
{
return String.format("%,.2f", amount / divider()); //$NON-NLS-1$
}
};
public static final MoneyValues Money = new MoneyValues();
public static final Values<Long> AmountFraction = new Values<Long>("#,##0.00###", 100000D, 100000) //$NON-NLS-1$
{
private final DecimalFormat format = new DecimalFormat(pattern());
@Override
public String format(Long share)
{
return format.format(share / divider());
}
};
/**
* Optionally format values without decimal places. Currently used only for
* attributes attached to the security.
*/
public static final Values<Long> AmountPlain = new Values<Long>("#,##0.##", 100D, 100) //$NON-NLS-1$
{
private final DecimalFormat format = new DecimalFormat(pattern());
@Override
public String format(Long amount)
{
return format.format(amount / divider());
}
};
public static final Values<Long> Share = new Values<Long>("#,##0.######", 1000000D, 1000000) //$NON-NLS-1$
{
private final DecimalFormat format = new DecimalFormat(pattern());
@Override
public String format(Long share)
{
return format.format(share / divider());
}
};
public static final QuoteValues Quote = new QuoteValues();
public static final Values<BigDecimal> ExchangeRate = new Values<BigDecimal>("#,##0.0000", 1D, 1)//$NON-NLS-1$
{
@Override
public String format(BigDecimal exchangeRate)
{
return String.format("%,.4f", exchangeRate); //$NON-NLS-1$
}
};
public static final Values<Integer> Index = new Values<Integer>("#,##0.00", 100D, 100) //$NON-NLS-1$
{
@Override
public String format(Integer index)
{
return String.format("%,.2f", index / divider()); //$NON-NLS-1$
}
};
public static final Values<LocalDate> Date = new Values<LocalDate>("yyyy-MM-dd", 1D, 1) //$NON-NLS-1$
{
DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM);
@Override
public String format(LocalDate date)
{
return formatter.format(date);
}
};
public static final Values<Double> Percent = new Values<Double>("0.00%", 1D, 1) //$NON-NLS-1$
{
@Override
public String format(Double percent)
{
return String.format("%,.2f", percent * 100); //$NON-NLS-1$
}
};
public static final Values<Double> PercentShort = new Values<Double>("0.00%", 1D, 1) //$NON-NLS-1$
{
@Override
public String format(Double percent)
{
return String.format("%,.1f", percent * 100); //$NON-NLS-1$
}
};
public static final Values<Double> PercentPlain = new Values<Double>("0.00", 1D, 1) //$NON-NLS-1$
{
@Override
public String format(Double percent)
{
return String.format("%,.2f", percent); //$NON-NLS-1$
}
};
public static final Values<Integer> Weight = new Values<Integer>("#,##0.00", 100D, 100) //$NON-NLS-1$
{
@Override
public String format(Integer weight)
{
return String.format("%,.2f", weight / divider()); //$NON-NLS-1$
}
};
public static final Values<Double> Percent2 = new Values<Double>("0.00%", 1D, 1) //$NON-NLS-1$
{
@Override
public String format(Double percent)
{
return String.format("%,.2f%%", percent * 100); //$NON-NLS-1$
}
};
public static final Values<Double> Percent5 = new Values<Double>("0.00000%", 1D, 1) //$NON-NLS-1$
{
@Override
public String format(Double percent)
{
return String.format("%,.5f%%", percent * 100); //$NON-NLS-1$
}
};
public static final Values<Integer> Id = new Values<Integer>("#,##0", 1D, 1) //$NON-NLS-1$
{
@Override
public String format(Integer amount)
{
return String.format("%,.0f", amount / divider()); //$NON-NLS-1$
}
};
public static final Values<Integer> Year = new Values<Integer>("0", 1D, 1) //$NON-NLS-1$
{
@Override
public String format(Integer amount)
{
return String.valueOf(amount);
}
};
private final String pattern;
private final double divider;
private final int factor;
private final BigDecimal bdFactor;
private Values(String pattern, double divider, int factor)
{
this.pattern = pattern;
this.divider = divider;
this.factor = factor;
this.bdFactor = BigDecimal.valueOf(factor);
}
public String pattern()
{
return pattern;
}
public double divider()
{
return divider;
}
public int factor()
{
return factor;
}
/**
* Returns the factor as BigDecimal
*/
public BigDecimal getBigDecimalFactor()
{
return bdFactor;
}
public long factorize(double value)
{
return Math.round(value * factor);
}
public abstract String format(E amount);
public String formatNonZero(E amount)
{
if (amount instanceof Double)
{
Double d = (Double) amount;
if (d.isNaN())
return null;
else if (d.doubleValue() == 0d)
return null;
else
return format(amount);
}
else if (amount instanceof Number)
{
boolean isNotZero = ((Number) amount).longValue() != 0;
return isNotZero ? format(amount) : null;
}
throw new UnsupportedOperationException();
}
public String formatNonZero(E amount, double threshold)
{
if (amount instanceof Double)
{
boolean isNotZero = Math.abs(((Double) amount).doubleValue()) >= threshold;
return isNotZero ? format(amount) : null;
}
throw new UnsupportedOperationException();
}
}