package org.solovyev.android.calculator.history;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import org.json.JSONException;
import org.json.JSONObject;
import org.solovyev.android.Check;
import org.solovyev.android.calculator.DisplayState;
import org.solovyev.android.calculator.EditorState;
import org.solovyev.android.calculator.json.Json;
import org.solovyev.android.calculator.json.Jsonable;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class HistoryState implements Parcelable, Jsonable {
public static final Creator<HistoryState> CREATOR = new Creator<HistoryState>() {
@Override
public HistoryState createFromParcel(Parcel in) {
return new HistoryState(in);
}
@Override
public HistoryState[] newArray(int size) {
return new HistoryState[size];
}
};
public static final Json.Creator<HistoryState> JSON_CREATOR = new Json.Creator<HistoryState>() {
@NonNull
@Override
public HistoryState create(@NonNull JSONObject json) throws JSONException {
return new HistoryState(json);
}
};
private static final String JSON_EDITOR = "e";
private static final String JSON_DISPLAY = "d";
private static final String JSON_TIME = "t";
private static final String JSON_COMMENT = "c";
public final int id;
@Nonnull
public final EditorState editor;
@Nonnull
public final DisplayState display;
protected long time = now();
@Nonnull
protected String comment = "";
private HistoryState(@Nonnull EditorState editor, @Nonnull DisplayState display) {
this.id = System.identityHashCode(this);
this.editor = editor;
this.display = display;
}
private HistoryState(@Nonnull HistoryState state, boolean newState) {
this.id = newState ? System.identityHashCode(this) : state.id;
this.editor = state.editor;
this.display = state.display;
this.time = state.time;
this.comment = state.comment;
}
private HistoryState(@Nonnull JSONObject json) throws JSONException {
this(EditorState.create(json.getJSONObject(JSON_EDITOR)), DisplayState.create(json.getJSONObject(JSON_DISPLAY)));
this.time = json.optLong(JSON_TIME, 0L);
this.comment = json.optString(JSON_COMMENT, "");
}
private HistoryState(Parcel in) {
id = in.readInt();
editor = in.readParcelable(EditorState.class.getClassLoader());
display = in.readParcelable(DisplayState.class.getClassLoader());
time = in.readLong();
comment = in.readString();
}
@Nonnull
public static Builder builder(@Nonnull EditorState editor, @Nonnull DisplayState display) {
return new Builder(editor, display);
}
@Nonnull
public static Builder builder(@Nonnull HistoryState state, boolean newState) {
return new Builder(state, newState);
}
@Nonnull
public static HistoryState create(@Nonnull JSONObject json) throws JSONException {
return new HistoryState(json);
}
private static long now() {
return System.currentTimeMillis();
}
@Nonnull
public JSONObject toJson() throws JSONException {
final JSONObject json = new JSONObject();
json.put(JSON_EDITOR, editor.toJson());
json.put(JSON_DISPLAY, display.toJson());
json.put(JSON_TIME, time);
if (!TextUtils.isEmpty(comment)) {
json.put(JSON_COMMENT, comment);
}
return json;
}
@Nonnull
public EditorState getEditor() {
return editor;
}
@Nonnull
public DisplayState getDisplay() {
return display;
}
public long getTime() {
return time;
}
@Nonnull
public String getComment() {
return comment;
}
public boolean same(@Nonnull HistoryState that) {
return this.editor.same(that.editor) && this.display.same(that.display);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || !(o instanceof HistoryState)) return false;
final HistoryState that = (HistoryState) o;
return id == that.id;
}
@Override
public int hashCode() {
return id;
}
@Override
public String toString() {
return "HistoryState{" +
"id=" + id +
", editor=" + editor +
", display=" + display +
", time=" + time +
", comment='" + comment + '\'' +
'}';
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(id);
dest.writeParcelable(editor, flags);
dest.writeParcelable(display, flags);
dest.writeLong(time);
dest.writeString(comment);
}
public boolean isEmpty() {
return display.isEmpty() && editor.isEmpty() && TextUtils.isEmpty(comment);
}
public static final class Builder {
@NonNull
private final HistoryState state;
private boolean built;
private Builder(@Nonnull EditorState editor, @Nonnull DisplayState display) {
this.state = new HistoryState(editor, display);
}
private Builder(@Nonnull HistoryState state, boolean newState) {
this.state = new HistoryState(state, newState);
if (newState) {
withTime(now());
}
}
@Nonnull
public Builder withTime(long time) {
Check.isTrue(!built);
state.time = time;
return this;
}
@Nonnull
public Builder withComment(@Nullable String comment) {
Check.isTrue(!built);
state.comment = comment == null ? "" : comment;
return this;
}
@Nonnull
public HistoryState build() {
built = true;
return state;
}
}
}