/* * Copyright (C) 2011 4th Line GmbH, Switzerland * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.fourthline.konto.shared.result; import org.fourthline.konto.shared.CurrencyProvider; import org.fourthline.konto.shared.MonetaryAmount; import org.fourthline.konto.shared.entity.Account; import org.fourthline.konto.shared.entity.AccountGroup; import org.fourthline.konto.shared.entity.CurrencyPair; import org.fourthline.konto.shared.entity.MonetaryUnit; import org.fourthline.konto.shared.query.AccountsQueryCriteria; import java.io.PrintStream; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; /** * @author Christian Bauer */ public class ReportLines extends ArrayList<GroupReportLine> { public static final AccountGroup DEFAULT_GROUP = new AccountGroup(Long.MAX_VALUE, "DEFAULT GROUP"); public static boolean isDefaultGroup(AccountGroup group) { return group.getId() != null && Long.MAX_VALUE == group.getId(); } // This type we need for map lookups protected class GroupIdName { Long id; String name; GroupIdName(Long id, String name) { this.id = id; this.name = name; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; GroupIdName that = (GroupIdName) o; return id.equals(that.id); } @Override public int hashCode() { return id.hashCode(); } } protected AccountsQueryCriteria criteria; protected MonetaryUnit unit; protected MonetaryAmount total; public ReportLines() { } public ReportLines(AccountsQueryCriteria criteria, MonetaryUnit unit, List<AccountReportLine> accountLines, CurrencyProvider currencyProvider, Date dateOfExchangeRate) { this.criteria = criteria; this.unit = unit; this.total = new MonetaryAmount(unit); updateExchangedAmounts(accountLines, unit, currencyProvider, dateOfExchangeRate); addAll(createGroupLines(accountLines)); } public ReportLines(AccountsQueryCriteria criteria, MonetaryUnit unit, Map<Account, List<EntryReportLine>> accountEntryLines, boolean useInitialBalance, CurrencyProvider currencyProvider, Date dateOfExchangeRate) { this.criteria = criteria; this.unit = unit; this.total = new MonetaryAmount(unit); Collection<AccountReportLine> accountLines = createAccountLines(accountEntryLines, useInitialBalance); updateExchangedAmounts(accountLines, unit, currencyProvider, dateOfExchangeRate); addAll(createGroupLines(accountLines)); } public AccountsQueryCriteria getCriteria() { return criteria; } public MonetaryUnit getUnit() { return unit; } public MonetaryAmount getTotal() { return total; } @Override public void clear() { super.clear(); total = new MonetaryAmount(getUnit()); } protected Collection<AccountReportLine> createAccountLines(Map<Account, List<EntryReportLine>> accountEntryLines, boolean useInitialBalance) { // Build and populate account lines Map<Long, AccountReportLine> accountLines = new LinkedHashMap(); for (Map.Entry<Account, List<EntryReportLine>> me : accountEntryLines.entrySet()) { Account account = me.getKey(); AccountReportLine accountLine; if ((accountLine = accountLines.get(account.getId())) == null) { MonetaryAmount amount = useInitialBalance ? account.getInitialBalance() : new MonetaryAmount(account.getMonetaryUnit()); accountLine = new AccountReportLine(account, amount); accountLines.put(account.getId(), accountLine); } for (EntryReportLine entryLine : me.getValue()) { accountLine.addSubLine(entryLine); } } return accountLines.values(); } protected Collection<GroupReportLine> createGroupLines(Collection<AccountReportLine> accountLines) { Map<GroupIdName, GroupReportLine> groupLines = new LinkedHashMap(); for (AccountReportLine accountLine : accountLines) { Account account = accountLine.getAccount(); GroupIdName group; if (account.getGroupId() != null) { group = new GroupIdName(account.getGroupId(), account.getGroupName()); } else { group = new GroupIdName(DEFAULT_GROUP.getId(), DEFAULT_GROUP.getName()); } GroupReportLine groupLine; if ((groupLine = groupLines.get(group)) == null) { AccountGroup ag = new AccountGroup(group.id, group.name); MonetaryAmount am = new MonetaryAmount(getUnit()); groupLine = new GroupReportLine(ag, am); groupLines.put(group, groupLine); } groupLine.addSubLine((accountLine)); } return groupLines.values(); } @Override public boolean addAll(Collection<? extends GroupReportLine> groupReportLines) { for (GroupReportLine groupLine : groupReportLines) { total = total.add(groupLine.getAmount()); } return super.addAll(groupReportLines); } protected void updateExchangedAmounts(Collection<? extends ReportLine> lines, MonetaryUnit targetUnit, CurrencyProvider currencyProvider, Date dayOfExchangeRate) { for (ReportLine line : lines) { MonetaryAmount amount = line.getAmount(); if (amount.requiresCurrencyExchange(targetUnit)) { line.setAmount( getExchangedAmount(amount, targetUnit, currencyProvider, dayOfExchangeRate) ); } } } protected MonetaryAmount getExchangedAmount(MonetaryAmount originalAmount, MonetaryUnit targetUnit, CurrencyProvider currencyProvider, Date dayOfExchangeRate) { CurrencyPair cp = currencyProvider.getCurrencyPair( originalAmount.getUnit(), targetUnit, dayOfExchangeRate ); if (cp == null) { cp = new CurrencyPair(originalAmount.getUnit(), targetUnit); } return new ExchangedMonetaryAmount(originalAmount, cp); } public void print(PrintStream ps) { for (GroupReportLine reportLine : this) { ps.println(reportLine); for (AccountReportLine accountLine : reportLine.getSubLines()) { ps.println(" - " + accountLine); for (EntryReportLine entryLine : accountLine.getSubLines()) { ps.println(" * " + entryLine); } } } } }