/*
* Copyright (C) 2012-2016 The Android Money Manager Ex Project Team
*
* This program 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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.money.manager.ex.account;
import android.content.Context;
import android.database.Cursor;
import android.os.AsyncTask;
import android.os.Bundle;
import com.money.manager.ex.account.events.RunningBalanceCalculatedEvent;
import com.money.manager.ex.servicelayer.AccountService;
import com.money.manager.ex.common.AllDataListFragment;
import com.money.manager.ex.core.TransactionStatuses;
import com.money.manager.ex.core.TransactionTypes;
import com.money.manager.ex.datalayer.QueryAllDataRepository;
import com.money.manager.ex.utils.MmxDate;
import com.money.manager.ex.viewmodels.AccountTransactionDisplay;
import org.greenrobot.eventbus.EventBus;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import info.javaperformance.money.Money;
import info.javaperformance.money.MoneyFactory;
import timber.log.Timber;
/**
* Not used!
* Async task that calculates and updates the amount balance for each transaction in the
* transactions list.
* Here the idea is the fast calculation of the balances and caching in memory.
* The problem is displaying the amounts once they are loaded.
*/
public class CalculateRunningBalanceTask2
extends AsyncTask<Void, Void, HashMap<Integer, Money>> {
/**
* Create the task.
* @param context Context
* @param accountId Id of the account for which to load the balances.
* @param startingDate The date, inclusive, from which to calculate the running balance.
*/
public CalculateRunningBalanceTask2(Context context, int accountId, Date startingDate,
Bundle selection) {
this.context = context.getApplicationContext();
this.accountId = accountId;
this.startingDate = startingDate;
this.selectionBundle = selection;
}
private Context context;
private HashMap<Integer, Money> balances;
private int accountId;
private Date startingDate;
private Bundle selectionBundle;
/**
* Override this method to perform a computation on a background thread. The
* specified parameters are the parameters passed to {@link #execute}
* by the caller of this task.
* <p/>
* This method can call {@link #publishProgress} to publish updates
* on the UI thread.
*
* @param params The parameters of the task.
* @return A result, defined by the subclass of this task.
* @see #onPreExecute()
* @see #onPostExecute
* @see #publishProgress
*/
@Override
protected HashMap<Integer, Money> doInBackground(Void... params) {
try {
return runTask();
} catch (Exception ex) {
Timber.e(ex, "balancing amount");
}
return null;
}
@Override
protected void onPostExecute(HashMap<Integer, Money> result) {
EventBus.getDefault().post(new RunningBalanceCalculatedEvent(result));
}
private HashMap<Integer, Money> runTask() {
// load data
Cursor c = loadData();
if (c == null) return null;
int records = c.getCount();
if (balances != null && records == balances.size()) return null;
if (c.getCount() <= 0) return null;
Money startingBalance = null;
AccountService accountService = new AccountService(this.context);
AccountTransactionDisplay tx = new AccountTransactionDisplay();
int originalPosition = c.getPosition();
balances = new HashMap<>();
String transType;
Money amount = MoneyFactory.fromBigDecimal(BigDecimal.ZERO);
Money runningBalance = MoneyFactory.fromBigDecimal(BigDecimal.ZERO);
// populate balance amounts
// Move from the earliest record towards the newer ones.
int i = c.getCount() - 1;
while (c.moveToPosition(i)) {
// load the initial balance based on the date of the first transaction
if (startingBalance == null) {
// Get starting balance on the given day.
startingBalance = accountService.loadInitialBalance(this.accountId);
String date = new MmxDate(this.startingDate).minusDays(1)
.toIsoString();
Money balanceOnDate = accountService.calculateBalanceOn(this.accountId, date);
startingBalance = startingBalance.add(balanceOnDate);
runningBalance = startingBalance;
}
// adjust the balance for each transaction.
tx.loadFromCursor(c);
// Exclude Void transactions from calculation.
TransactionStatuses status = tx.getStatus();
if (!status.equals(TransactionStatuses.VOID)) {
transType = tx.getTransactionTypeName();
switch (TransactionTypes.valueOf(transType)) {
case Withdrawal:
amount = tx.getAmount();
break;
case Deposit:
amount = tx.getAmount();
break;
case Transfer:
int accountId = tx.getAccountId();
if (accountId == this.accountId) {
amount = tx.getAmount();
} else {
amount = tx.getToAmount();
}
break;
}
runningBalance = runningBalance.add(amount);
}
this.balances.put(tx.getId(), runningBalance);
i--;
}
// set back to the original position.
c.moveToPosition(originalPosition);
return this.balances;
}
private Cursor loadData() {
String where = this.selectionBundle.getString(AllDataListFragment.KEY_ARGUMENTS_WHERE);
String sort = this.selectionBundle.getString(AllDataListFragment.KEY_ARGUMENTS_SORT);
QueryAllDataRepository repo = new QueryAllDataRepository(this.context);
return repo.query(where, sort);
}
}