package com.code44.finance.data.model; import android.content.ContentValues; import android.database.Cursor; import android.os.Parcel; import android.os.Parcelable; import com.code44.finance.common.model.ModelState; import com.code44.finance.common.utils.Preconditions; import com.code44.finance.common.utils.StringUtils; import com.code44.finance.data.db.Column; import java.util.UUID; public abstract class Model implements Parcelable { private long localId; private String id; private ModelState modelState; private SyncState syncState; protected Model() { localId = 0; setId(null); setModelState(ModelState.Normal); setSyncState(SyncState.None); } protected Model(Parcel parcel) { localId = parcel.readLong(); setId(parcel.readString()); setModelState(ModelState.fromInt(parcel.readInt())); setSyncState(SyncState.fromInt(parcel.readInt())); } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel parcel, int flags) { parcel.writeLong(localId); parcel.writeString(id); parcel.writeInt(modelState.asInt()); parcel.writeInt(syncState.asInt()); } @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof Model)) return false; final Model model = (Model) o; // We are only checking id, because otherwise some parts of the app might misbehave // For example BaseModelAdapter contains Set<BaseModel> selectedItems // noinspection RedundantIfStatement return !(StringUtils.isEmpty(id) || StringUtils.isEmpty(model.id)) && id.equals(model.id); } @Override public int hashCode() { // TODO Should create a better hash code for models that doesn't have id. return id != null ? id.hashCode() : 0; } protected abstract Column getLocalIdColumn(); protected abstract Column getIdColumn(); protected abstract Column getModelStateColumn(); protected abstract Column getSyncStateColumn(); public void prepareForDb() { if (StringUtils.isEmpty(id)) { id = UUID.randomUUID().toString(); } if (modelState == null) { modelState = ModelState.Normal; } if (syncState == null) { syncState = SyncState.None; } } public void validate() { Preconditions.notEmpty(id, "Id cannot be empty."); Preconditions.notNull(modelState, "ModelState cannot be null."); Preconditions.notNull(syncState, "SyncState cannot be null."); } public ContentValues asValues() { prepareForDb(); validate(); final ContentValues values = new ContentValues(); if (localId != 0) { values.put(getLocalIdColumn().getName(), localId); } values.put(getIdColumn().getName(), id); values.put(getModelStateColumn().getName(), modelState.asInt()); values.put(getSyncStateColumn().getName(), syncState.asInt()); return values; } public String getId() { return id; } public void setId(String id) { this.id = id; } public ModelState getModelState() { return modelState; } public void setModelState(ModelState modelState) { this.modelState = modelState; } public SyncState getSyncState() { return syncState; } public void setSyncState(SyncState syncState) { this.syncState = syncState; } public void updateFrom(Cursor cursor, String columnPrefixTable) { int index; // Local id index = cursor.getColumnIndex(getLocalIdColumn().getName(columnPrefixTable)); if (index >= 0) { localId = cursor.getLong(index); } // Id index = cursor.getColumnIndex(getIdColumn().getName(columnPrefixTable)); if (index >= 0) { setId(cursor.getString(index)); } // Model state index = cursor.getColumnIndex(getModelStateColumn().getName(columnPrefixTable)); if (index >= 0) { setModelState(ModelState.fromInt(cursor.getInt(index))); } // Sync state index = cursor.getColumnIndex(getSyncStateColumn().getName(columnPrefixTable)); if (index >= 0) { setSyncState(SyncState.fromInt(cursor.getInt(index))); } } public boolean hasId() { return !StringUtils.isEmpty(id); } }