package com.evancharlton.mileage;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ListActivity;
import android.content.ContentUris;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.view.ContextMenu;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ContextMenu.ContextMenuInfo;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
import android.widget.TextView;
import android.widget.AdapterView.AdapterContextMenuInfo;
import com.evancharlton.mileage.calculators.CalculationEngine;
public class HistoryView extends ListActivity implements View.OnCreateContextMenuListener {
public static final int MENU_IMPORT_EXPORT = Menu.FIRST;
public static final int MENU_EXPORT = Menu.FIRST;
public static final int MENU_EXPORT_DB = Menu.FIRST + 1;
public static final int MENU_EXPORT_SQL = Menu.FIRST + 2;
public static final int MENU_EXPORT_CSV = Menu.FIRST + 3;
public static final int MENU_IMPORT = Menu.FIRST + 4;
public static final int MENU_IMPORT_DB = Menu.FIRST + 5;
public static final int MENU_IMPORT_SQL = Menu.FIRST + 6;
public static final int MENU_IMPORT_CSV = Menu.FIRST + 7;
public static final int MENU_DELETE = Menu.FIRST;
public static final int MENU_EDIT = Menu.FIRST + 1;
public static final int DELETE_DIALOG_ID = 1;
public static final String TAG = "HistoryList";
public static final int COL_ID = 0;
public static final int COL_AMOUNT = 1;
public static final int COL_COST = 2;
public static final int COL_DATE = 3;
public static final int COL_COMMENT = 4;
public static final int COL_VEHICLEID = 5;
public static final int COL_MILEAGE = 6;
private Map<Integer, String> m_vehicleTitles = new HashMap<Integer, String>();
private Map<Integer, Double> m_avgEconomies = new HashMap<Integer, Double>();
private HashMap<Integer, HashMap<Double, Double>> m_history;
private AlertDialog m_deleteDialog;
private long m_deleteId;
private PreferencesProvider m_prefs;
private CalculationEngine m_calcEngine;
private static final String[] PROJECTIONS = new String[] {
FillUps._ID,
FillUps.AMOUNT,
FillUps.COST,
FillUps.DATE,
FillUps.COMMENT,
FillUps.VEHICLE_ID,
FillUps.MILEAGE
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
m_deleteDialog = new AlertDialog.Builder(this).create();
m_deleteDialog.setMessage(getString(R.string.confirm_delete));
m_deleteDialog.setCancelable(false);
m_deleteDialog.setButton(getString(R.string.yes), m_deleteListener);
m_deleteDialog.setButton2(getString(R.string.no), m_deleteListener);
}
public void onResume() {
super.onResume();
setDefaultKeyMode(DEFAULT_KEYS_SHORTCUT);
Intent intent = getIntent();
if (intent.getData() == null) {
intent.setData(FillUps.CONTENT_URI);
}
getListView().setOnCreateContextMenuListener(this);
String[] from = new String[] {
FillUps.AMOUNT,
FillUps.COST,
FillUps.DATE,
FillUps.COMMENT,
FillUps.VEHICLE_ID,
FillUps.MILEAGE
};
int[] to = new int[] {
R.id.history_amount,
R.id.history_price,
R.id.history_date,
R.id.history_comment,
R.id.history_vehicle,
R.id.history_mileage
};
String[] projection = new String[] {
Vehicles._ID,
Vehicles.TITLE
};
m_prefs = PreferencesProvider.getInstance(this);
m_calcEngine = m_prefs.getCalculator();
m_history = new HashMap<Integer, HashMap<Double, Double>>();
Cursor vehicleCursor = managedQuery(Vehicles.CONTENT_URI, projection, null, null, Vehicles.DEFAULT_SORT_ORDER);
vehicleCursor.moveToFirst();
while (vehicleCursor.isAfterLast() == false) {
String title = vehicleCursor.getString(1);
int index = vehicleCursor.getInt(0);
m_vehicleTitles.put(index, title);
m_history.put(index, new HashMap<Double, Double>());
vehicleCursor.moveToNext();
}
Cursor historyCursor = managedQuery(FillUps.CONTENT_URI, PROJECTIONS, FillUps.AMOUNT + " != ''", null, FillUps.DEFAULT_SORT_ORDER);
if (historyCursor.getCount() > 0) {
historyCursor.moveToFirst();
while (historyCursor.isAfterLast() == false) {
int vehicleId = historyCursor.getInt(COL_VEHICLEID);
HashMap<Double, Double> data = m_history.get(vehicleId);
if (data == null) {
// invalid vehicle ID
continue;
}
double mileage = historyCursor.getDouble(COL_MILEAGE);
double amount = historyCursor.getDouble(COL_AMOUNT);
data.put(mileage, amount);
historyCursor.moveToNext();
}
historyCursor.moveToFirst();
// calculate their respective economies
for (Integer vehicleId : m_history.keySet()) {
HashMap<Double, Double> data = m_history.get(vehicleId);
Double[] keys = data.keySet().toArray(new Double[data.keySet().size()]);
Arrays.sort(keys);
if (keys.length == 0) {
data.put(0D, null);
continue;
}
if (keys.length == 1) {
// can't calculate the avg economy
data.put(keys[0], null);
continue;
}
double total_miles = Math.abs(keys[0] - keys[keys.length - 1]);
double total_fuel = 0.0D;
for (int i = keys.length - 1; i > 0; i--) {
double key = keys[i];
double miles = keys[i] - keys[i - 1];
double amount = data.get(key);
data.put(key, m_calcEngine.calculateEconomy(miles, amount));
total_fuel += amount;
}
double mileage = m_calcEngine.calculateEconomy(total_miles, total_fuel);
m_avgEconomies.put(vehicleId, mileage);
}
}
ListView list = getListView();
list.setFocusable(true);
list.setOnCreateContextMenuListener(this);
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, R.layout.history, historyCursor, from, to);
adapter.setViewBinder(m_viewBinder);
setListAdapter(adapter);
}
@Override
protected void onListItemClick(ListView lv, View v, int position, long id) {
super.onListItemClick(lv, v, position, id);
Uri uri = ContentUris.withAppendedId(getIntent().getData(), id);
Intent intent = new Intent();
intent.setData(uri);
intent.setClass(HistoryView.this, FillUpView.class);
startActivity(intent);
}
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
Mileage.createMenu(menu);
HelpDialog.injectHelp(menu, 'h');
return true;
}
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo info) {
menu.setHeaderTitle(R.string.operations);
menu.add(Menu.NONE, MENU_DELETE, Menu.NONE, R.string.delete);
menu.add(Menu.NONE, MENU_EDIT, Menu.NONE, R.string.edit_fillup);
}
public boolean onContextItemSelected(MenuItem item) {
AdapterView.AdapterContextMenuInfo info = null;
try {
info = (AdapterContextMenuInfo) item.getMenuInfo();
switch (item.getItemId()) {
case MENU_DELETE:
m_deleteId = getListAdapter().getItemId(info.position);
showDialog(DELETE_DIALOG_ID);
return true;
case MENU_EDIT:
long id = getListAdapter().getItemId(info.position);
onListItemClick(getListView(), info.targetView, info.position, id);
return true;
}
} catch (ClassCastException e) {
// fail gracefully?
}
return super.onContextItemSelected(item);
}
public boolean onOptionsItemSelected(MenuItem item) {
boolean ret = Mileage.parseMenuItem(item, this);
if (ret) {
return true;
}
switch (item.getItemId()) {
case HelpDialog.MENU_HELP:
HelpDialog.create(this, R.string.help_title_history, R.string.help_history);
return true;
}
return super.onOptionsItemSelected(item);
}
public Dialog onCreateDialog(int id) {
switch (id) {
case DELETE_DIALOG_ID:
return m_deleteDialog;
}
return super.onCreateDialog(id);
}
private void delete() {
Uri uri = ContentUris.withAppendedId(FillUps.CONTENT_URI, m_deleteId);
getContentResolver().delete(uri, null, null);
}
private SimpleCursorAdapter.ViewBinder m_viewBinder = new SimpleCursorAdapter.ViewBinder() {
public boolean setViewValue(View view, Cursor cursor, int columnIndex) {
String val;
switch (columnIndex) {
case 1:
double gallons = cursor.getDouble(columnIndex);
val = m_prefs.format(gallons) + m_calcEngine.getVolumeUnitsAbbr();
((TextView) view).setText(val);
return true;
case 2:
double price = cursor.getDouble(columnIndex);
val = m_prefs.getCurrency() + m_prefs.format(price) + "/" + m_calcEngine.getVolumeUnitsAbbr().trim();
((TextView) view).setText(val);
return true;
case 3:
long time = cursor.getLong(columnIndex);
Date date = new Date(time);
String text = m_prefs.format(date);
((TextView) view).setText(text);
return true;
case 5:
int id = cursor.getInt(columnIndex);
val = m_vehicleTitles.get(id);
boolean hide = true;
if (m_vehicleTitles.size() == 1) {
hide = true;
} else {
if (val != null) {
((TextView) view).setText(val);
hide = false;
}
}
if (hide) {
view.setVisibility(View.GONE);
}
return true;
case COL_MILEAGE:
double mileage = cursor.getDouble(columnIndex);
if (!cursor.isLast()) {
int vehicleId = cursor.getInt(COL_VEHICLEID);
Double mpg = m_history.get(vehicleId).get(mileage);
if (mpg == null) {
// can't do anything
return true;
}
double avgMpg = m_avgEconomies.get(vehicleId);
TextView tv = (TextView) view;
int color = 0xFF666666;
if (m_calcEngine.better(mpg, avgMpg)) {
color = 0xFF0AB807;
} else if (mpg == avgMpg) {
color = 0xFF2469FF;
} else {
color = 0xFFD90000;
}
tv.setTextColor(color);
tv.setText(m_prefs.format(mpg) + m_calcEngine.getEconomyUnits());
}
return true;
}
return false;
}
};
private DialogInterface.OnClickListener m_deleteListener = new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
if (which == Dialog.BUTTON1) {
delete();
}
}
};
}