package com.evancharlton.mileage.dao;
import com.evancharlton.mileage.R;
import com.evancharlton.mileage.dao.Dao.DataObject;
import com.evancharlton.mileage.provider.tables.FillupsFieldsTable;
import com.evancharlton.mileage.provider.tables.FillupsTable;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import java.util.ArrayList;
import java.util.Date;
@DataObject(path = FillupsTable.URI)
public class Fillup extends Dao {
public static final String TOTAL_COST = "total_cost";
public static final String UNIT_PRICE = "price";
public static final String VOLUME = "volume";
public static final String ODOMETER = "odometer";
public static final String DATE = "timestamp"; // ms since epoch
public static final String PARTIAL = "is_partial";
public static final String VEHICLE_ID = "vehicle_id";
public static final String LATITUDE = "latitude";
public static final String LONGITUDE = "longitude";
public static final String COMMENT = "comment";
public static final String RESTART = "restart";
public static final String ECONOMY = "economy";
@Range.Positive
@Validate(R.string.error_no_vehicle_specified)
@Column(type = Column.INTEGER, name = VEHICLE_ID)
protected long mVehicleId;
@Range.Positive
@Validate(R.string.error_no_odometer_specified)
@Column(type = Column.DOUBLE, name = ODOMETER)
protected double mOdometer;
@Past
@Validate(R.string.error_date_in_past)
@Column(type = Column.TIMESTAMP, name = DATE)
protected Date mDate;
@Range.Positive
@Validate(R.string.error_no_volume_specified)
@Column(type = Column.DOUBLE, name = VOLUME)
protected double mVolume;
@Range.Positive
@Validate(R.string.error_no_price_specified)
@Column(type = Column.DOUBLE, name = UNIT_PRICE)
protected double mUnitPrice;
@Range.Positive
@Validate(R.string.error_no_total_cost_specified)
@Column(type = Column.DOUBLE, name = TOTAL_COST)
protected double mTotalCost;
@Validate
@Column(type = Column.BOOLEAN, name = PARTIAL, value = 0)
protected boolean mIsPartial;
@Validate
@Column(type = Column.BOOLEAN, name = RESTART)
protected boolean mIsRestart;
@Validate
@Range.Positive
@Column(type = Column.DOUBLE, name = ECONOMY)
protected double mEconomy;
@Validate
@Column(type = Column.DOUBLE, name = LATITUDE)
protected double mLatitude;
@Validate
@Column(type = Column.DOUBLE, name = LONGITUDE)
protected double mLongitude;
private final ArrayList<FillupField> mFields = new ArrayList<FillupField>();
private Fillup mNext = null;
private Fillup mPrevious = null;
public Fillup(ContentValues contentValues) {
super(contentValues);
}
public Fillup(Cursor cursor) {
super(cursor);
}
@Override
protected void preValidate() {
getVolume();
getUnitPrice();
getTotalCost();
if (mDate == null) {
mDate = new Date(System.currentTimeMillis());
}
}
public Fillup loadPrevious(Context context) {
Fillup previous = null;
if (!mIsRestart) {
Uri uri = FillupsTable.BASE_URI;
String[] projection = FillupsTable.PROJECTION;
Cursor c =
context.getContentResolver().query(uri, projection,
Fillup.VEHICLE_ID + " = ? AND " + ODOMETER + " < ?", new String[] {
String.valueOf(getVehicleId()), String.valueOf(getOdometer())
}, Fillup.ODOMETER + " desc");
if (c.getCount() >= 1) {
c.moveToFirst();
previous = new Fillup(c);
}
c.close();
}
return previous;
}
public Fillup loadNext(Context context) {
Fillup next = null;
if (!mIsRestart) {
Uri uri = FillupsTable.BASE_URI;
String[] projection = FillupsTable.PROJECTION;
Cursor c =
context.getContentResolver().query(uri, projection,
Fillup.VEHICLE_ID + " = ? AND " + ODOMETER + " > ?", new String[] {
String.valueOf(getVehicleId()), String.valueOf(getOdometer())
}, Fillup.ODOMETER + " asc");
if (c.getCount() >= 1) {
c.moveToFirst();
next = new Fillup(c);
}
c.close();
}
return next;
}
public double getEconomy() {
return mEconomy;
}
public ArrayList<FillupField> getFields() {
return mFields;
}
/**
* Note that this is run synchronously!
*
* @param context
* @return
*/
public ArrayList<FillupField> getFields(Context context) {
if (mFields.size() == 0) {
Uri uri = ContentUris.withAppendedId(FillupsFieldsTable.FILLUPS_FIELDS_URI, getId());
Cursor c =
context.getContentResolver().query(uri, FillupsFieldsTable.PROJECTION, null,
null, null);
if (c.getCount() > 0) {
c.moveToFirst();
FillupField field = new FillupField(c);
mFields.add(field);
}
c.close();
}
return mFields;
}
public Fillup getNext() {
return mNext;
}
public double getOdometer() {
return mOdometer;
}
public double getDistance() {
return getOdometer() - mPrevious.getOdometer();
}
public Fillup getPrevious() {
return mPrevious;
}
public long getTimestamp() {
if (mDate == null) {
mDate = new Date();
}
return mDate.getTime();
}
public double getTotalCost() {
if (mTotalCost == 0 && (mVolume > 0 && mUnitPrice > 0)) {
mTotalCost = mVolume * mUnitPrice;
setInMemoryDataChanged();
}
return mTotalCost;
}
public double getUnitPrice() {
if (mUnitPrice == 0 && (mVolume > 0 && mTotalCost > 0)) {
mUnitPrice = mTotalCost / mVolume;
setInMemoryDataChanged();
}
return mUnitPrice;
}
public long getVehicleId() {
return mVehicleId;
}
public double getVolume() {
if (mVolume == 0 && (mTotalCost > 0 && mUnitPrice > 0)) {
mVolume = mTotalCost / mUnitPrice;
setInMemoryDataChanged();
}
return mVolume;
}
public double getCostPerDistance() {
if (hasPrevious() && getDistance() > 0) {
return getTotalCost() / getDistance();
}
return -1D;
}
public boolean hasNext() {
return mNext != null;
}
public boolean hasPrevious() {
return mPrevious != null;
}
public boolean isPartial() {
return mIsPartial;
}
public boolean isRestart() {
return mIsRestart;
}
public double getLongitude() {
return mLongitude;
}
public double getLatitude() {
return mLatitude;
}
public void setEconomy(double economy) {
mEconomy = economy;
setInMemoryDataChanged();
}
public void setFields(ArrayList<FillupField> fields) {
mFields.clear();
mFields.addAll(fields);
}
public void setNext(Fillup next) {
mNext = next;
}
public void setOdometer(double odometer) {
mOdometer = odometer;
}
public void setPartial(boolean partial) {
mIsPartial = partial;
}
public void setPrevious(Fillup previous) {
mPrevious = previous;
}
public void setRestart(boolean restart) {
mIsRestart = restart;
}
public void setTimestamp(long timestamp) {
if (mDate == null) {
mDate = new Date(timestamp);
} else {
mDate.setTime(timestamp);
}
}
public void setTotalCost(double totalCost) {
mTotalCost = totalCost;
}
public void setUnitPrice(double unitPrice) {
mUnitPrice = unitPrice;
}
public void setVehicleId(long id) {
mVehicleId = id;
}
public void setVolume(double volume) {
mVolume = volume;
}
public void setLatitude(double latitude) {
mLatitude = latitude;
}
public void setLongitude(double longitude) {
mLongitude = longitude;
}
/**
* @return true if this fillup should be counted in an economy calculation.
*/
public boolean validForEconomy() {
if (!hasPrevious()) {
return false;
}
if (isPartial()) {
// Walk the chain to see if there's a following complete fillup.
Fillup fillup = this;
while (fillup.hasNext()) {
if (fillup.isPartial() == false) {
// Found a following complete; this is a valid fillup.
return true;
}
fillup = fillup.getNext();
}
return false;
}
return true;
}
}