/*
This file is part of Cyclos (www.cyclos.org).
A project of the Social Trade Organisation (www.socialtrade.org).
Cyclos is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Cyclos is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Cyclos; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package nl.strohalm.cyclos.services.stats.finances;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import nl.strohalm.cyclos.dao.accounts.transactions.TransferDAO;
import nl.strohalm.cyclos.entities.accounts.SystemAccountType;
import nl.strohalm.cyclos.entities.accounts.transactions.PaymentFilter;
import nl.strohalm.cyclos.entities.accounts.transactions.TransferQuery;
import nl.strohalm.cyclos.entities.accounts.transactions.TransferType;
import nl.strohalm.cyclos.entities.reports.StatisticalDTO;
import nl.strohalm.cyclos.entities.reports.StatisticalNumber;
import nl.strohalm.cyclos.utils.Period;
/**
* takes care of the calculations for finance stats for one single point (bar or section) in the graphs/tables. Should be subclassed for specific sets
* of stats (i.e.: a subclass for single period, a subclass for Compared, etc)
*
* @author Rinke
*
*/
public abstract class FinanceStats {
/**
* the cached result
*/
protected Number[][] tableCells;
/**
* cached paymentFilters
*/
protected Collection<PaymentFilter> paymentFilters;
/**
* the cached rowKeys
*/
protected String[] paymentFilterNames;
private final TransferDAO transferDao;
protected FinanceStats(final TransferDAO transferDao) {
this.transferDao = transferDao;
}
/**
* returns the paymentFilter names in a String array. If there is only one paymentFilter in the paymentFilters, then an array of containing
* transferType names is returned.
*
* @return a array of paymentFilter names.
*/
public String[] getPaymentFilterNames(final Collection<PaymentFilter> aPaymentFilters) {
if (!hasEqualParameters(aPaymentFilters) || paymentFilterNames == null) {
paymentFilterNames = null;
final List<String> names = new ArrayList<String>();
for (final PaymentFilter paymentFilter : aPaymentFilters) {
if (aPaymentFilters.size() == 1) {
for (final TransferType transferType : paymentFilter.getTransferTypes()) {
names.add(transferType.getName());
}
break;
}
names.add(paymentFilter.getName());
}
paymentFilterNames = names.toArray(new String[] {});
}
return paymentFilterNames;
}
// TODO Jefferson: please javadoc
private StatisticalNumber getSumOfTransactions(final Period aPeriod, final TransferType transferType) {
final StatisticalDTO dto = new StatisticalDTO();
dto.setPeriod(aPeriod);
dto.setTransferType(transferType);
final BigDecimal sumOfTransaction = transferDao.getSumOfTransactions(dto);
return new StatisticalNumber(sumOfTransaction.doubleValue(), (byte) 2);
}
/**
* checks if the paymentFilters param has changed, and if a local cached result is available. If parameters haven't changed and a cached value of
* the results is available, the calling method should read filternames from local field values rather than reretrieving them again. The method
* does <b>NOT</b> update the values it checks, that is the responsibility of the calling method, after having redone all calculations.
*
* @param aPaymentFilters
* @return <code>false</code> if the input parameters are different from the corresponding class instance variables, or if there is no cached
* result available.
*/
private boolean hasEqualParameters(final Collection<PaymentFilter> aPaymentFilters) {
return (paymentFilters != null && paymentFilters.equals(aPaymentFilters));
}
/**
* gets the Expenditure which was done from the specified system Account, in the period, and according to the paymentFilter
*
* @param period
* @param paymentFilter
* @param systemAccountFilter
* @return a <code>StatisticalNumber</code> containing the result.
*/
Number getExpenditure(final Period aPeriod, final PaymentFilter aPaymentFilter, final SystemAccountType aSystemAccountFilter) {
double expenditure = 0;
for (final TransferType transferType : aPaymentFilter.getTransferTypes()) {
expenditure += getExpenditure(aPeriod, transferType, aSystemAccountFilter).doubleValue();
}
return new StatisticalNumber(expenditure, (byte) 2);
}
/**
* gets the Expenditure which was done from the specified system Account, in the period, and according to the transferType specified.
*
* @param period2
* @param transferType
* @param systemAccountFilter2
* @return a <code>StatisticalNumber</code> containing the result.
*/
Number getExpenditure(final Period aPeriod, final TransferType transferType, final SystemAccountType aSystemAccountType) {
if (!transferType.getFrom().equals(aSystemAccountType)) {
return new StatisticalNumber(0, (byte) 2);
} else {
return getSumOfTransactions(aPeriod, transferType);
}
}
/**
* calculates the expenditure for this systemAccount in the specified period, which falls NOT in the specified paymentFilter Collection.
*
* @param period
* @param paymentFilters
* @param systemAccountFilter
*/
Number getExpenditureRest(final Period aPeriod, final Collection<PaymentFilter> aPaymentFilters, final SystemAccountType aSystemAccountType) {
final TransferQuery transferQuery = new TransferQuery();
transferQuery.setFromAccountType(aSystemAccountType);
transferQuery.setPaymentFilters(aPaymentFilters);
transferQuery.setPeriod(aPeriod);
final BigDecimal sumOfTransactionsRest = transferDao.getSumOfTransactionsRest(transferQuery);
return new StatisticalNumber(sumOfTransactionsRest.doubleValue(), (byte) 2);
}
/**
* gets the Income retrieved on the specified system Account, in the period, and according to the paymentFilter
*
* @param period
* @param paymentFilter
* @param systemAccountFilter
* @return a <code>StatisticalNumber</code> containing the result.
*/
Number getIncome(final Period aPeriod, final PaymentFilter aPaymentFilter, final SystemAccountType aSystemAccountFilter) {
double income = 0;
for (final TransferType transferType : aPaymentFilter.getTransferTypes()) {
income += getIncome(aPeriod, transferType, aSystemAccountFilter).doubleValue();
}
return new StatisticalNumber(income, (byte) 2);
}
/**
* gets the income retrieved on the specified system Account, in the period, and according to the transferType specified.
*
* @param period2
* @param transferType
* @param systemAccountFilter2
* @return a <code>StatisticalNumber</code> containing the result.
*/
Number getIncome(final Period aPeriod, final TransferType transferType, final SystemAccountType aSystemAccountType) {
if (!transferType.getTo().equals(aSystemAccountType)) {
return new StatisticalNumber(0, (byte) 2);
} else {
return getSumOfTransactions(aPeriod, transferType);
}
}
/**
* calculates the income on this systemAccount in the specified period, which falls NOT in the specified paymentFilter Collection.
*
* @param period
* @param paymentFilters
* @param systemAccountFilter
*/
Number getIncomeRest(final Period aPeriod, final Collection<PaymentFilter> aPaymentFilters, final SystemAccountType aSystemAccountType) {
final TransferQuery transferQuery = new TransferQuery();
transferQuery.setToAccountType(aSystemAccountType);
transferQuery.setPaymentFilters(aPaymentFilters);
transferQuery.setPeriod(aPeriod);
final BigDecimal sumOfTransactionsRest = transferDao.getSumOfTransactionsRest(transferQuery);
return new StatisticalNumber(sumOfTransactionsRest.doubleValue(), (byte) 2);
}
}