package games.strategy.engine.history; import javax.swing.SwingUtilities; import games.strategy.engine.data.Change; import games.strategy.engine.data.PlayerID; /** * Used to write to a history object. Delegates should use a * DelegateHistoryWriter */ public class HistoryWriter implements java.io.Serializable { private static final long serialVersionUID = 4230519614567508061L; private final History m_history; private HistoryNode m_current; public HistoryWriter(final History history) { m_history = history; } private void assertCorrectThread() { if (m_history.getGameData().areChangesOnlyInSwingEventThread() && !SwingUtilities.isEventDispatchThread()) { throw new IllegalStateException("Wrong thread"); } } /** * Can only be called if we are currently in a round or a step. */ public void startNextStep(final String stepName, final String delegateName, final PlayerID player, final String stepDisplayName) { assertCorrectThread(); // we are being called for the first time if (m_current == null) { int round = 0; m_history.getGameData().acquireReadLock(); try { round = m_history.getGameData().getSequence().getRound(); } finally { m_history.getGameData().releaseReadLock(); } startNextRound(round); } if (isCurrentEvent()) { closeCurrent(); } // stop the current step if (isCurrentStep()) { closeCurrent(); } if (!isCurrentRound()) { throw new IllegalStateException("Not in a round"); } final Step currentStep = new Step(stepName, delegateName, player, m_history.getChanges().size(), stepDisplayName); addToAndSetCurrent(currentStep); } public void startNextRound(final int round) { assertCorrectThread(); if (isCurrentEvent()) { closeCurrent(); } if (isCurrentStep()) { closeCurrent(); } if (isCurrentRound()) { closeCurrent(); } final Round currentRound = new Round(round, m_history.getChanges().size()); m_current = (HistoryNode) m_history.getRoot(); addToAndSetCurrent(currentRound); } private void closeCurrent() { assertCorrectThread(); final HistoryNode old = m_current; m_history.getGameData().acquireWriteLock(); try { // remove steps where nothing happened if (isCurrentStep()) { final HistoryNode parent = (HistoryNode) m_current.getParent(); if (m_current.getChildCount() == 0) { final int index = parent.getChildCount() - 1; parent.remove(m_current); m_history.nodesWereRemoved(parent, new int[] {index}, new Object[] {m_current}); } m_current = parent; return; } m_current = (HistoryNode) m_current.getParent(); ((IndexedHistoryNode) old).setChangeEndIndex(m_history.getChanges().size()); } finally { m_history.getGameData().releaseWriteLock(); } } private void addToAndSetCurrent(final HistoryNode newNode) { addToCurrent(newNode); m_current = newNode; } private void addToCurrent(final HistoryNode newNode) { m_history.getGameData().acquireWriteLock(); try { m_history.insertNodeInto(newNode, m_current, m_current.getChildCount()); } finally { m_history.getGameData().releaseWriteLock(); } m_history.goToEnd(); } public void startEvent(final String eventName) { assertCorrectThread(); if (isCurrentEvent()) { closeCurrent(); } if (!isCurrentStep()) { throw new IllegalStateException("Cant add an event, not a step. " + "Must be in a step to add an event to the step. \nTrying to add event: " + eventName); } final Event event = new Event(eventName, m_history.getChanges().size()); addToAndSetCurrent(event); } private boolean isCurrentEvent() { return m_current instanceof Event; } private boolean isCurrentRound() { return m_current instanceof Round; } private boolean isCurrentStep() { return m_current instanceof Step; } /** * Add a child to the current event. */ public void addChildToEvent(final EventChild node) { assertCorrectThread(); if (!isCurrentEvent()) { new IllegalStateException("Not in an event, but trying to add child:" + node + " current is:" + m_current) .printStackTrace(System.out); startEvent("???"); } addToCurrent(node); } /** * Add a change to the current event. */ public void addChange(final Change change) { assertCorrectThread(); if (!isCurrentEvent() && !isCurrentStep()) { new IllegalStateException("Not in an event, but trying to add change:" + change + " current is:" + m_current) .printStackTrace(System.out); startEvent("Bad Event for change: \n" + change.toString()); } m_history.changeAdded(change); } public void setRenderingData(final Object details) { assertCorrectThread(); if (!isCurrentEvent()) { new IllegalStateException("Not in an event, but trying to set details:" + details + " current is:" + m_current) .printStackTrace(System.out); startEvent("???"); } m_history.getGameData().acquireWriteLock(); try { ((Event) m_current).setRenderingData(details); } finally { m_history.getGameData().releaseWriteLock(); } m_history.goToEnd(); } }