package StevensLevel; import configuration.RoundDesign; import StevensLevel.listeners.PartInteractionListener; import StevensLevel.parts.ExperimentPart; import StevensLevel.parts.BeginningPart; import StevensLevel.parts.EndingPart; import StevensLevel.parts.Round; import configuration.ExperimentConfiguration; import interaction.InteractionReactor; import java.util.ArrayList; import java.util.List; import screens.AbstractStrictScreen; import static StevensLevel.EventBusHelper.*; /** * * @author Tristan Goffman(tgoffman@gmail.com) Jul 17, 2011 */ public class ExperimentControl extends WithStateImpl implements InteractionReactor, Runnable, PartInteractionListener { ViewControl vCon; List<Round> rounds; protected Sequence seq; private ExperimentConfiguration conf; private ExperimentPart currPart; /** Simple counter for keeping track how many parts have been played so far **/ private int partsComplete = 0; //Has many TaskRounds (task within) public ExperimentControl() { setViewControl(new ViewControl()); } //JavaBeans methods protected ViewControl getViewControl() { return vCon; } private void setViewControl(ViewControl vCon) { this.vCon = vCon; } public List<Round> getRounds() { if (rounds == null) { rounds = new ArrayList<Round>(); } return rounds; } public boolean addRound(Round rnd) { return getRounds().add(rnd); } //Get ExperimentControl ready for running public void setup() { listen(this, PartInteractionListener.class); addPart(new BeginningPart()); addTasks(); addPart(new EndingPart()); } protected Sequence getSequence() { if (seq == null) setSequence(new Sequence()); return seq; } protected void setSequence(Sequence seq) { this.seq = seq; } //Run experiment @Override public void run() { setState(State.WAITING); //waiting for first part to begin getConfiguration().ready(); setup(); nextPart(); } void addPart(ExperimentPart<?> part) { Sequence local_sequence = getSequence(); local_sequence.add(local_sequence.size(), part); } ExperimentPart getPart(Class<? extends AbstractStrictScreen> clazz) { for (ExperimentPart part : this.seq) { if (part.getScreenClass() == clazz) { return part; } } return null; } /** \\ Configuration */ void setConfiguration(ExperimentConfiguration exc) { this.conf = exc; } ExperimentConfiguration getConfiguration() { return this.conf; } private ExperimentPart getPart() { return this.currPart; } /** * Adds tasks to be performed by users */ private void addTasks() { ExperimentConfiguration ec = getConfiguration(); for (RoundDesign design : ec.getRoundDesigns()) { addPart(new Round(design)); } } /** * Run the next part in the sequence, listen to events from it and pass on messages to the view control */ private void nextPart() { eb().getPublisher(this, UserKeyInteractionListener.class).ignoreUserInteractions(); if (getPart() != null) { getPart().stop(); } setPart(getSequence().get(this.partsComplete)); getPart().setup(); getPart().run(); setState(getPart().getState()); //ExperimentControl has the same state as the current part running. Logic should prevail as each part finishes and a new one //starts the control should take the state from the incoming part.. only as the final part completes will ExperimentControl complete as well. partsComplete++;//One more part complete } private void setPart(ExperimentPart get) { this.currPart = get; } @Override public void partComplete() { if(hasNextPart()) nextPart(); else exit(); } @Override public void exit() { throw new UnsupportedOperationException("Not supported yet."); } /** * Checks whether there is another ExperimentPart remaining in sequence to run. * @return */ private boolean hasNextPart() { return partsComplete < getSequence().size(); } }