var app = {
	/* Variables */
	panel: $('#multipanel'),
	results: {},
	blocks: [],
	side: 'left',
	iterations: 8,
	position: [],
	types: ['absolute', 'absolute_dummy', 'jnd', 'jnd_dummy'],
  types_verbose: {
    absolute: 'Counting',
    absolute_dummy: 'Counting with Dummies',
    jnd: 'Choosing a Side',
    jnd_dummy: 'Choosing a Side with Dummies'
  },
	i: 0,
	current_experiment: 0,
	experiment_descriptions: ["<h2>Welcome!</h2><p>The following set of experiments will measure your ability to count objects at a glance.</p><p>The first two rounds will measure the maximum number of objects you can recognize.</p><p>The final two rounds will measure the JND between two sets of objects.</p><input type=\"submit\" id=\"begin\" value=\"Begin &raquo;\"/>",
							  "<h3>Identification</h3><p>The upcoming round will measure the absolute threshold of identification.</p><p>You'll be given a glance of some red squares and then asked how many there were.  We'll run a few variations and then proceed to the next experiment.</p><input type=\"submit\" id=\"start\" value=\"Start &raquo;\"/>",
							  "<h3>Identification with Dummies</h3><p>Now there are some yellow triangles in addition to the red squares in the box.</p><p>You'll still just want to count the number of red squares.  Ignore the yellow triangles.</p><input type=\"submit\" id=\"start\" value=\"Start &raquo;\"/>",
							  "<h3>Noticeable Difference</h3><p>The upcoming round will measure the JND of identification.</p><p>You'll simultaneously be given a glance of two sets of red squares and then asked which had more.</p><input type=\"submit\" id=\"start\" value=\"Start &raquo;\"/>",
							  "<h3>Noticeable Difference with Dummies</h3><p>The sets of red squares now include some yellow triangles.</p><p>Ignore the yellow triangles.  You will still be asked which side has more red squares.</p><input type=\"submit\" id=\"start\" value=\"Start &raquo;\"/>"
							  ],
	
	
	/* Functions */
	// Clear the multipanel of children.
	empty: function() {
		return this.panel.empty();
	},
	
	// Bind the click action for the Begin button in the welcome view.
	bindBegin: function(context) {
		$('#begin').click(function(event) {
			event.preventDefault();
			$(this).unbind();
			return context.initExperiment();
		});
	},
	
	// Bind the click action for the Start button in the description view.
	bindStart: function(context) {
		$('#start').click(function(event) {
			event.preventDefault();
			$(this).unbind();
			return context.runExperiment();
		});
	},
	
	// Bind the click action for the Restart button in the finish view.
	bindRestart: function(context) {
		$('#restart').click(function(event) {
			event.preventDefault();
			$(this).unbind();
			return context.start();
		});
	},
	
	// Bind the click action for the Continue button in the question view.
	bindContinue: function(context) {
		$('#continue').click(function(event) {
			event.preventDefault();
			if(/^(\d+)$/.test($('#numblocks').val()) == false) {
				alert('Please enter a number.');
				return false;
			}

			$(this).unbind();
			
			context.results[context.types[context.current_experiment-1]][context.blocks[context.i]-1] = $('#numblocks').val();
			
			if(++context.i >= context.iterations) {
				return context.initExperiment();
			} else {
				return context.beginCountdown();
			}
		});
	},
	
	// Bind the click action for the Left/Right buttons in the question view.
	bindSides: function(context) {
		$("#left").click(function(event) {
			event.preventDefault();
			$(this).unbind();
			$('#right').unbind();

			if(context.side == 'left') {
				context.results[context.types[context.current_experiment-1]][context.blocks[context.i]-1] = 1;
			} else {
				context.results[context.types[context.current_experiment-1]][context.blocks[context.i]-1] = 0;	
			}
			
			if(++context.i >= context.iterations) {
				return context.initExperiment();
			} else {
				return context.beginCountdown();
			}
		});
		
		$("#right").click(function(event) {
			event.preventDefault();
			$(this).unbind();
			$('#left').unbind();

			if(context.side == 'right') {
				context.results[context.types[context.current_experiment-1]][context.blocks[context.i]-1] = 1;
			} else {
				context.results[context.types[context.current_experiment-1]][context.blocks[context.i]-1] = 0;	
			}
			
			if(++context.i >= context.iterations) {
				return context.initExperiment();
			} else {
				return context.beginCountdown();
			}
		});
	},
	
	// Reset the results objects.
	resetResults: function() {
		this.results = {absolute:null,absolute_dummy:null,jnd:null,jnd_dummy:null};
		for(type in this.results) {
			this.results[type] = [-1,-1,-1,-1,-1,-1,-1,-1];
		}
	},
	
	// Begin the study.  Reset variables and display the welcome view.
	start: function() {
		this.resetResults();
		this.current_experiment = 0;
		this.welcome();
	},
	
	// Show the welcome view.
	welcome: function() {
		this.empty();
		this.panel.append(this.experiment_descriptions[0]);
		this.bindBegin(this);
	},
	
	// Initialize an experiment.
	initExperiment: function() {
		++this.current_experiment;
		
		// Check experiment number.
		if(this.current_experiment < 1) {
			alert("Invalid experiment.");
			return false;
		} else if (this.current_experiment > 4) {
			this.finish();
			return true;
		}
		
		this.empty();
		this.panel.append(this.experiment_descriptions[this.current_experiment]);
		
		this.bindStart(this);
	},
	
	// Run a round of tests.
	runExperiment: function() {
		this.blocks = [1, 2, 3, 4, 5, 6, 7, 8];
		this.blocks.sort(function() { return (Math.round(Math.random())-.05);});
		
		this.i = 0;
		this.beginCountdown();
	},
	
	// Show the view.
	beginCountdown: function() {
		this.empty();
		this.panel.append("<div id='canvasWrap'><div>3</div></div>");
		
		$('#canvasWrap div:last-child').fadeOut(1000, function() {app.countdown2();});
	},
	
	// 2nd part of the countdown.
	countdown2: function() {
		$('#canvasWrap').append('<div>2</div>');
		$('#canvasWrap div:last-child').fadeOut(1000, function() {app.countdown1();});
	},
	
	// Last part of the countdown.
	countdown1: function() {
		$('#canvasWrap').append('<div>1</div>');
		$('#canvasWrap div:last-child').fadeOut(1000, function() {app.showCanvas();});
	},
	
	// Find a non-overlapping position for the next block.
	getPosition: function(width, max_x, shift_x) {
		good = false;
		
		offset_x = 0;
		offset_y = 0;
		
		while(!good) {
			good = true;
			offset_x = shift_x+Math.round(Math.random()*max_x);
			offset_y = Math.round(Math.random()*525);
			
			for(k=0;k<this.positions.length;++k) {
				// Check to see if the new square would intersect with the existing ones.
				if(((offset_x >= this.positions[k][0] && offset_x <= this.positions[k][0]+width) || (offset_x+width >= this.positions[k][0] && offset_x < this.positions[k][0])) && ((offset_y >= this.positions[k][1] && offset_y <= this.positions[k][1]+width) || (offset_y+width >= this.positions[k][1] && offset_y < this.positions[k][1]))) {
					// If it does, then break and choose another random starting point.
					good = false;
					break;	
				}
			}
		}
		
		// The current offset will not intersect with any other squares.
		this.positions.push([offset_x, offset_y]);
		return [offset_x, offset_y];
	},
	
	// Show the canvas.
	showCanvas: function() {
		$('#canvasWrap').empty();
		$('#canvasWrap').append('<canvas width="800" height="800" id="canvas"></canvas>');
		
		canvas = document.getElementById('canvas');
		ctx = canvas.getContext('2d');
		
		this.positions = [];
		
		offset_x = 0;
		offset_y = 0;
		
		if(this.current_experiment < 3) {
			ctx.fillStyle = '#F02311';
			ctx.strokeStyle = '#000';
			
			for(j=0;j<this.blocks[this.i];++j) {
				offset = this.getPosition(50, 725, 0);
			
				ctx.fillRect(25+offset[0],25+offset[1],50,50);
				ctx.strokeRect(25+offset[0],25+offset[1],50,50);
			}
			
			if(this.current_experiment == 2) {
				ctx.fillStyle = '#FAAF01';
				for(j=0;j<4;++j) {	
					offset_x = Math.round(Math.random()*725);
					offset_y = Math.round(Math.random()*525);
				
					ctx.beginPath();
					ctx.moveTo(25+offset_x,25+offset_y);
					ctx.lineTo(67+offset_x,50+offset_y);
					ctx.lineTo(67+offset_x,offset_y);
					ctx.lineTo(25+offset_x,25+offset_y);
					ctx.fill();
					ctx.stroke();
				}
			}
		} else {
			ctx.fillStyle = '#000000';
			ctx.fillRect(399,0,2,600);
			
			ctx.fillStyle = '#F02311';
			ctx.strokeStyle = '#000';
			
			// The side refers to the side of the canvas with MORE blocks.
			this.side = Math.random() < 0.5 ? 'left' : 'right';
			
			// Offset the control and variable depending on the side.
			if(this.side == 'left') {
				control_offset = 400;
				var_offset = 0;
			} else {
				control_offset = 0;
				var_offset = 400;
			}
			
			// Draw control.
			for(j=0;j<10;++j) {	
				offset = this.getPosition(35, 325, control_offset);
			
				ctx.fillRect(25+offset[0],25+offset[1],35,35);
				ctx.strokeRect(25+offset[0],25+offset[1],35,35);
			}
			
			// Draw variable.
			for(j=0;j<this.blocks[this.i]+10;++j) {	
				offset = this.getPosition(35, 325, var_offset);
			
				ctx.fillRect(25+offset[0],25+offset[1],35,35);
				ctx.strokeRect(25+offset[0],25+offset[1],35,35);
			}
			
			// Draw triangles, if appropriate.
			if(this.current_experiment == 4) {
				// Set fill color to yellow.
				ctx.fillStyle = '#FAAF01';
				
				// Draw left side triangles.
				for(j=0;j<3;++j) {	
					offset_x = Math.round(Math.random()*325);
					offset_y = Math.round(Math.random()*525);
				
					ctx.beginPath();
					ctx.moveTo(25+offset_x,25+offset_y);
					ctx.lineTo(55+offset_x,40+offset_y);
					ctx.lineTo(55+offset_x,offset_y);
					ctx.lineTo(25+offset_x,25+offset_y);
					ctx.fill();
					ctx.stroke();
				}
				
				// Draw right side triangles.
				for(j=0;j<3;++j) {	
					offset_x = Math.round(Math.random()*325);
					offset_y = Math.round(Math.random()*525);
				
					ctx.beginPath();
					ctx.moveTo(425+offset_x,25+offset_y);
					ctx.lineTo(455+offset_x,35+offset_y);
					ctx.lineTo(455+offset_x,offset_y);
					ctx.lineTo(425+offset_x,25+offset_y);
					ctx.fill();
					ctx.stroke();
				}
			}
		}
		
		setTimeout(function(){app.askQuestion();}, 400);
	},
	
	// Ask question.
	askQuestion: function() {
		this.empty();
		
		if(this.current_experiment < 3) {
			this.panel.append('<h3>How Many Red Squares?</h3><p><input type="text" id="numblocks" maxlength="2" size="2" value="" /></p><input type="submit" id="continue" value="Continue" />');
			$('#numblocks').focus();
			this.bindContinue(this);
		} else {
			this.panel.append('<h3>Which Side Had More Red Squares?</h3><input type="submit" id="left" value="Left Side" />&nbsp;&nbsp;&nbsp;&nbsp;<input type="submit" id="right" value="Right Side" />');	
			this.bindSides(this);
		}
	},
	
	// All done with the experiments.
	// (Old, for class) Upload data and show a thank you view.
  // (New, for web demo) Show the user how they did.
	finish: function() {
		this.empty();
		
		// Prep results for display.
		str = '<thead><tr><th>Type</th><th>% Correct</th></tr></thead>';
		for(type in this.results) {
			str += '<tr><th>' + this.types_verbose[type] + '</th>';
      
      percent = 0.0;
			for(j=0;j<this.results[type].length;++j) {
        if (type == 'jnd' || type == 'jnd_dummy') {
          percent += this.results[type][j];
        } else {
          percent += j + 1 == this.results[type][j] ? 1 : 0;
        }
				
			}
      
			str += '<td>' + ((percent / this.results[type].length) * 100) + '</td></tr>';
		}
		str += '</tbody>';
    
		this.panel.append("<h2>Thanks!</h2><p>Hey, you finished all the tests.  Thanks for helping out.</p><p><strong>Here are your results:</strong></p><table>" + str + "</table><input type=\"submit\" id=\"restart\" value=\"Restart\"/>");
		this.bindRestart(this);
	}
};

app.start();
window.onbeforeunload = function () {
	return "You are about to leave the experiment.  Are you sure you want to continue?";	
}
