StateManager.java

package org.sterling.source.scanner;

import java.util.ArrayDeque;
import java.util.Deque;

class StateManager<T> {

    private final Deque<T> inputState;
    private final Deque<Deque<T>> states;

    public StateManager(Deque<T> inputState) {
        this.inputState = inputState;
        this.states = new ArrayDeque<>();
    }

    public void begin() {
        states.push(new ArrayDeque<T>());
    }

    public void close() {
        while (!states.isEmpty()) {
            states.pop();
        }
    }

    public void end() {
        if (states.isEmpty()) {
            throw new IllegalStateException();
        } else {
            states.pop();
        }
    }

    public void push(T reference) {
        for (Deque<T> transaction : states) {
            transaction.push(reference);
        }
    }

    public void restore() {
        if (states.isEmpty()) {
            throw new IllegalStateException();
        } else {
            Deque<T> transaction = states.pop();
            while (transaction.size() > 0) {
                inputState.push(transaction.pop());
            }
        }
    }
}