﻿/*--------------------------------------------------------------------------*/
/*	Quiz application
 *
 * interesting note:
 *
 *	the score is calculated in a slightly weird way:
 *		each question is scored (e.g., if it took you 2 guesses, you get 50%)
 *		the total score is the score for each question divided by the number
 *		of questions.
 *
 *		so, for instance, if you get #1 right in one try, but take two tries
 *		to get #2, then your score is 75% (not 67%, as you might expect,
 *		since it took you 3 tries to get 2 questions answered.)
/*--------------------------------------------------------------------------*/


// Quiz
//
Quiz = function( quizData, questionNumberOffset )
{
	// member variables
	var _this = this;
	var _numGuesses = 0;	// number of guesses per question
	var _lastGuessCorrect = false;	// last answer was correct
	var _percentCorrect = 0;	// running percentage (calculated per question)
	var _numQuestionsAnswered = 0;	// total number of questions answered
	var _enableAnswer = true;
	var _scoreShowing = false;
	var _animationDelay = 100;	// ms
	var _clearButtonDelay = 12 * _animationDelay;
	var _showAnswerDelay = 12 * _animationDelay;
	
	// ids for button elements
	this.buttons = {
		answers : ['buttona', 'buttonb', 'buttonc', 'buttond'],
		prev : 'backbutton',
		next : 'nextbutton',
		enter : 'enterbutton'
	};
	
	// ids for view elements
	this.elemIds = {
		instructions : 'instructions',
		result : 'result',
		questionNum : 'questionNum',
		content : 'content',
		question : 'question',
		answers : ['answerA', 'answerB', 'answerC', 'answerD']
	};
	
	// public vars
	this.animateClassNormal = 'buttonNormal';
	this.animateClass1 = 'buttonGreen';
	this.animateClass2 = 'buttonRed';
	
	this.instructionsScore = "Press Enter to Continue<br/>&nbsp;";
	this.questionNumberOffset = ( questionNumberOffset ) ? questionNumberOffset : 1;
	
	//======================================================================
	// INITIALIZATION	

	// get initial default text from the instructions
	var _instructionsDefault = $(this.elemIds.instructions).innerHTML;

	// create a data model for the quiz data.
	var _quizModel = new Crad.Model(quizData);
	// create a cursor to keep track of which question is being asked.
	var _quizCursor = new Crad.Cursor(_quizModel);
	// create a cursor controller to manage the cursor (next/prev, etc.)
	var _quizCursorController = new Crad.CursorController(_quizCursor, true);	// wrap
	
	// hook up the cursor controller as onclick handlers for the next/prev elements
	$(_this.buttons.prev).getEventDelegator().register('click', _quizCursorController.prev);
	$(_this.buttons.next).getEventDelegator().register('click', _quizCursorController.next);
	$(_this.buttons.enter).getEventDelegator().register('click', showScore);
	
	// hook up the answer buttons: A, B, C, D to the checkAnswer() routine
	for ( var i=0; i<_this.buttons.answers.length; i++ )
	{
		 $(_this.buttons.answers[i]).getEventDelegator().register('click', checkAnswer);
	}
	// register updateQuestion() as an observer to the cursor so that it will be called when
	// the question changes.
	_quizCursor.register(updateQuestion);
	
	// set the cursor's index (which will cause observers to be called).
	_quizCursor.setIndex(0);
	
	// END INITIALIZATION	
	//======================================================================

	//======================================================================
	// UTILITIES

	// setResult -- set the result element to the given string.
	function setText(id, s)
	{
		var cmd = "$(_this.elemIds." + id + ").innerHTML = s";
		eval(cmd);
	}

	// END UTILITIES
	//======================================================================

	//======================================================================
	// ANIMATION

	// makeAnimateCmd -- create the command to animate a button
	function makeAnimateCmd( buttonNum, removeClass, addClass )
	{
		var text =	"$('"+_this.buttons.answers[buttonNum]+"').removeClassName('"+removeClass+"'); " +
					"$('"+_this.buttons.answers[buttonNum]+"').addClassName('"+addClass+"'); ";
		return text;
	}
	
	// animateButtons -- cause the buttons to animate.
	function animateButtons()
	{
		var text;
		var totDelay = 0;
		
		// prime first button -- this turns the first button red
		text = makeAnimateCmd(0, _this.animateClassNormal, _this.animateClass2);
		setTimeout( text, totDelay );

		// do the loop through all the buttons -- this turns each button red in turn
		for ( var i=0; i<3; i++ )
		{
			totDelay += _animationDelay;
			text = makeAnimateCmd(i, _this.animateClass2, _this.animateClassNormal);
			text += makeAnimateCmd(i+1, _this.animateClassNormal, _this.animateClass2);
			setTimeout( text, totDelay );
		}

		// do the last button -- this turns the last button to green
		totDelay += _animationDelay;
		text = makeAnimateCmd(3, _this.animateClass2, _this.animateClass1);
		setTimeout( text, totDelay );

		// do the loop backward -- this turns each button green in turn
		for ( var i=3; i>0; i-- )
		{
			totDelay += _animationDelay;
			text = makeAnimateCmd(i, _this.animateClass1, _this.animateClassNormal);
			text += makeAnimateCmd(i-1, _this.animateClassNormal, _this.animateClass1);
			setTimeout( text, totDelay );
		}
		
		// do the first button -- this turns the first button to red
		totDelay += _animationDelay;
		text = makeAnimateCmd(0, _this.animateClass1, _this.animateClass2);
		setTimeout( text, totDelay );
		
		// do the loop through all the buttons -- this turns each button red in turn
		for ( var i=0; i<3; i++ )
		{
			totDelay += _animationDelay;
			text = makeAnimateCmd(i, _this.animateClass2, _this.animateClassNormal);
			text += makeAnimateCmd(i+1, _this.animateClassNormal, _this.animateClass2);
			setTimeout( text, totDelay );
		}

		// do the last button -- this turns the last button to normal
		totDelay += _animationDelay;
		text = makeAnimateCmd(3, _this.animateClass2, _this.animateClassNormal);
		setTimeout( text, totDelay );		
	}

	// END ANIMATION
	//======================================================================
	

	//======================================================================
	// BIZ LOGIC

	function updateStats()
	{
		// update the stats
		if ( _numGuesses > 0 )
		{
			// percent correct for this question - 0% if the question was not answered correctly
			if ( _lastGuessCorrect )
			{
				var p = 1 / _numGuesses;
				_percentCorrect += p;
			}
			_numGuesses = 0;
			_numQuestionsAnswered++;
		}
	}
	
	// checkAnswer -- is called when the user clicks one of the answer buttons.
	function checkAnswer()
	{
		// the context is the element that fired the event that caused this routine to be called.
		// retrieve that element, and find it in the answerButtonId array.
		var elem = this;
		for ( var i=0; i<_this.buttons.answers.length; i++ )
		{
			if ( elem.id == _this.buttons.answers[i] )
				break;
		}
		
		if ( _enableAnswer )
		{
			// clear out the answer section
			setText('result',"");
			
			// animate the buttons
			animateButtons();
			
			// show the answer
			setTimeout(function() { evaluateAnswer(i); }, _showAnswerDelay );
		}
	}
	
	// evaluateAnswer -- show whether or not the answer is correct
	function evaluateAnswer( i )
	{
		// get the current question
		var correctAnswer = _quizCursor.getData('correctAnswer');
		_numGuesses++;
		if ( _numGuesses > 4 ) _numGuesses = 4;	// there are only 4 buttons, so you can't guess more than four times
		if ( i == correctAnswer )
		{
			// answer is correct!
			// set the result text and light up the button green for a little while
			_lastGuessCorrect = true;
			setText('result', "Yes!");
			var t = makeAnimateCmd(i, _this.animateClassNormal, _this.animateClass1);
			eval(t);
			t = makeAnimateCmd(i, _this.animateClass1, _this.animateClassNormal);
			setTimeout( t, _clearButtonDelay );

			// once the user has correctly answered, they cannot answer the same question again.
			_enableAnswer = false;
		}
		else
		{
			// answer is wrong!
			// set the result text and light up correct button red for a little while
			_lastGuessCorrect = false;			
			setText('result', "Try Again!");
			var t = makeAnimateCmd(i, _this.animateClassNormal, _this.animateClass2);
			eval(t);
			t = makeAnimateCmd(i, _this.animateClass2, _this.animateClassNormal);
			setTimeout( t, _clearButtonDelay );
		}
	}
	
	// updateQuestion is called when the cursor changes.
	function updateQuestion()
	{
		if ( _scoreShowing )
			return;

		// update the stats
		updateStats();
										
		// update the question number
		var i = _quizCursor.getIndex() + _this.questionNumberOffset;
		var h = Math.floor( i / 100 );
		var c = h * 100;
		var t = Math.floor(( i - c ) / 10);
		c += t * 10;
		var o = Math.floor( i - c );
		var t = h.toString() + t.toString() + o.toString();
		setText('questionNum', t);
		
		// show the question and the answers
		setText('question', _quizCursor.getData('question'));
		var answers = _quizCursor.getData('answers');
		setText('answers[0]', answers[0]);
		setText('answers[1]', answers[1]);
		setText('answers[2]', answers[2]);
		setText('answers[3]', answers[3]);
		
		// clear out the answer section
		setText('result', "");
		
		// enable the answer buttons (A, B, C, D)
		_enableAnswer = true;
	}
	
	// showScore -- is called when the user presses the enter button
	// show the score and reset the game.
	function showScore()
	{
		if ( _scoreShowing )
		{
			// reset the game
			setText('instructions', _instructionsDefault);
			_scoreShowing = false;
			_enableAnswer = true;
			
			// show the content area
			$(_this.elemIds.content).show();

			// select the first question
			_quizCursor.setIndex(0);
		}
		else
		{
			// change the instructions
			_instructionsDefault = $(_this.elemIds.instructions).innerHTML;
			setText('instructions', _this.instructionsScore);
			// hide the questions & answers
			$(_this.elemIds.content).hide();
			
			// update the stats
			updateStats();

			// show the score
			_scoreShowing = true;
			_enableAnswer = false;
			
			if ( _numQuestionsAnswered == 0 )
			{
				setText('questionNum',  "0%");
			}
			else
			{
				var score = Math.floor((( _percentCorrect * 100 ) / _numQuestionsAnswered ));
				setText('questionNum', score.toString() + "%" );
			}
			setText('result', "");
			_percentCorrect = 0;
			_numQuestionsAnswered = 0;
		}
	}
}


