/* * Copyright (C) 2012 Brendan Robert (BLuRry) brendan.robert@gmail.com. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA */ package jace.state; import java.io.Serializable; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.Set; import javafx.scene.image.Image; /** * A state is nothing more than a map of captured variable values, except that a * state can also be a delta (set of changes) from a previous state. This allows * states to occupy a lot less memory and be more efficiently managed. States * are chained together in a linked list, using a special delete method to * ensure that delta states are properly merged. * * @author Brendan Robert (BLuRry) brendan.robert@gmail.com */ public class State extends HashMap<ObjectGraphNode, StateValue> implements Serializable { boolean deltaState; State previousState; State nextState; // Tail is only correct on the head node, everything else will likely be null State tail; Image screenshot; /** * Removing the next state allows a LRU buffer of states -- but states can't * simple be discarded, they have to be more carefully managed because most * states only track deltas. Things like memory have to be merged correctly. * * This state will merge with the next state and then remove it from the * linked list. * * @return */ public State deleteNext() { if (nextState == null) { return null; } if (nextState.deltaState) { putAll(nextState); nextState = nextState.nextState; if (nextState == null) { tail = this; } return this; } else { nextState.tail = tail; nextState.previousState = previousState; return nextState; } } public void addState(State newState) { newState.previousState = this; nextState = newState; } public void apply() { Set<ObjectGraphNode> applied = new LinkedHashSet<>(); State current = this; while (current != null) { for (StateValue val : current.values()) { if (!applied.contains(val.node)) { System.out.print(val.node.parent.parent != null ? val.node.parent.parent.name + "." : ""); System.out.print(val.node.parent != null ? val.node.parent.name + "." : ""); System.out.print(val.node.name); System.out.print("=="); System.out.println(val.value == null ? "NULL" : val.value.getClass().toString()); val.node.setCurrentValue(val.value); applied.add(val.node); } } if (!current.deltaState) { current = null; } else { current = current.previousState; } } } }