package co.smartreceipts.android.model.impl;
import android.content.Context;
import android.os.Parcel;
import android.support.annotation.NonNull;
import com.google.common.base.Preconditions;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.sql.Date;
import java.util.TimeZone;
import co.smartreceipts.android.model.Distance;
import co.smartreceipts.android.model.Price;
import co.smartreceipts.android.model.PriceCurrency;
import co.smartreceipts.android.model.Trip;
import co.smartreceipts.android.model.factory.PriceBuilderFactory;
import co.smartreceipts.android.model.utils.ModelUtils;
import co.smartreceipts.android.sync.model.SyncState;
import co.smartreceipts.android.sync.model.impl.DefaultSyncState;
/**
* An immutable {@link co.smartreceipts.android.model.Distance} implementation to track distance.
*/
public final class ImmutableDistanceImpl implements Distance {
private static final int DEFAULT_RATE_DECIMAL_PRECISION = 3;
private static final int ROUNDING_PRECISION = RATE_PRECISION + 2;
private final int mId;
private final Trip mTrip;
private final String mLocation;
private final BigDecimal mDistance;
private final Date mDate;
private final TimeZone mTimezone;
private final BigDecimal mRate;
private final Price mPrice;
private final String mComment;
private final SyncState mSyncState;
public ImmutableDistanceImpl(int id, @NonNull Trip trip, String location, BigDecimal distance, BigDecimal rate, PriceCurrency currency, Date date, TimeZone timeZone, String comment) {
this(id, trip, location, distance, rate, currency, date, timeZone, comment, new DefaultSyncState());
}
public ImmutableDistanceImpl(int id, @NonNull Trip trip, String location, BigDecimal distance, BigDecimal rate, PriceCurrency currency, Date date, TimeZone timeZone, String comment, @NonNull SyncState syncState) {
mId = id;
mTrip = Preconditions.checkNotNull(trip);
mLocation = location;
mDistance = distance.setScale(ROUNDING_PRECISION, RoundingMode.HALF_UP);
mRate = rate.setScale(ROUNDING_PRECISION, RoundingMode.HALF_UP);
final int precision = ModelUtils.getDecimalFormattedValue(distance.multiply(rate), DEFAULT_RATE_DECIMAL_PRECISION).endsWith("0") ? Price.DEFAULT_DECIMAL_PRECISION : DEFAULT_RATE_DECIMAL_PRECISION;
mPrice = new PriceBuilderFactory().setCurrency(currency).setPrice(distance.multiply(rate)).setDecimalPrecision(precision).build();
mDate = date;
mTimezone = timeZone;
mComment = comment;
mSyncState = Preconditions.checkNotNull(syncState);
}
private ImmutableDistanceImpl(Parcel in) {
mId = in.readInt();
mTrip = in.readParcelable(Trip.class.getClassLoader());
mLocation = in.readString();
mDistance = (BigDecimal) in.readValue(BigDecimal.class.getClassLoader());
long tmpDate = in.readLong();
mDate = tmpDate != -1 ? new Date(tmpDate) : null;
mTimezone = TimeZone.getTimeZone(in.readString());
mRate = (BigDecimal) in.readValue(BigDecimal.class.getClassLoader());
mPrice = in.readParcelable(Price.class.getClassLoader());
mComment = in.readString();
mSyncState = in.readParcelable(SyncState.class.getClassLoader());
}
@Override
public int getId() {
return mId;
}
@Override
@NonNull
public Trip getTrip() {
return mTrip;
}
@Override
public String getLocation() {
return mLocation;
}
@Override
public BigDecimal getDistance() {
return mDistance;
}
@Override
public String getDecimalFormattedDistance() {
return ModelUtils.getDecimalFormattedValue(mDistance);
}
@Override
public Date getDate() {
return mDate;
}
@Override
public String getFormattedDate(Context context, String separator) {
return ModelUtils.getFormattedDate(mDate, mTimezone, context, separator);
}
@Override
public TimeZone getTimeZone() {
return mTimezone;
}
@Override
public BigDecimal getRate() {
return mRate;
}
@Override
public String getDecimalFormattedRate() {
return ModelUtils.getDecimalFormattedValue(mRate, DEFAULT_RATE_DECIMAL_PRECISION);
}
@Override
public String getCurrencyFormattedRate() {
final int precision = getDecimalFormattedRate().endsWith("0") ? Price.DEFAULT_DECIMAL_PRECISION : DEFAULT_RATE_DECIMAL_PRECISION;
return ModelUtils.getCurrencyFormattedValue(mRate, mPrice.getCurrency(), precision);
}
@NonNull
@Override
public Price getPrice() {
return mPrice;
}
@NonNull
@Override
public SyncState getSyncState() {
return mSyncState;
}
@Override
public String getComment() {
return mComment;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mId);
dest.writeParcelable(mTrip, flags);
dest.writeString(mLocation);
dest.writeValue(mDistance);
dest.writeLong(mDate != null ? mDate.getTime() : -1L);
dest.writeString(mTimezone.getID());
dest.writeValue(mRate);
dest.writeParcelable(mPrice, flags);
dest.writeString(mComment);
dest.writeParcelable(mSyncState, flags);
}
public static final Creator<ImmutableDistanceImpl> CREATOR = new Creator<ImmutableDistanceImpl>() {
@Override
public ImmutableDistanceImpl createFromParcel(Parcel in) {
return new ImmutableDistanceImpl(in);
}
@Override
public ImmutableDistanceImpl[] newArray(int size) {
return new ImmutableDistanceImpl[size];
}
};
@Override
public String toString() {
return "Distance [" + "mLocation=" + mLocation + ", mDistance=" + mDistance + ", mDate=" + mDate + ", mTimezone=" + mTimezone + ", mRate=" + mRate + ", mPrice= " + mPrice + ", mComment=" + mComment + "]";
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof ImmutableDistanceImpl)) return false;
ImmutableDistanceImpl that = (ImmutableDistanceImpl) o;
if (mId != that.mId) return false;
if (!mTrip.equals(that.mTrip)) return false;
if (mLocation != null ? !mLocation.equals(that.mLocation) : that.mLocation != null)
return false;
if (mDistance != null ? !mDistance.equals(that.mDistance) : that.mDistance != null)
return false;
if (mDate != null ? !mDate.equals(that.mDate) : that.mDate != null) return false;
if (mTimezone != null ? !mTimezone.equals(that.mTimezone) : that.mTimezone != null)
return false;
if (mRate != null ? !mRate.equals(that.mRate) : that.mRate != null) return false;
if (mPrice != null ? !mPrice.equals(that.mPrice) : that.mPrice != null) return false;
if (mComment != null ? !mComment.equals(that.mComment) : that.mComment != null) {
return false;
} else {
return true;
}
}
@Override
public int hashCode() {
int result = mId;
result = 31 * result + mTrip.hashCode();
result = 31 * result + (mLocation != null ? mLocation.hashCode() : 0);
result = 31 * result + (mDistance != null ? mDistance.hashCode() : 0);
result = 31 * result + (mDate != null ? mDate.hashCode() : 0);
result = 31 * result + (mTimezone != null ? mTimezone.hashCode() : 0);
result = 31 * result + (mRate != null ? mRate.hashCode() : 0);
result = 31 * result + (mPrice != null ? mPrice.hashCode() : 0);
result = 31 * result + (mComment != null ? mComment.hashCode() : 0);
return result;
}
@Override
public int compareTo(@NonNull Distance distance) {
if (distance.getDate() != null) {
return distance.getDate().compareTo(mDate);
} else {
if (mDate != null) {
return mDate.compareTo(null);
} else {
return 0;
}
}
}
}