package edu.cmu.cs.eyetrack.state;
import java.awt.Color;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.Set;
import javax.swing.ImageIcon;
import edu.cmu.cs.eyetrack.gui.shapes.BoxStimulus;
import edu.cmu.cs.eyetrack.gui.shapes.CircleStimulus;
import edu.cmu.cs.eyetrack.gui.shapes.CrescentStimulus;
import edu.cmu.cs.eyetrack.gui.shapes.CrossStimulus;
import edu.cmu.cs.eyetrack.gui.shapes.DiamondStimulus;
import edu.cmu.cs.eyetrack.gui.shapes.HeartStimulus;
import edu.cmu.cs.eyetrack.gui.shapes.OctagonStimulus;
import edu.cmu.cs.eyetrack.gui.shapes.StarStimulus;
import edu.cmu.cs.eyetrack.gui.shapes.Stimulus;
import edu.cmu.cs.eyetrack.gui.shapes.Stimulus.StimulusClass;
import edu.cmu.cs.eyetrack.gui.shapes.StimulusFactory;
import edu.cmu.cs.eyetrack.gui.shapes.StimulusFactory.StimulusType;
import edu.cmu.cs.eyetrack.gui.shapes.TriangleStimulus;
import edu.cmu.cs.eyetrack.gui.shapes.sabine.part1.Sabine2Stimulus;
import edu.cmu.cs.eyetrack.gui.shapes.sabine.part1.Sabine6Stimulus;
import edu.cmu.cs.eyetrack.gui.shapes.sabine.part1.Sabine8Stimulus;
import edu.cmu.cs.eyetrack.gui.shapes.sabine.part2.SabineNew1Stimulus;
import edu.cmu.cs.eyetrack.gui.shapes.sabine.part2.SabineNew3Stimulus;
import edu.cmu.cs.eyetrack.gui.shapes.sabine.part2.SabineNew4Stimulus;
import edu.cmu.cs.eyetrack.gui.shapes.sabine.part2.SabineNew5Stimulus;
import edu.cmu.cs.eyetrack.gui.shapes.sabine.part2.SabineNew6Stimulus;
import edu.cmu.cs.eyetrack.gui.shapes.sabine.part2.SabineNew7Stimulus;
import edu.cmu.cs.eyetrack.gui.shapes.sabine.part2.SabineNew8Stimulus;
import edu.cmu.cs.eyetrack.gui.shapes.sabine.part2.SabineNew9Stimulus;
import edu.cmu.cs.eyetrack.helper.Util;
import edu.cmu.cs.eyetrack.io.TestRecord;
public class GameState {
private Settings settings;
private History history;
private FileWriter file;
private LinkedList<String[]> outputBuffer;
private Trial activeTrial;
private ArrayList<ImageIcon> backgroundImages;
// Keeps track of the set of Target stimuli we've used
private Set<Stimulus> previousStimTargets;
// Maintain a single Random instance, always draw from this;
// given a unique seed, should be able to reproduce experiment exactly
private Random random;
private RandomGen randomGen;
private int currentTrialCount = 0;
public GameState() {
outputBuffer = new LinkedList<String[]>();
previousStimTargets = new HashSet<Stimulus>();
}
public void registerStimuli(int blockWidth, int blockHeight, StimulusClass stimulusClass) {
// Kill everything that's been inserted before.
StimulusFactory.getInstance().reset();
// Color each stimulus a different, randomly generated (someday...) color
List<Color> stimColors;
switch(stimulusClass) {
case CMU:
// CMU wants a random rainbow of colors
int totalNumberOfStimuli = 9;
if(getRandomGen() == null) {
stimColors = new ArrayList<Color>();
for(int idx=0; idx<totalNumberOfStimuli; idx++) {
stimColors.add(Color.BLACK);
}
} else {
stimColors = getRandomGen().getRandomColors( totalNumberOfStimuli );
}
break;
case UCOLORADO:
// UColorado wants only gray
totalNumberOfStimuli = 11;
stimColors = new ArrayList<Color>();
for(int idx=0; idx<totalNumberOfStimuli; idx++) {
stimColors.add(Color.GRAY);
}
break;
default:
throw new IllegalArgumentException("Cannot understand StimulusClass type " + stimulusClass);
}
// Register some Stimuli as targets, some as distractors
int colorIdx = 0;
double stimScale = 0.5;
double minBlockDim = Math.min(blockHeight, blockWidth) * stimScale;
switch(stimulusClass) {
case CMU:
StimulusFactory.getInstance().registerStimulus(new BoxStimulus("Box", stimColors.get(colorIdx++), (int) (blockWidth * stimScale), (int) (blockHeight * stimScale)), StimulusType.BOTH);
StimulusFactory.getInstance().registerStimulus(new TriangleStimulus("Triangle", stimColors.get(colorIdx++), (int) minBlockDim), StimulusType.BOTH);
StimulusFactory.getInstance().registerStimulus(new CrossStimulus("Cross", stimColors.get(colorIdx++), (int) (blockWidth * stimScale), (int) (blockHeight * stimScale)), StimulusType.BOTH);
StimulusFactory.getInstance().registerStimulus(new OctagonStimulus("Octagon", stimColors.get(colorIdx++), (int) (blockWidth * stimScale), (int) (blockHeight * stimScale)), StimulusType.BOTH);
StimulusFactory.getInstance().registerStimulus(new CircleStimulus("Circle", stimColors.get(colorIdx++),(int) minBlockDim), StimulusType.BOTH);
StimulusFactory.getInstance().registerStimulus(new HeartStimulus("Heart", stimColors.get(colorIdx++), (int) (blockWidth * stimScale), (int) (blockHeight * stimScale)), StimulusType.BOTH);
StimulusFactory.getInstance().registerStimulus(new StarStimulus("Star", stimColors.get(colorIdx++), 5, minBlockDim / 4.0, minBlockDim / 2.0), StimulusType.BOTH);
StimulusFactory.getInstance().registerStimulus(new DiamondStimulus("Diamond", stimColors.get(colorIdx++), (int) (blockWidth * stimScale), (int) (blockHeight * stimScale)), StimulusType.BOTH);
StimulusFactory.getInstance().registerStimulus(new CrescentStimulus("Crescent", stimColors.get(colorIdx++), (int) (blockWidth * stimScale), (int) (blockHeight * stimScale)), StimulusType.BOTH);
break;
case UCOLORADO:
// Older stimuli before UC wanted an update to less-recognizable shapes
//StimulusFactory.getInstance().registerStimulus(new Sabine1Stimulus("Stimulus 1", stimColors.get(colorIdx++), (int) (blockWidth * stimScale), (int) (blockHeight * stimScale)), StimulusType.BOTH);
//StimulusFactory.getInstance().registerStimulus(new Sabine2Stimulus("Stimulus 2", stimColors.get(colorIdx++), (int) (blockWidth * stimScale), (int) (blockHeight * stimScale)), StimulusType.BOTH);
//StimulusFactory.getInstance().registerStimulus(new Sabine3Stimulus("Stimulus 3", stimColors.get(colorIdx++), (int) (blockWidth * stimScale), (int) (blockHeight * stimScale)), StimulusType.BOTH);
//StimulusFactory.getInstance().registerStimulus(new Sabine4Stimulus("Stimulus 4", stimColors.get(colorIdx++), (int) (blockWidth * stimScale), (int) (blockHeight * stimScale)), StimulusType.BOTH);
//StimulusFactory.getInstance().registerStimulus(new Sabine5Stimulus("Stimulus 5", stimColors.get(colorIdx++), (int) (blockWidth * stimScale), (int) (blockHeight * stimScale)), StimulusType.BOTH);
//StimulusFactory.getInstance().registerStimulus(new Sabine6Stimulus("Stimulus 6", stimColors.get(colorIdx++), (int) (blockWidth * stimScale), (int) (blockHeight * stimScale)), StimulusType.BOTH);
//StimulusFactory.getInstance().registerStimulus(new Sabine7Stimulus("Stimulus 7", stimColors.get(colorIdx++), (int) minBlockDim), StimulusType.BOTH);
//StimulusFactory.getInstance().registerStimulus(new Sabine8Stimulus("Stimulus 8", stimColors.get(colorIdx++), (int) (blockWidth * stimScale), (int) (blockHeight * stimScale)), StimulusType.BOTH);
//StimulusFactory.getInstance().registerStimulus(new Sabine9Stimulus("Stimulus 9", stimColors.get(colorIdx++), (int) (blockWidth * stimScale), (int) (blockHeight * stimScale)), StimulusType.BOTH);
//StimulusFactory.getInstance().registerStimulus(new Sabine10Stimulus("Stimulus 10", stimColors.get(colorIdx++), (int) (blockWidth * stimScale), (int) (blockHeight * stimScale)), StimulusType.BOTH);
//StimulusFactory.getInstance().registerStimulus(new SabineNew2Stimulus("Stimulus 2", stimColors.get(colorIdx++), (int) (blockWidth * stimScale), (int) (blockHeight * stimScale)), StimulusType.BOTH);
//StimulusFactory.getInstance().registerStimulus(new SabineNew10Stimulus("Stimulus 10", stimColors.get(colorIdx++), (int) (blockWidth * stimScale), (int) (blockHeight * stimScale)), StimulusType.BOTH);
// Newer stimuli (Sept 2015)
/* 1 --> SabineNewStimulus4
2 --> SabineNewStimulus8
3 --> SabineNewStimulus5
4 --> SabineNewStimulus3
5 --> SabineNewStimulus1 */
StimulusFactory.getInstance().registerStimulus(new SabineNew4Stimulus("Target 1", stimColors.get(colorIdx++), (int) (blockWidth * stimScale), (int) (blockHeight * stimScale)), StimulusType.TARGET);
StimulusFactory.getInstance().registerStimulus(new SabineNew8Stimulus("Target 2", stimColors.get(colorIdx++), (int) (blockWidth * stimScale), (int) (blockHeight * stimScale)), StimulusType.TARGET);
StimulusFactory.getInstance().registerStimulus(new SabineNew5Stimulus("Target 3", stimColors.get(colorIdx++), (int) (blockWidth * stimScale), (int) (blockHeight * stimScale)), StimulusType.TARGET);
StimulusFactory.getInstance().registerStimulus(new SabineNew3Stimulus("Target 4", stimColors.get(colorIdx++), (int) (blockWidth * stimScale), (int) (blockHeight * stimScale)), StimulusType.TARGET);
StimulusFactory.getInstance().registerStimulus(new SabineNew1Stimulus("Target 5", stimColors.get(colorIdx++), (int) (blockWidth * stimScale), (int) (blockHeight * stimScale)), StimulusType.TARGET);
/* 6 --> SabineNewStimulus6
7 --> SabineNewStimulus7
8 --> SabineStimulus6
9 --> SabineStimulus8
10 -> SabineNewStimulus9
11 -> SabineStimulus2 */
StimulusFactory.getInstance().registerStimulus(new SabineNew6Stimulus("Distractor 6", stimColors.get(colorIdx++), (int) (blockWidth * stimScale), (int) (blockHeight * stimScale)), StimulusType.DISTRACTOR);
StimulusFactory.getInstance().registerStimulus(new SabineNew7Stimulus("Distractor 7", stimColors.get(colorIdx++), (int) (blockWidth * stimScale), (int) (blockHeight * stimScale)), StimulusType.DISTRACTOR);
StimulusFactory.getInstance().registerStimulus(new Sabine6Stimulus("Distractor 8", stimColors.get(colorIdx++), (int) (blockWidth * stimScale), (int) (blockHeight * stimScale)), StimulusType.DISTRACTOR);
StimulusFactory.getInstance().registerStimulus(new Sabine8Stimulus("Distractor 9", stimColors.get(colorIdx++), (int) (blockWidth * stimScale), (int) (blockHeight * stimScale)), StimulusType.DISTRACTOR);
StimulusFactory.getInstance().registerStimulus(new SabineNew9Stimulus("Distractor 10", stimColors.get(colorIdx++), (int) (blockWidth * stimScale), (int) (blockHeight * stimScale)), StimulusType.DISTRACTOR);
StimulusFactory.getInstance().registerStimulus(new Sabine2Stimulus("Distractor 11", stimColors.get(colorIdx++), (int) (blockWidth * stimScale), (int) (blockHeight * stimScale)), StimulusType.DISTRACTOR);
break;
default:
throw new IllegalArgumentException("Cannot understand StimulusClass type " + stimulusClass);
}
}
public void registerStimuli(StimulusClass stimulusClass) {
registerStimuli(1, 1, stimulusClass);
}
public boolean hasMoreToWrite() {
return !outputBuffer.isEmpty();
}
public String[] nextDataLine() {
return outputBuffer.removeFirst();
}
public void addTrial(Trial trial) {
// If we've never added a Trial before, we need to tack on CSV headers
if(history == null) {
history = new History();
}
// Add the trial to our history of all trials, and push its data to the write buffer
history.addTrial(trial);
outputBuffer.add(trial.getCSVHeader());
// Assume that this is our current trial now
activeTrial = trial;
}
public void endActiveTrial() {
outputBuffer.addAll(activeTrial.getCSVData());
try {
TestRecord.getInstance().updateLog(this);
} catch(IOException ex) {
Util.dPrintln("ERROR: Cannot write data to file!");
ex.printStackTrace();
}
}
public RandomGen getRandomGen() {
return randomGen;
}
public void setBackgroundImages(ArrayList<ImageIcon> backgroundImages) {
this.backgroundImages = backgroundImages;
}
public ArrayList<ImageIcon> getBackgroundImages() {
return backgroundImages;
}
public Settings getSettings() {
return settings;
}
public Random getRandom() {
return random;
}
public Trial getActiveTrial() {
return activeTrial;
}
public void setActiveTrial(Trial activeTrial) {
this.activeTrial = activeTrial;
}
public void setSettings(Settings settings) {
this.settings = settings;
// Set up the global random counter
random = new Random(settings.getExperiment().getSeed());
StimulusFactory.getInstance().setRandom(random);
randomGen = new RandomGen(random, settings.getExperiment());
// We only add Settings once, so add the header and the data to the write buffer
outputBuffer.add(settings.getCSVHeader());
List<String[]> settingsData = settings.getCSVData();
for(String[] row : settingsData) {
outputBuffer.add(row);
}
}
public void setIO(FileWriter file) {
this.file = file;
}
public FileWriter getIO() {
return file;
}
public int getCurrentTrialCount() {
return currentTrialCount;
}
public void incCurrentTrialCount() {
this.currentTrialCount++;
}
public Set<Stimulus> getPreviousStimTargets() {
return previousStimTargets;
}
}