// CategoryReportWriter package org.javamoney.examples.ez.money.report; import static org.javamoney.examples.ez.common.utility.I18NHelper.getSharedProperty; import static java.util.Collections.sort; import static org.javamoney.examples.ez.money.ApplicationProperties.UI_DATE_FORMAT; import static org.javamoney.examples.ez.money.ApplicationProperties.getCategoryReportSortByField; import static org.javamoney.examples.ez.money.ApplicationProperties.includeDetailsInReport; import static org.javamoney.examples.ez.money.ApplicationProperties.includeGroupsInReport; import static org.javamoney.examples.ez.money.model.dynamic.total.IncomeExpenseTotal.getExpenseTotal; import static org.javamoney.examples.ez.money.model.dynamic.total.IncomeExpenseTotal.getIncomeTotal; import static org.javamoney.examples.ez.money.utility.HTMLHelper.buildLinkTag; import java.io.File; import java.io.PrintStream; import java.util.Collection; import java.util.List; import org.javamoney.examples.ez.money.KeywordKeys; import org.javamoney.examples.ez.money.locale.PercentFormat; import org.javamoney.examples.ez.money.model.dynamic.total.IncomeExpenseTotal; import org.javamoney.examples.ez.money.model.dynamic.total.TransactionDetail; import org.javamoney.examples.ez.money.model.persisted.transaction.Transaction; import org.javamoney.examples.ez.common.utility.I18NHelper; /** * This class facilitates generating an HTML formatted file for a category * report. All methods in this class are static. */ public final class CategoryReportWriter extends ReportWriter { /** * This method writes HTML formatted data to a user specified file. * * @param type The type of category report to generate. * @param report The report to generate the file for. */ public static void generate(TotalReportTypeKeys type, CategoryReport report) { File file = chooseFile(getSharedProperty("report")); if(file != null) { generate(type, report, file); } } ////////////////////////////////////////////////////////////////////////////// // Start of private methods. ////////////////////////////////////////////////////////////////////////////// private static void generate(TotalReportTypeKeys type, CategoryReport report, File file) { try { PrintStream stream = createPrintStream(file); Collection<IncomeExpenseTotal> groups = getGroupTotals(report, type); Collection<IncomeExpenseTotal> totals = getTotals(report, type); stream.println("<html>"); printHeadTag(stream); stream.println("<body>"); printPreparedOn(stream); printPeriodInfo(stream, report, type); printSectionHeader(stream, getSharedProperty("period_summary")); printReportSummary(stream); if(includeGroupsInReport() == true && totals.size() != 0) { printSectionHeader(stream, getProperty("group_totals")); printTotals(stream, groups, false); } printSectionHeader(stream, type.toString()); printTotals(stream, totals, includeDetailsInReport()); if(includeDetailsInReport() == true && totals.size() != 0) { printSectionHeader(stream, getSharedProperty("transaction_details")); printDetails(stream, totals); } stream.println("</body></html>"); stream.flush(); stream.close(); showSuccessMessage(file); } catch(Exception exception) { showErrorMessage(exception); } } private static String getCategoryUID(IncomeExpenseTotal total) { String category = total.getCategoryIdentifier(); if(category.length() == 0) { category = KeywordKeys.NOT_CATEGORIZED.toString(); } return category; } private static Collection<IncomeExpenseTotal> getTotals(CategoryReport report, TotalReportTypeKeys type) { Collection<IncomeExpenseTotal> totals = null; if(type == TotalReportTypeKeys.EXPENSES) { totals = report.getExpenses(); } else { totals = report.getIncome(); } // Sort the report according to the user's preference. sort((List<IncomeExpenseTotal>)totals, new CategoryReportComparator()); return totals; } private static Collection<IncomeExpenseTotal> getGroupTotals(CategoryReport report, TotalReportTypeKeys type) { Collection<IncomeExpenseTotal> totals = null; if(type == TotalReportTypeKeys.EXPENSES) { totals = report.getExpenseGroups(); } else { totals = report.getIncomeGroups(); } // Sort the report according to the user's preference. sort((List<IncomeExpenseTotal>)totals, new CategoryReportComparator()); return totals; } private static String getProperty(String key) { return I18NHelper.getProperty("CategoryReportWriter." + key); } private static void printDetails(PrintStream stream, Collection<IncomeExpenseTotal> totals) { for(IncomeExpenseTotal total : totals) { printTotalDetail(stream, total); stream.println("<table>"); printTransactionsHeader(stream); for(TransactionDetail detail : total.getTransactionDetails()) { Transaction trans = detail.getTransaction(); stream.println("<tr>"); stream.println("<td align=center>" + UI_DATE_FORMAT.format(trans.getDate()) + "</td>"); stream.println("<td> </td>"); stream.println("<td align=center>" + formatAmount(-trans.getAmount().getNumber().doubleValue()) + "</td>"); stream.println("</tr>"); printTransactionDetailField(stream, ACCOUNT, detail.getAccount().getIdentifier()); printTransactionDetailField(stream, PAYEE, trans.getPayee()); printTransactionDetailField(stream, CATEGORY, getCategory(trans.getCategory())); stream.println(TABLE_BREAK); } stream.println("</table>"); if(total.getTransactionDetails().size() == 0) { printNoTransactionsMessage(stream); } stream.println("<br>"); } } private static void printReportSummary(PrintStream stream) { double net = getIncomeTotal() - getExpenseTotal(); stream.println("<table>"); // Income total. stream.println("<tr>"); stream.println("<td>" + getSharedProperty("income") + ":</td>"); stream.println("<td>" + formatAmount(getIncomeTotal()) + "</td>"); stream.println("</tr>"); // Total spent. stream.println("<tr>"); stream.println("<td>" + getSharedProperty("expenses") + ":</td>"); stream.println("<td>" + formatAmount(getExpenseTotal()) + "</td>"); stream.println("</tr>"); stream.println("<tr>"); stream.println("<td colspan=2><hr></td>"); stream.println("</tr>"); // Total available balance. stream.println("<tr>"); stream.println("<td>" + getSharedProperty("net") + ":</td>"); stream.println("<td>" + formatAmount(net) + "</td>"); stream.println("</tr>"); stream.println(TABLE_BREAK); stream.println("</table>"); } private static void printTotalDetail(PrintStream stream, IncomeExpenseTotal total) { String category = getCategoryUID(total); stream.println("<table>"); stream.println(TABLE_BREAK); stream.println("<tr>"); stream.println("<td colspan=2>"); stream.println("<a id=\"" + category + "\"> </a>"); stream.println("-- <font color=#006600><b>" + category + "</b></font> --"); stream.println("</td>"); stream.println("</tr>"); stream.println("<tr>"); stream.println("<td>" + AMOUNT + ":</td>"); stream.println("<td>" + formatAmount(Math.abs(total.getAmount())) + "</td>"); stream.println("</tr>"); stream.println("<tr>"); stream.println("<td>" + GROUP + ":</td>"); stream.println("<td>" + total.getGroupName() + "</td>"); stream.println("</tr>"); stream.println("<tr>"); stream.println("<td>" + PercentFormat.SYMBOL + ":</td>"); stream.println("<td>" + PERCENT_FORMAT.format(total.getPercent()) + "</td>"); stream.println("</tr>"); stream.println("<tr>"); stream.println("<td>" + TRANSACTIONS + ":</td>"); stream.println("<td>" + total.getTransactionDetails().size() + "</td>"); stream.println("</tr>"); stream.println(TABLE_BREAK); stream.println("</table>"); } private static void printTotalHeader(PrintStream stream) { CategoryReportSortByKeys key = getCategoryReportSortByField(); String gray = "#CCCCFF"; String amountColor = (key == CategoryReportSortByKeys.AMOUNT) ? gray : "#FFFFFF"; String categoryColor = (key == CategoryReportSortByKeys.CATEGORY) ? gray : "#FFFFFF"; String groupColor = (key == CategoryReportSortByKeys.GROUP) ? gray : "#FFFFFF"; String percentColor = (key == CategoryReportSortByKeys.PERCENT) ? gray : "#FFFFFF"; stream.println("<tr>"); // Number column. stream.println("<td width=10> </td>"); // Category column. stream.println("<td bgcolor=" + categoryColor + " align=center width=200>"); stream.println("<b>" + CATEGORY + "</b>"); stream.println("</td>"); // Group column. stream.println("<td bgcolor=" + groupColor + " align=center width=225>"); stream.println("<b>" + GROUP + "</b>"); stream.println("</td>"); // Amount column. stream.println("<td bgcolor=" + amountColor + " align=center width=90>"); stream.println("<b>" + AMOUNT + "</b>"); stream.println("</td>"); // Percent column. stream.println("<td bgcolor=" + percentColor + " align=center width=50>"); stream.println("<b>" + PercentFormat.SYMBOL + "</b>"); stream.println("</td>"); stream.println("</tr>"); stream.println("<tr><td colspan=5><hr></td></tr>"); } private static void printTotals(PrintStream stream, Collection<IncomeExpenseTotal> totals, boolean includeDetails) { int count = 1; stream.println("<table>"); printTotalHeader(stream); for(IncomeExpenseTotal total : totals) { String category = getCategoryUID(total); stream.println("<tr>"); stream.println("<td align=right>" + (count++) + ")</td>"); stream.println("<td>"); if(includeDetails == true) { stream.println(buildLinkTag("#" + category, category)); } else { stream.println(category); } stream.println("</td>"); stream.println("<td>" + total.getGroupName() + "</td>"); stream.println("<td align=center>" + formatAmount(Math.abs(total.getAmount())) + "</td>"); stream.println("<td align=center>" + PERCENT_FORMAT.format(total.getPercent()) + "</td>"); stream.println("</tr>"); } stream.println(TABLE_BREAK); stream.println("</table>"); if(totals.size() == 0) { printNoTransactionsMessage(stream); } } ////////////////////////////////////////////////////////////////////////////// // Start of class members. ////////////////////////////////////////////////////////////////////////////// private static final PercentFormat PERCENT_FORMAT = new PercentFormat(); private static final String AMOUNT = getSharedProperty("amount"); private static final String GROUP = getSharedProperty("group"); }