// ReportWriter
package org.javamoney.examples.ez.money.report;
import static org.javamoney.examples.ez.common.utility.DateHelper.createCalendar;
import static org.javamoney.examples.ez.common.utility.I18NHelper.getSharedProperty;
import static org.javamoney.examples.ez.common.utility.ResourceHelper.openURL;
import static java.util.Calendar.MONTH;
import static java.util.Calendar.YEAR;
import static org.javamoney.examples.ez.money.ApplicationProperties.UI_DATE_FORMAT;
import static org.javamoney.examples.ez.money.KeywordKeys.NOT_CATEGORIZED;
import static org.javamoney.examples.ez.money.importexport.QIFConstants.CATEGORY_SEPARATOR_CHAR;
import static org.javamoney.examples.ez.money.utility.DialogHelper.decide;
import static org.javamoney.examples.ez.money.utility.DialogHelper.error;
import static org.javamoney.examples.ez.money.utility.FileDialogHelper.showSaveDialog;
import static org.javamoney.examples.ez.money.utility.TransactionHelper.isExpense;
import static org.javamoney.examples.ez.money.utility.TransactionHelper.isSplit;
import static org.javamoney.examples.ez.money.utility.TransactionHelper.isTransfer;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import java.text.DateFormatSymbols;
import java.util.Date;
import java.util.GregorianCalendar;
import org.javamoney.examples.ez.money.model.dynamic.transaction.Split;
import org.javamoney.examples.ez.money.model.persisted.transaction.Transaction;
import org.javamoney.examples.ez.money.utility.HTMLHelper;
import org.javamoney.examples.ez.common.utility.I18NHelper;
/**
* This class provides common functionality and class members for the report
* writers. All methods in this class are static.
*/
abstract
class
ReportWriter
{
/**
* This method returns the select a file if the user accepts the dialog,
* otherwise null.
*
* @param fileName The initially selected file.
*
* @return The select a file if the user accepts the dialog, otherwise null.
*/
protected
final
static
File
chooseFile(String fileName)
{
return showSaveDialog(fileName + HTML_EXT, HTML_EXT);
}
/**
* This method returns a print stream that will print to the specified file.
*
* @param file The file to write to.
*
* @return A print stream that will print to the specified file.
*
* @throws FileNotFoundException If the file cannot be found.
* @throws UnsupportedEncodingException If the stream is opened with an
* invalid encoding type.
*/
protected
final
static
PrintStream
createPrintStream(File file)
throws FileNotFoundException, UnsupportedEncodingException
{
return new PrintStream(new FileOutputStream(file), false, "UTF-16");
}
/**
* This method returns an HTML formatted string representation of the
* specified amount in the format of #,###.## or (#,###.##), depending on
* whether or not the amount is negative.
*
* @param amount The amount to format.
*
* @return An HTML formatted string representation of the specified amount.
*/
protected
final
static
String
formatAmount(double amount)
{
return HTMLHelper.formatAmount(amount, false);
}
/**
* This method returns the category for the specified QIF string.
*
* @param qif The QIF formatted string to obtain the category from.
*
* @return The category for the specified QIF string.
*/
protected
static
String
getCategory(String qif)
{
int index = qif.lastIndexOf(CATEGORY_SEPARATOR_CHAR);
if(index != -1)
{
qif = qif.substring(index + 1);
}
return qif;
}
/**
*
*
* @param stream
* @param trans
*/
protected
static
void
printCategory(PrintStream stream, Transaction trans)
{
String category = trans.getCategory();
if(isTransfer(trans) == true)
{
if(isExpense(trans) == true)
{
category = TRANSFER_TO;
}
else
{
category = TRANSFER_FROM;
}
}
else if(isSplit(trans) == true)
{
category = SPLIT;
}
else
{
category = getCategory(category);
}
printTransactionDetailField(stream, CATEGORY, category);
if(isSplit(trans) == true)
{
printSplit(stream, trans);
}
}
/**
*
*
* @param stream
* @param trans
*/
protected
static
void
printFlags(PrintStream stream, Transaction trans)
{
if(trans.isReconciled() == true)
{
printTransactionDetailField(stream, RECONCILED, YES);
}
else
{
printTransactionDetailField(stream, RECONCILED, NO);
}
}
/**
* This method prints common elements for reports pertaining to the head tag
* on the specified stream.
*
* @param stream The stream to print on.
*/
protected
final
static
void
printHeadTag(PrintStream stream)
{
stream.println("<head>");
stream.println("<style type=\"text/css\">");
stream.println("a{border-bottom-color:white;border-bottom-style:solid;color:black;text-decoration:none;}");
stream.println("a:link{border-bottom-color:white;border-bottom-style:solid;color:black;}");
stream.println("a:visited{border-bottom-color:white;border-bottom-style:solid;color:black;}");
stream.println("a:hover{border-bottom-color:#8187BA;border-bottom-style:groove;}");
stream.println("body{color:black;font-family:arial;font-size:11px}");
stream.println("hr{background-color:black;border-style:none;color:black;height:1px;}");
stream.println("table{color:black;font-family:arial;font-size:11px}");
stream.println("table.header{border-style:solid}");
stream.println("</style>");
stream.println("</head>");
}
/**
* This method prints a message on the specified stream informing the user
* that there are no transactions for the period.
*
* @param stream The stream to print on.
*/
protected
final
static
void
printNoTransactionsMessage(PrintStream stream)
{
stream.println("<table width=595>");
stream.println("<tr><td align=center><b>" + getProperty("no_transactions") + "</b></td></tr>");
stream.println("</table>");
}
/**
* This method prints the period information on the specified stream for the
* specified account statement.
*
* @param stream The stream to print on.
* @param statement The account statement the period pertains to.
*/
protected
final
static
void
printPeriodInfo(PrintStream stream, AccountStatement statement)
{
stream.println(getProperty("period_from.statement"));
stream.println("<b>" + formatDate(statement.getStartDate()) + "</b>");
stream.println(getSharedProperty("thru"));
stream.println("<b>" + formatDate(statement.getEndDate()) + "</b><br>");
}
/**
* This method prints the period information on the specified stream for the
* specified budget report.
*
* @param stream The stream to print on.
* @param report The budget report statement the period pertains to.
*/
protected
final
static
void
printPeriodInfo(PrintStream stream, BudgetReport report)
{
GregorianCalendar end = createCalendar(report.getEndDate());
GregorianCalendar start = createCalendar(report.getStartDate());
String[] months = new DateFormatSymbols().getMonths();
stream.println(getProperty("period_from.budget"));
stream.println("<b>" + months[start.get(MONTH)]);
stream.println(" " + start.get(YEAR) + "</b>");
if(start.get(MONTH) != end.get(MONTH))
{
stream.println(" " + getSharedProperty("thru") + " ");
stream.println("<b>" + months[end.get(MONTH)]);
stream.println(" " + end.get(YEAR) + "</b>");
}
stream.println("<br>");
}
/**
* This method prints the period information on the specified stream for the
* specified category report.
*
* @param stream The stream to print on.
* @param report The category report the period pertains to.
* @param type The category report's type.
*/
protected
final
static
void
printPeriodInfo(PrintStream stream, CategoryReport report,
TotalReportTypeKeys type)
{
if(type == TotalReportTypeKeys.EXPENSES)
{
stream.println(getProperty("period_from.expenses"));
}
else
{
stream.println(getProperty("period_from.income"));
}
stream.println("<b>" + formatDate(report.getStartDate()) + "</b>");
stream.println(getSharedProperty("thru"));
stream.println("<b>" + formatDate(report.getEndDate()) + "</b><br>");
}
/**
* This method prints a table on the specified stream detailing when the
* report was prepared.
*
* @param stream The stream to print on.
*/
protected
final
static
void
printPreparedOn(PrintStream stream)
{
stream.println("<table>");
stream.println("<tr><td align=right width=595>");
stream.println(getProperty("prepared") + " " + formatDate(new Date()));
stream.println(" " + getProperty("by") + "</td></tr>");
stream.println("</table>");
}
/**
* This method prints a table with the specified title on the specified stream
* to act as a section header.
*
* @param stream The stream to print on.
* @param title The title for the section.
*/
protected
final
static
void
printSectionHeader(PrintStream stream, String title)
{
stream.println("<br>");
stream.println("<table class=\"header\" width=595>");
stream.println("<tr><td>" + title + "</td></tr>");
stream.println("</table>");
}
/**
* This method prints a transaction's field and value on the specified stream.
*
* @param stream The stream to print on.
* @param key The field's key.
* @param value The field's value.
*/
protected
final
static
void
printTransactionDetailField(PrintStream stream, String key, String value)
{
if(value.length() == 0)
{
value = NO_DATA;
}
stream.println("<tr><td> </td>");
stream.println("<td colspan=2 style=\"max-width:375px\">");
stream.println("<font color=#000066><u>" + key + "</font></u>: <i>" + value + "</i>");
stream.println("</td></tr>");
}
/**
* This method prints a heading that will precede a list of transactions on
* the specified stream.
*
* @param stream The stream to print on.
*/
protected
final
static
void
printTransactionsHeader(PrintStream stream)
{
stream.println("<tr>");
stream.println("<td align=center width=75><b>" + getSharedProperty("date") + "</b></td>");
stream.println("<td width=375><b>" + "" + "</b></td>");
stream.println("<td align=center width=125><b>" + getSharedProperty("amount") + "</b></td>");
stream.println("</tr>");
stream.println("<tr><td colspan=3><hr></td></tr>");
}
/**
* This method logs the specified exception and displays a message to the user
* that the process failed.
*
* @param exception The error that occurred.
*/
protected
final
static
void
showErrorMessage(Exception exception)
{
error(getProperty("error.title"),
getProperty("error.description") + " " + exception.getLocalizedMessage());
}
/**
* This method displays a message to the user that the process succeeded and
* asks whether or not to view the report now.
*
* @param file The file where the report was written.
*/
protected
final
static
void
showSuccessMessage(File file)
{
if(decide(getProperty("success.title"),
getProperty("success.description")) == true)
{
openURL(file.toURI().toString());
}
}
//////////////////////////////////////////////////////////////////////////////
// Start of private methods.
//////////////////////////////////////////////////////////////////////////////
private
static
String
formatDate(Date date)
{
String str = ALL;
if(date != null)
{
str = UI_DATE_FORMAT.format(date);
}
return str;
}
private
static
String
getProperty(String key)
{
return I18NHelper.getProperty("ReportWriter." + key);
}
static
private
void
printSplit(PrintStream stream, Transaction trans)
{
Split split = new Split(trans);
stream.println("<tr><td> </td>");
stream.println("<td colspan=2><ol>");
// Print the categories in a list.
for(int index = 0; index < split.size(); ++index)
{
String category = getCategory(split.getCategory(index));
double amount = Math.abs(split.getAmount(index));
if(category.length() == 0)
{
category = NOT_CATEGORIZED.toString();
}
stream.println("<li><i>" + category + " = " + formatAmount(amount) + "</i></li>");
}
stream.println("</ol></td></tr>");
}
//////////////////////////////////////////////////////////////////////////////
// Start of class members.
//////////////////////////////////////////////////////////////////////////////
/**
* A constant for the word.
*/
protected static final String ACCOUNT = I18NHelper.getSharedProperty("account");
/**
* A constant for the word.
*/
protected static final String BALANCE = I18NHelper.getSharedProperty("balance");
/**
* A constant for the word.
*/
protected static final String CATEGORY = I18NHelper.getSharedProperty("category");
/**
* A constant for the word.
*/
protected static final String CHECK = I18NHelper.getSharedProperty("check_number");
/**
* A constant for the word.
*/
protected static final String NOTES = I18NHelper.getSharedProperty("notes");
/**
* A constant for the word.
*/
protected static final String PAYEE = I18NHelper.getSharedProperty("payee");
/**
* A constant for an empty row in a table to act as a break.
*/
protected static final String TABLE_BREAK = "<tr><td> </td></tr>";
/**
* A constant for the word.
*/
protected static final String TRANSACTIONS = I18NHelper.getSharedProperty("transactions");
private static final String ALL = I18NHelper.getSharedProperty("all");
private static final String HTML_EXT = ".html";
private static final String NO = I18NHelper.getSharedProperty("no");
private static final String NO_DATA = getProperty("no_data");
private static final String RECONCILED = I18NHelper.getSharedProperty("reconciled");
private static final String SPLIT = I18NHelper.getSharedProperty("split");
private static final String TRANSFER_FROM = getProperty("transfer_from");
private static final String TRANSFER_TO = getProperty("transfer_to");
private static final String YES = I18NHelper.getSharedProperty("yes");
}