package ru.orangesoftware.financisto2.activity;
import android.app.ListActivity;
import android.content.Intent;
import android.graphics.Color;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageButton;
import android.widget.TextView;
import ru.orangesoftware.financisto2.R;
import ru.orangesoftware.financisto2.adapter.CreditCardStatementAdapter;
import ru.orangesoftware.financisto2.db.DatabaseAdapter;
import ru.orangesoftware.financisto2.db.DatabaseAdapter_;
import ru.orangesoftware.financisto2.model.*;
import ru.orangesoftware.financisto2.utils.MonthlyViewPlanner;
import ru.orangesoftware.financisto2.utils.PinProtection;
import ru.orangesoftware.financisto2.utils.TransactionList;
import ru.orangesoftware.financisto2.utils.Utils;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
/**
* Display the credit card bill, including scheduled and future transactions for a given period.
* Display only expenses, ignoring payments (positive values) in Credit Card accounts.
* @author Abdsandryk
*/
public class MonthlyViewActivity extends ListActivity {
public static final String ACCOUNT_EXTRA = "account_id";
public static final String BILL_PREVIEW_EXTRA = "bill_preview";
private DatabaseAdapter db;
private long accountId = 0;
private Account account;
private Currency currency;
private boolean isCreditCard = false;
private boolean isStatementPreview = false;
private String title;
private int closingDay = 0;
private int paymentDay = 0;
private int month = 0;
private int year = 0;
private Calendar closingDate;
private Utils u;
private MonthlyPreviewTask currentTask;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.monthly_view);
u = new Utils(this);
Intent intent = getIntent();
if (intent != null) {
accountId = intent.getLongExtra(ACCOUNT_EXTRA, 0);
isStatementPreview = intent.getBooleanExtra(BILL_PREVIEW_EXTRA, false);
}
initialize();
}
@Override
public void onDestroy() {
cancelCurrentTask();
super.onDestroy();
}
private void cancelCurrentTask() {
if (currentTask != null) {
currentTask.cancel(true);
currentTask = null;
}
}
@Override
protected void onPause() {
super.onPause();
PinProtection.lock(this);
}
@Override
protected void onResume() {
super.onResume();
PinProtection.unlock(this);
}
/**
* Initialize data and GUI elements.
*/
private void initialize() {
// get account data
db = DatabaseAdapter_.getInstance_(this);
// set currency based on account
account = db.getAccount(accountId);
if (month==0 && year==0) {
// get current month and year in first launch
Calendar cal = Calendar.getInstance();
month = cal.get(Calendar.MONTH) + 1;
year = cal.get(Calendar.YEAR);
}
// set part of the title, based on account name: "<CCARD> Bill"
if (account != null) {
// get account type
isCreditCard = AccountType.valueOf(account.type).isCreditCard;
currency = account.currency;
if (isCreditCard) {
if (isStatementPreview) {
// assuming that expensesOnly is true only if payment and closing days > 0 [BlotterActivity]
title = getString(R.string.ccard_statement_title);
String accountTitle = account.title;
if (account.title==null || account.title.length()==0) {
accountTitle = account.cardIssuer;
}
String toReplace = getString(R.string.ccard_par);
title = title.replaceAll(toReplace, accountTitle);
paymentDay = account.paymentDay;
closingDay = account.closingDay;
// set activity window title
this.setTitle(R.string.ccard_statement);
setCCardTitle();
setCCardInterval();
} else {
title = (account.title==null|| account.title.length()==0? account.cardIssuer: account.title);
paymentDay = 1;
closingDay = 31;
setTitle();
setInterval();
// set payment date and label on total bar
TextView totalLabel = (TextView) findViewById(R.id.monthly_result_label);
totalLabel.setText(getResources().getString(R.string.monthly_result));
}
} else {
if (account.title==null|| account.title.length()==0) {
if (isCreditCard) {
// title = <CARD_ISSUER>
title = account.cardIssuer;
} else {
// title = <ACCOUNT_TYPE_TITLE>
AccountType type = AccountType.valueOf(account.type);
title = getString(type.titleId);
}
} else {
// title = <TITLE>
title = account.title;
}
paymentDay = 1;
closingDay = 31;
setTitle();
setInterval();
// set payment date and label on total bar
TextView totalLabel = (TextView) findViewById(R.id.monthly_result_label);
totalLabel.setText(getResources().getString(R.string.monthly_result));
}
ImageButton bPrevious = (ImageButton) findViewById(R.id.bt_month_previous);
bPrevious.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
month--;
if (month < 1) {
month = 12;
year--;
}
if (isCreditCard) {
if (isStatementPreview) {
setCCardTitle();
setCCardInterval();
} else {
setTitle();
setInterval();
}
} else {
setTitle();
setInterval();
}
}
});
ImageButton bNext = (ImageButton) findViewById(R.id.bt_month_next);
bNext.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
month++;
if (month > 12) {
month = 1;
year++;
}
if (isCreditCard) {
if (isStatementPreview) {
setCCardTitle();
setCCardInterval();
} else {
setTitle();
setInterval();
}
} else {
setTitle();
setInterval();
}
}
});
}
}
/**
* Configure the interval based on the bill period of a credit card.
* Attention:
* Calendar.MONTH = 0 to 11
* integer month = 1 to 12
*/
private void setCCardInterval() {
Calendar close = getClosingDate(month, year);
Calendar open;
if (month>1) {
// closing date from previous month
open = getClosingDate(month-1, year);
} else {
open = getClosingDate(12, year-1);
}
// add one day to the closing date of previous month
open.add(Calendar.DAY_OF_MONTH, +1);
// adjust time for closing day
close.set(Calendar.HOUR_OF_DAY, 23);
close.set(Calendar.MINUTE, 59);
close.set(Calendar.SECOND, 59);
this.closingDate = new GregorianCalendar(close.get(Calendar.YEAR),
close.get(Calendar.MONTH),
close.get(Calendar.DAY_OF_MONTH));
// Verify custom closing date
int periodKey = Integer.parseInt(Integer.toString(close.get(Calendar.MONTH))+
Integer.toString(close.get(Calendar.YEAR)));
int cd = db.getCustomClosingDay(accountId, periodKey);
if (cd>0) {
// use custom closing day
close.set(Calendar.DAY_OF_MONTH, cd);
}
// Verify custom opening date = closing day of previous month + 1
periodKey = Integer.parseInt(Integer.toString(open.get(Calendar.MONTH))+
Integer.toString(open.get(Calendar.YEAR)));
int od = db.getCustomClosingDay(accountId, periodKey);
if (od>0) {
// use custom closing day
open.set(Calendar.DAY_OF_MONTH, od);
open.add(Calendar.DAY_OF_MONTH, +1);
}
fillData(open, close);
}
/**
* Configure the interval in a monthly perspective.
* Attention:
* Calendar.MONTH = 0 to 11
* integer month = 1 to 12
*/
private void setInterval() {
Calendar close = new GregorianCalendar(year, month-1, getLastDayOfMonth(month, year));
Calendar open = new GregorianCalendar(year, month-1, 1);
// adjust time for closing day
close.set(Calendar.HOUR_OF_DAY, 23);
close.set(Calendar.MINUTE, 59);
close.set(Calendar.SECOND, 59);
close.set(Calendar.MILLISECOND, 999);
fillData(open, close);
}
// Returns the day on which the credit card bill closes for a given month/year.
private Calendar getClosingDate(int month, int year) {
int m = month;
if (closingDay > paymentDay) {
m--;
}
int maxDay = getLastDayOfMonth(m, year);
int day = closingDay;
if (closingDay>maxDay) {
day = maxDay;
}
return new GregorianCalendar(year, m-1, day);
}
private int getLastDayOfMonth(int month, int year) {
Calendar calCurr = GregorianCalendar.getInstance();
calCurr.set(year, month-1, 1); // Months are 0 to 11
return calCurr.getActualMaximum(GregorianCalendar.DAY_OF_MONTH);
}
private class MonthlyPreviewTask extends AsyncTask<Void, Void, TransactionList> {
private final Date open;
private final Date close;
private final Date now;
private MonthlyPreviewTask(Date open, Date close, Date now) {
this.open = open;
this.close = close;
this.now = now;
}
@Override
protected void onPreExecute() {
((TextView)findViewById(android.R.id.empty)).setText(R.string.calculating);
}
@Override
protected TransactionList doInBackground(Void... voids) {
MonthlyViewPlanner planner = new MonthlyViewPlanner(db, account, isStatementPreview, open, close, now);
TransactionList transactions;
if (isStatementPreview) {
transactions = planner.getCreditCardStatement();
} else {
transactions = planner.getPlannedTransactionsWithTotals();
}
return transactions;
}
@Override
protected void onPostExecute(TransactionList monthlyPreviewReport) {
List<TransactionInfo> transactions = monthlyPreviewReport.transactions;
long total = monthlyPreviewReport.totals[0].balance;
if (transactions == null || transactions.isEmpty()) {
displayNoTransactions();
} else { // display data
// Mapping data to view
CreditCardStatementAdapter expenses = new CreditCardStatementAdapter(MonthlyViewActivity.this, R.layout.credit_card_transaction, transactions, currency, accountId);
expenses.setStatementPreview(isStatementPreview);
setListAdapter(expenses);
// calculate total
// display total
TextView totalText = (TextView)findViewById(R.id.monthly_result);
if (isStatementPreview) {
u.setAmountText(totalText, currency, (-1)*total, false);
totalText.setTextColor(Color.BLACK);
} else {
if (total<0) {
u.setAmountText(totalText, currency, (-1)*total, false);
u.setNegativeColor(totalText);
} else {
u.setAmountText(totalText, currency, total, false);
u.setPositiveColor(totalText);
}
}
}
}
}
/**
* Get data for a given period and display the related credit card expenses.
* @param open Start of period.
* @param close End of period.
*/
private void fillData(Calendar open, Calendar close) {
cancelCurrentTask();
currentTask = new MonthlyPreviewTask(open.getTime(), close.getTime(), new Date());
currentTask.execute();
}
private void displayNoTransactions() {
TextView totalText = (TextView)findViewById(R.id.monthly_result);
// display total = 0
u.setAmountText(totalText, currency, 0, false);
totalText.setTextColor(Color.BLACK);
// hide list and display empty message
((TextView)findViewById(android.R.id.empty)).setText(R.string.no_transactions);
setListAdapter(null);
}
/**
* Adjust the title based on the credit card's payment day.
*/
private void setCCardTitle() {
Calendar date = new GregorianCalendar(year, month-1, paymentDay);
String monthStr = Integer.toString(date.get(Calendar.MONTH) + 1);
String yearStr = Integer.toString(date.get(Calendar.YEAR));
String paymentDayStr;
if (paymentDay < 10) {
paymentDayStr = "0"+paymentDay;
} else {
paymentDayStr = Integer.toString(paymentDay);
}
if (monthStr.length()<2) {
monthStr = "0"+ monthStr;
}
String pd = paymentDayStr + "/" + monthStr + "/" + yearStr;
// set payment date and label on title bar
TextView label = (TextView)findViewById(R.id.monthly_view_title);
label.setText(title+"\n" + pd);
// set payment date and label on total bar
TextView totalLabel = (TextView) findViewById(R.id.monthly_result_label);
totalLabel.setText(getResources().getString(R.string.bill_on)+" "+pd);
}
/**
* Adjust the title based on the credit card's payment day.
*/
private void setTitle() {
Calendar date = new GregorianCalendar(year, month-1, 1);
SimpleDateFormat dateFormat = new SimpleDateFormat("MMMMM yyyy");
String pd = dateFormat.format(date.getTime());
TextView label = (TextView)findViewById(R.id.monthly_view_title);
label.setText(title+"\n" + pd);
}
// Update view
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (resultCode) {
case RESULT_OK:
int update = data.getIntExtra(CCardStatementClosingDayActivity.UPDATE_VIEW, 0);
if (update>0) {
setCCardTitle();
setCCardInterval();
}
break;
case RESULT_CANCELED:
break;
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Allow changes on credit card closing date (for statements preview only)
if (isStatementPreview) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.statement_preview_menu, menu);
return true;
} else {
return super.onCreateOptionsMenu(menu);
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
super.onOptionsItemSelected(item);
Intent intent = new Intent(this, CCardStatementClosingDayActivity.class);
int closingDay = getClosingDate(month, year).get(Calendar.DAY_OF_MONTH);
switch (item.getItemId()) {
case R.id.opt_menu_closing_day:
// call credit card closing day sending period
intent.putExtra(CCardStatementClosingDayActivity.PERIOD_MONTH, closingDate.get(Calendar.MONTH));
intent.putExtra(CCardStatementClosingDayActivity.PERIOD_YEAR, closingDate.get(Calendar.YEAR));
intent.putExtra(CCardStatementClosingDayActivity.ACCOUNT, accountId);
intent.putExtra(CCardStatementClosingDayActivity.REGULAR_CLOSING_DAY, closingDay);
startActivityForResult(intent, 16);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
}