/*
 * kansai.js controls the multiple choice and checkup question
 * generation and display code 
 */

/**********************DETECT_BROWSER**********************/
var BrowserDetect = {
	init: function () {
		this.browser = this.searchString(this.dataBrowser) || "An unknown browser";
		this.version = this.searchVersion(navigator.userAgent)
			|| this.searchVersion(navigator.appVersion)
			|| "an unknown version";
		this.OS = this.searchString(this.dataOS) || "an unknown OS";
	},
	searchString: function (data) {
		for (var i=0;i<data.length;i++)	{
			var dataString = data[i].string;
			var dataProp = data[i].prop;
			this.versionSearchString = data[i].versionSearch || data[i].identity;
			if (dataString) {
				if (dataString.indexOf(data[i].subString) != -1)
					return data[i].identity;
			}
			else if (dataProp)
				return data[i].identity;
		}
	},
	searchVersion: function (dataString) {
		var index = dataString.indexOf(this.versionSearchString);
		if (index == -1) return;
		return parseFloat(dataString.substring(index+this.versionSearchString.length+1));
	},
	dataBrowser: [
		{ 	string: navigator.userAgent,
			subString: "OmniWeb",
			versionSearch: "OmniWeb/",
			identity: "OmniWeb"
		},
		{
			string: navigator.vendor,
			subString: "Apple",
			identity: "Safari"
		},
		{
			prop: window.opera,
			identity: "Opera"
		},
		{
			string: navigator.vendor,
			subString: "iCab",
			identity: "iCab"
		},
		{
			string: navigator.vendor,
			subString: "KDE",
			identity: "Konqueror"
		},
		{
			string: navigator.userAgent,
			subString: "Firefox",
			identity: "Firefox"
		},
		{
			string: navigator.vendor,
			subString: "Camino",
			identity: "Camino"
		},
		{		// for newer Netscapes (6+)
			string: navigator.userAgent,
			subString: "Netscape",
			identity: "Netscape"
		},
		{
			string: navigator.userAgent,
			subString: "MSIE",
			identity: "Explorer",
			versionSearch: "MSIE"
		},
		{
			string: navigator.userAgent,
			subString: "Gecko",
			identity: "Mozilla",
			versionSearch: "rv"
		},
		{ 		// for older Netscapes (4-)
			string: navigator.userAgent,
			subString: "Mozilla",
			identity: "Netscape",
			versionSearch: "Mozilla"
		}
	],
	dataOS : [
		{
			string: navigator.platform,
			subString: "Win",
			identity: "Windows"
		},
		{
			string: navigator.platform,
			subString: "Mac",
			identity: "Mac"
		},
		{
			string: navigator.platform,
			subString: "Linux",
			identity: "Linux"
		}
	]

};
BrowserDetect.init();

/**********************HELPER_FUNCTIONS**********************/

// compare two arrays for equality
function sameArray(array1, array2) {
	if(array1.length != array2.length) { return false; }
	for(var i = 0; i < array1.length; i++) {
		if(array1[i] != array2[i]) { return false; }
	}
	return true;
}

// to see if an obj contains a certain class
function hasClass(obj, objClass) {
	var result = jQuery.grep(obj.className.split(' '), function (n, i) { 
		if(n == objClass) return true;
		return false;
	});
	return (result[0] == objClass);
}

// randomize a set of values
function randomize(values) {
	var newValues = [];
	jQuery(values).each(function () { newValues.push(this)})
	newValues.sort(function (a, b) { return [1, 0, -1][Math.floor(Math.random()*3)]; });
	if(sameArray(newValues, values)) return randomize(values); // TODO: comment to make IE work
	return newValues;
};

/**********************SOUND_MANAGER**********************/

// housekeeping for the soundManager, add mouseover effects
soundManager.onload = function () {
	/*
		soundManager.createSound({
		 id: 'test',
		 url: '/sound/test.mp3',
		 stream: true,
		 autoPlay: true,
		 multiShot: false,
		 onprogress: function() { alert('sound '+this.sID+': '+this.bytesLoaded+' of '+this.bytesTotal+' bytes loaded.'); } // event handler: "this" is scoped to SMSound() object instance for easy access to methods/properties
		});
		soundManager.play('test');
		soundManager.loadFromXML('sounds.xml');
	*/
		// add mouseovers for each sound
		jQuery('div.sound').each(function () {
		  var soundid = jQuery(this).attr('soundid')

		  jQuery(this).mouseover(function () {  soundManager.createSound({ id: jQuery(this).attr('soundid'), url: jQuery(this).attr('file')}); soundManager.play(soundid) });
		  jQuery(this).mouseout(function () { soundManager.stop(soundid) });

		})
};

/**********************DOCUMENT_LOADED**********************/

// when the document is ready
jQuery(document).ready(function () {
		
	/**********************MULTIPLE_CHOICE_HELPER**********************/
	
	/*
	 * Constructor takes an unformatted multipleChoiceUl section, 
	 * that was generated by the webgen script, and creates 
	 * a "multiplechoice_processed" div to store the processed 
	 * multiple choice questions. The original multipleChoiceUl 
	 * section is then removed
	 */
	function QuestionGroup(multipleChoiceUl) {
		var questionGroup = this; //ul.multiplechoice
		questionGroup.questions = [];
		questionGroup.mc_processed = jQuery('<div class="multiplechoice_processed"></div>').get(0);
		questionGroup.mc_processed.questionGroup = questionGroup;
		questionGroup.mc_unprocessed = multipleChoiceUl;
		jQuery(questionGroup.mc_processed).insertBefore(jQuery(multipleChoiceUl));
		jQuery('<div style="clear: left"></div>').insertAfter(jQuery(questionGroup.mc_processed));
		
		// remove the original Ul from the DOM (but not from jQuery)
		jQuery(questionGroup.mc_unprocessed).remove();
		
		// populate the model
		this.buildModel();
		
		// randomize the answers
		this.randomizeAnswers();
		
		//draw the QuestionGroup
		this.paint();
		
	};
	
	/*
	 * The buildModel function parses the code created by the webgen script to create 
	 * drag-and-drop models. The function expects questions to be tagged with <span>
	 * and answers to be tagged with <li> inside of a <ul>
	 */
	QuestionGroup.prototype.buildModel = function () {
		var questionGroup = this;
		var thisQuestion = undefined;
		questionGroup.unrandomizedAnswers = [];
		
		// for each child of the multipleChoiceUl
		jQuery(questionGroup.mc_unprocessed).children().each(function (index) {
			if(this.nodeName == "SPAN") {	// this is a question // TODO:change to SPAN
				// if the question has already been created, just push it on the questions stack
				if(thisQuestion != undefined) {
					questionGroup.questions.push(thisQuestion);
				}
				// otherwise, initialize the question
				thisQuestion = { 
					answers: [], 
					questionIndex: index, 
					questionDiv: jQuery('<div style="min-height:30px;" class="question q'+index+'"></div>')
						.addClass('i'+index).Droppable({
				        	accept : 'a' + index,
				        	onDrop : function (answer) {
								answer.answerModel.chosen = 1;
								soundManager.createSound({ id: 'right', url: 'http://llarc.mit.edu/kansai/sound/right.mp3'});
								soundManager.play('right'); 
								questionGroup.paint(); },
				        	onOut : function (answer) { 
								answer.answerModel.chosen = 0; 
								questionGroup.paint(); }
				    }).get(0)
				};
				jQuery(thisQuestion.questionDiv).append(this);
//this.childNodes).each (function () { thisQuestion.questionDiv.appendChild(this.cloneNode(true))}); //TODO comment to make IE work
				thisQuestion.questionDiv.questionModel = thisQuestion;
			} else if (this.nodeName == "UL") {	// this is an answer
				jQuery(this).children('li').each(function () {
					var thisAnswer = { 
						answerDiv: jQuery('<div class="answer a' + thisQuestion.questionIndex + ' "></div>')
							.Draggable({
						        zIndex : 1000,
						        opacity : 0.7,
						        revert : true
					    }).get(0), 
						correctQuestion: thisQuestion, 
						chosen: 0 
					};
					jQuery(thisAnswer.answerDiv).append(this);
					//jQuery(this.childNodes).each (function () { thisAnswer.answerDiv.appendChild(this.cloneNode(true)) }); //TODO comment to make IE work
					thisAnswer.answerDiv.answerModel = thisAnswer;
					thisQuestion.answers.push(thisAnswer);
					questionGroup.unrandomizedAnswers.push(thisAnswer);
				});
			}
		});	
		questionGroup.questions.push(thisQuestion);
	}
	
	/*
	 * The paint function renders the multiple choice questions within two divs,
	 * questiongroup and answergroup. Labels are added to answers
	 */
	QuestionGroup.prototype.paint = function () {
		var questionGroup = this;
		questionGroup.questionGroupDiv = jQuery('<div class="questiongroup"></div>').get(0);
		questionGroup.answerGroupDiv = jQuery('<div class="answergroup"></div>').get(0);
		//questionGroup.mc_processed.innerHTML = ''; <-- this breaks IE
		
		// get rid of the old divs
		jQuery(questionGroup.mc_processed).empty();
		// add the new divs
		jQuery(questionGroup.mc_processed).append(questionGroup.questionGroupDiv);
		jQuery(questionGroup.mc_processed).append(questionGroup.answerGroupDiv);
		
		jQuery(questionGroup.questions).each(function (index) {
			jQuery(questionGroup.questionGroupDiv).append(this.questionDiv);
			//alert(jQuery(this.questionDiv).html());
		});
		jQuery(questionGroup.randomizedAnswers).each(function (index) {
			if(this.labelSpan == undefined) { 
				this.labelSpan = jQuery('<span class="label"></span>').get(0);
				jQuery(this.labelSpan).prependTo(this.answerDiv)
			}
			this.labelSpan.innerHTML = (index+1) + '. ';
			if(this.chosen == 0) {
				jQuery(questionGroup.answerGroupDiv).append(this.answerDiv);
			} else if (this.chosen == 1) {
				jQuery(this.correctQuestion.questionDiv).append(this.answerDiv);
			}
			//alert(jQuery(this.answerDiv).html());
		});
		
	}
	
	/*
	 * Randomize the answers so that multiple choice questions can be done more than once
	 */
	QuestionGroup.prototype.randomizeAnswers = function () {
		var questionGroup = this;
		questionGroup.randomizedAnswers = []
		jQuery(randomize(questionGroup.unrandomizedAnswers)).each(function (index) {
			questionGroup.randomizedAnswers.push(this);
			if(this.orderClass != undefined ) { jQuery(this.answerDiv).removeClass(this.orderClass); }
			this.orderClass = 'i' + index;
			jQuery(this.answerDiv).addClass(this.orderClass);
		});
	};
	
	/**********************GENERATE_MULTIPLE_CHOICE**********************/
	jQuery('ul.multiplechoice').each(function () {
		new QuestionGroup(this);
	});
	
	/**********************ANSWER_HELPER**********************/
	function Answer(questionController, isCorrect, domElement) {
		
		this.model = {};
		this.model.correct = isCorrect;
		this.model.isSelected = false;
		this.model.studentCorrect = undefined;
		this.view = {};
		this.view.topLevel = jQuery('<div class="answer"></div>').get(0);
		this.view.button = jQuery('<input type="radio">').appendTo(this.view.topLevel).get(0);
		jQuery(this.view.topLevel).append(domElement.cloneNode(true));
		this.view.feedback = jQuery('<div class="feedback"></div>').appendTo(this.view.topLevel).get(0)
		this.view.topLevel.controller = this;
		this.questionController = questionController;
		jQuery(this.view.topLevel).click(function () { this.controller.toggleSelect() ;});
		this.origDom = domElement;
	}
	
	Answer.prototype.markCorrect = function () {
		this.model.studentCorrect = true;
		this.view.feedback.innerHTML = 'Right!';
		jQuery(this.view.topLevel).addClass('correct');
	}
	
	Answer.prototype.markIncorrect = function () {
		this.model.studentCorrect = false;
		this.view.feedback.innerHTML = 'Try again...';
		jQuery(this.view.topLevel).addClass('incorrect');
	}
	
	Answer.prototype.submit = function () {
		if(this.model.isSelected == true) {
			if(this.model.correct == true) { this.markCorrect(); }
			else { this.markIncorrect(); }
		}
	}
	
	Answer.prototype.toggleSelect = function () {
		if(this.model.isSelected == true) {
			this.reset(); }
		else { this.select(); }
	}
	
	Answer.prototype.select = function () {
		this.reset();
		this.questionController.selectAnswer();
		this.model.isSelected = true;
		this.view.button.checked = true;
		jQuery(this.view.topLevel).addClass('selected');
	}
	
	Answer.prototype.reset = function () {
		jQuery(this.view.topLevel).removeClass('correct').removeClass('incorrect');
		this.view.feedback.innerHTML = '';
		this.model.studentCorrect = undefined;
		this.model.isSelected = false;
		this.view.button.checked = false;
		jQuery(this.view.topLevel).removeClass('selected');
	}
	
	Answer.prototype.makeRadioButton = function () {
		jQuery(this.view.button).attr("type", "radio");
	}
	
	/**********************CHECKUP_QUESTION_HELPER**********************/
	
	function CheckupQuestion(originalUL) {
		var currentQuestion = this;
		this.answers = [];
		this.view =  {};
		this.model = {};
		this.model.shouldRandomize = true; // Because of the IE problem, this is disabled (enabled for page to work)
		this.view.origDom = jQuery(originalUL).children('span').get(0); // TODO: Change to <SPAN>
		this.mayOnlySelectOne = false; // Because of the IE problem, this is enabled (diabled for page to work)
		currentQuestion.view.originalUL = originalUL;
		currentQuestion.view.topLevelDiv = jQuery('<div class="checkupqanda"></div>').insertBefore(originalUL).get(0);
		currentQuestion.view.feedback = jQuery('<div class="feedback"></div>').appendTo(currentQuestion.view.topLevelDiv).get(0);
		currentQuestion.view.questionDiv = jQuery('<div class="question"></div>').appendTo(currentQuestion.view.topLevelDiv).get(0);
		jQuery(currentQuestion.view.questionDiv).append(this.view.origDom.cloneNode(true));
		currentQuestion.view.answersDiv = jQuery('<div class="answers"></div>').appendTo(currentQuestion.view.topLevelDiv).get(0);
	
		jQuery(originalUL).children('ul').each(function () {
			var isCorrect = false;
			if(hasClass(this, 'correct')) { isCorrect = true; }
			
			jQuery(this).children('li').each(function () {
				currentQuestion.answers.push(new Answer(currentQuestion, isCorrect, this));
			});
		});
		if(currentQuestion.answers.length == 2 && jQuery(currentQuestion.view.originalUl).attr('forceRandom') != 'true') { currentQuestion.model.shouldRandomize = true; }
		if(this.correctAnswers().length == 1) { this.setupForSelectOne(); } // breaks IE, fix it
		jQuery(currentQuestion.view.topLevelDiv).insertBefore(originalUL);
		//alert(jQuery(currentQuestion.view.topLevelDiv).html());
		this.paint();
		//jQuery(originalUL).remove(); <-- this breaks IE
		jQuery(originalUL).empty();
	}
	
	CheckupQuestion.prototype.setupForSelectOne = function () {
		this.mayOnlySelectOne = true;
		jQuery(this.answers).each (function () {
			this.makeRadioButton();
		});
	}
	CheckupQuestion.prototype.paint = function () {
		var currentQuestion = this;
		//currentQuestion.view.answersDiv.innerHTML = '';  // breaks IE
		jQuery(currentQuestion.view.answersDiv).empty();
		
		var orderedAnswers = undefined;
		//orderedAnswers = currentQuestion.answers; // did this because the program never falls into the if
		if(this.model.shouldRandomize == false) { orderedAnswers = currentQuestion.answers; }
		else { orderedAnswers = randomize(currentQuestion.answers); }
		jQuery(orderedAnswers).each (function () {
			jQuery(currentQuestion.view.answersDiv).append(this.view.topLevel);
		});
	}
	
	CheckupQuestion.prototype.submit = function () {
		var allCorrect = true;
		var anyCorrect = false;
		jQuery(this.answers).each(function () {
			this.submit();
			if(this.model.studentCorrect == false || (this.model.correct == true && this.model.studentCorrect != true)) {allCorrect = false;}
			if(this.model.studentCorrect == true) {anyCorrect = true;}
		});
		if(allCorrect) { jQuery(this.view.topLevelDiv).addClass('correct'); this.view.feedback.innerHTML = 'Right!';}
		if(!allCorrect && anyCorrect) { jQuery(this.view.topLevelDiv).addClass('partial'); this.view.feedback.innerHTML = 'Partially correct...';}
		
	}
	
	CheckupQuestion.prototype.reset = function () {
		jQuery(this.answers).each(function () {
			this.reset();
		});
		jQuery(this.view.topLevelDiv).removeClass('correct').removeClass('partial');
		this.view.feedback.innerHTML = '';
	}
	
	CheckupQuestion.prototype.correctAnswers = function () {
		return jQuery.grep(this.answers, function (n, i) { return n.model.correct });
	}
	
	CheckupQuestion.prototype.incorrectAnswers = function () {
		return jQuery.grep(this.answers, function (n, i) { return ! n.model.correct });
	}
	
	CheckupQuestion.prototype.selectAnswer = function () {
		if(this.mayOnlySelectOne) {
			jQuery(this.answers).each(function () {
				this.reset();
			})
		}
	}
	
	/**********************GENERATE_CHECKUP_QUESTION**********************/
	
	jQuery('div.checkupquestion').each(function () {
		var checkupQuestionDiv = this;
		checkupQuestionDiv.controller = { questions: []};
		checkupQuestionController = checkupQuestionDiv.controller;
		checkupQuestionController.submit = function () {
			jQuery(checkupQuestionController.questions).each(function () { this.submit(); })
		}
		checkupQuestionController.reset = function () {
			jQuery(checkupQuestionController.questions).each(function () { this.reset(true); })
		}
		jQuery(checkupQuestionDiv).find('ul.question').each(function () {
			checkupQuestionController.questions.push(new CheckupQuestion(this));
		});
		checkupQuestionController.submitButton = jQuery('<div class="submitbutton">Submit</div>').get(0);
		checkupQuestionController.submitButton.controller = checkupQuestionController;
		jQuery(checkupQuestionController.submitButton).click(function () {this.controller.submit() }).get(0);
		checkupQuestionController.resetButton = jQuery('<div class="resetbutton">Reset</div>').get(0);
		checkupQuestionController.resetButton.controller = checkupQuestionController;
		jQuery(checkupQuestionController.resetButton).click(function () {this.controller.reset(true) });
		checkupQuestionController.view = checkupQuestionDiv;
		jQuery(checkupQuestionDiv).append(checkupQuestionController.submitButton);
		jQuery(checkupQuestionDiv).append(checkupQuestionController.resetButton);
	});
	
	
	jQuery('li.toggler').each(function () {
	  var toggleButton = jQuery('<div class="toggleButton"></div>').get(0);
	  var toggled = jQuery(this).find('ul').get(0);
	  
	  jQuery(toggleButton).html(jQuery(toggled).is(':hidden') ? 'SHOW' : 'HIDE');
	  
	  toggleButton.toggle = function () {
	    if(jQuery(toggled).is(':hidden')) {
	      jQuery(toggled).slideDown('slow');
	      jQuery(toggleButton).html('HIDE');
	    } else {
	      jQuery(toggled).slideUp('slow');
	      jQuery(toggleButton).html('SHOW');
	    }
	  };
	  jQuery(toggleButton).insertBefore(toggled);
	  if(BrowserDetect.browser=="Safari") {
            jQuery(toggleButton).before('<br><br>');
          }
	  jQuery(toggleButton).click(function () { this.toggle(); });
	});
});
