package org.solovyev.android.calculator.history; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import org.solovyev.android.Check; import java.util.Collections; import java.util.LinkedList; import java.util.List; public class RecentHistory { private static final int MAX_HISTORY = 40; @NonNull private final List<HistoryState> list = new LinkedList<>(); private int current = -1; public boolean add(@NonNull HistoryState state) { Check.isMainThread(); if (isCurrent(state)) { return false; } if (updateState(state)) { return true; } while (current != list.size() - 1) { list.remove(list.size() - 1); } list.add(state); current++; trim(); return true; } private boolean updateState(@NonNull HistoryState state) { if (current == -1) { return false; } final HistoryState old = list.get(current); if (old.display.sequence == state.display.sequence && old.editor.sequence == state.editor.sequence) { // if recalculation is taking place we need to update current history item list.set(current, state); return true; } return false; } private void trim() { while (list.size() > MAX_HISTORY) { current--; list.remove(0); } } public void addInitial(@NonNull List<HistoryState> states) { Check.isMainThread(); for (HistoryState state : states) { list.add(0, state); } current += states.size(); trim(); } public void remove(@NonNull HistoryState state) { Check.isMainThread(); for (int i = 0; i < list.size(); i++) { final HistoryState candidate = list.get(i); if (candidate.same(state)) { list.remove(i); if (current >= i) { current--; } break; } } } private boolean isCurrent(@NonNull HistoryState state) { final HistoryState current = getCurrent(); if (current == null) { return false; } return current.same(state); } @Nullable public HistoryState getCurrent() { Check.isMainThread(); if (current == -1) { return null; } return list.get(current); } @Nullable public HistoryState redo() { Check.isMainThread(); if (current < list.size() - 1) { current++; } return getCurrent(); } @Nullable public HistoryState undo() { Check.isMainThread(); if (current == -1) { return null; } if (current > 0) { current--; return getCurrent(); } return null; } public void clear() { Check.isMainThread(); list.clear(); current = -1; } public boolean isEmpty() { return list.isEmpty(); } @NonNull public List<HistoryState> asList() { Check.isMainThread(); if (current == -1) { return Collections.emptyList(); } return Collections.unmodifiableList(list.subList(0, current + 1)); } }