package uk.org.squirm3.engine; import java.util.Collection; import java.util.LinkedList; import uk.org.squirm3.listener.EventDispatcher; import uk.org.squirm3.listener.Listener; import uk.org.squirm3.model.Atom; import uk.org.squirm3.model.Configuration; import uk.org.squirm3.model.DraggingPoint; import uk.org.squirm3.model.Reaction; import uk.org.squirm3.model.level.Level; public class ApplicationEngine { // things to run the collider and the commands private Collider collider; private final Thread applicationThread; private final Object colliderExecution; private boolean isRunning; private short sleepPeriod; private final LinkedList<ICommand> commands; // things to do with the dragging around of atoms private DraggingPoint draggingPoint; private DraggingPoint lastUsedDraggingPoint; // composition private final LevelManager levelManager; private final ReactionManager reactionManager; private final EventDispatcher<ApplicationEngineEvent> eventDispatcher; private Configuration configuration; public ApplicationEngine(final LevelManager levelManager) throws Exception { // load levels this.levelManager = levelManager; reactionManager = new ReactionManager(); // manager of the listeners eventDispatcher = new EventDispatcher<ApplicationEngineEvent>(); sleepPeriod = 50; // start the challenge by the introduction try { setLevel(0); } catch (final Exception e) { } commands = new LinkedList<ICommand>(); colliderExecution = new Object(); isRunning = true; // create and run the thread of this application applicationThread = new Thread(new Runnable() { @Override public void run() { while (applicationThread == Thread.currentThread()) { // execute commands synchronized (commands) { while (!commands.isEmpty()) { final ICommand command = commands.removeFirst(); command.execute(); } } // compute one step of the simulation synchronized (colliderExecution) { if (isRunning) { lastUsedDraggingPoint = draggingPoint; collider.doTimeStep( draggingPoint, new LinkedList<Reaction>(reactionManager .getReactions())); eventDispatcher .dispatchEvent(ApplicationEngineEvent.ATOMS); try { Thread.sleep(sleepPeriod); } catch (final InterruptedException e) { break; } } else { try { Thread.sleep(5); } catch (final InterruptedException e) { break; } } } } } }); applicationThread.setPriority(Thread.MIN_PRIORITY); applicationThread.start(); } public Configuration getConfiguration() { return configuration; } public void clearReactions() { addCommand(new ICommand() { @Override public void execute() { if (!reactionManager.getReactions().isEmpty()) { reactionManager.clearReactions(); eventDispatcher .dispatchEvent(ApplicationEngineEvent.REACTIONS); } } }); } public Collection<? extends Atom> getAtoms() { // TODO synchronize correctly : atoms should not be iterated while the // collider is working on theĆ¹ synchronized (colliderExecution) { return collider.getAtoms(); } } public DraggingPoint getCurrentDraggingPoint() { return draggingPoint; } public LevelManager getLevelManager() { return levelManager; } public DraggingPoint getLastUsedDraggingPoint() { return lastUsedDraggingPoint; } public Collection<Reaction> getReactions() { return reactionManager.getReactions(); } public short getSimulationSpeed() { return sleepPeriod; } public void pauseSimulation() { addCommand(new ICommand() { @Override public void execute() { synchronized (colliderExecution) { if (isRunning) { isRunning = false; eventDispatcher .dispatchEvent(ApplicationEngineEvent.SIMULATION_STATE); } } } }); } public void addReactions(final Collection<Reaction> reactions) { addCommand(new ICommand() { @Override public void execute() { reactionManager.addReactions(reactions); eventDispatcher.dispatchEvent(ApplicationEngineEvent.REACTIONS); } }); } public void removeReactions(final Collection<Reaction> reactions) { addCommand(new ICommand() { @Override public void execute() { reactionManager.removeReactions(reactions); eventDispatcher.dispatchEvent(ApplicationEngineEvent.REACTIONS); } }); } private void setLevel(final int levelIndex) { levelManager.setLevel(levelIndex); if (collider != null) { reactionManager.clearReactions(); eventDispatcher.dispatchEvent(ApplicationEngineEvent.REACTIONS); } loadCurrentLevel(); eventDispatcher.dispatchEvent(ApplicationEngineEvent.LEVEL); return; } private void loadCurrentLevel() { final Level currentLevel = levelManager.getCurrentLevel(); configuration = currentLevel.construct(); collider = new Collider(configuration); eventDispatcher.dispatchEvent(ApplicationEngineEvent.CONFIGURATION); eventDispatcher.dispatchEvent(ApplicationEngineEvent.ATOMS); } public void restartLevel() { addCommand(new ICommand() { @Override public void execute() { loadCurrentLevel(); synchronized (colliderExecution) { if (!isRunning) { isRunning = true; eventDispatcher .dispatchEvent(ApplicationEngineEvent.SIMULATION_STATE); } } } }); } public void runSimulation() { addCommand(new ICommand() { @Override public void execute() { synchronized (colliderExecution) { if (!isRunning) { isRunning = true; eventDispatcher .dispatchEvent(ApplicationEngineEvent.SIMULATION_STATE); } } } }); } public void setDraggingPoint(final DraggingPoint newDraggingPoint) { if (draggingPoint == null && newDraggingPoint == null) { return; } if (draggingPoint == null && newDraggingPoint != null || draggingPoint != null && newDraggingPoint == null) { draggingPoint = newDraggingPoint; eventDispatcher .dispatchEvent(ApplicationEngineEvent.DRAGGING_POINT); return; } if (draggingPoint.equals(newDraggingPoint)) { return; } draggingPoint = newDraggingPoint; eventDispatcher.dispatchEvent(ApplicationEngineEvent.DRAGGING_POINT); } public void setReactions(final Collection<Reaction> reactions) { addCommand(new ICommand() { @Override public void execute() { reactionManager.clearReactions(); reactionManager.addReactions(reactions); eventDispatcher.dispatchEvent(ApplicationEngineEvent.REACTIONS); } }); } public void setSimulationSpeed(final short newSleepPeriod) { addCommand(new ICommand() { @Override public void execute() { sleepPeriod = newSleepPeriod; eventDispatcher.dispatchEvent(ApplicationEngineEvent.SPEED); } }); } public boolean simulationIsRunning() { return isRunning; } public final void addListener(final Listener listener, final ApplicationEngineEvent event) { listener.propertyHasChanged(); eventDispatcher.addListener(listener, event); } public void goToLevel(final int levelIndex) { addCommand(new ICommand() { @Override public void execute() { setLevel(levelIndex); } }); } public void goToFirstLevel() { goToLevel(0); } public void goToLastLevel() { addCommand(new ICommand() { @Override public void execute() { setLevel(levelManager.getNumberOfLevel() - 1); } }); } public void goToNextLevel() { addCommand(new ICommand() { @Override public void execute() { final int levelIndex = levelManager.getCurrentLevelIndex(); if (levelIndex + 1 < levelManager.getNumberOfLevel()) { setLevel(levelIndex + 1); } } }); } public void goToPreviousLevel() { addCommand(new ICommand() { @Override public void execute() { final int levelIndex = levelManager.getCurrentLevelIndex(); if (levelIndex - 1 >= 0) { setLevel(levelIndex - 1); } } }); } private interface ICommand { public void execute(); } private void addCommand(final ICommand c) { synchronized (commands) { commands.add(c); } } }