/*

name         Questionair
author       Mark de Jong (http://www.spellcoder.nl)
copyright    (c) Mark de Jong
website      http://www.senna.nu
version      october 2009


- option selection done using event delegation
  (better against leaks, easyer for generic locking of question and to support options in a HTML fragment)

*/

questionairid = 0;

questionair = function(questions, container)
{
	questionairid++;

	this.name = 'spcQuestionair';	
	this.id = questionairid;
	this.questions = questions;
	this.currentquestionid = -1;

	this.locked = false; // lockdown full questionair (nakijkmode)

	// if true, user can skip to next question without answering
	// and will be able to go back to an question to change the answer
	this.allowbrowsing = true;

	this.currentanswers = [];
	
	this.builddom(container);
	// TODO: maybe have the ability to show an intro screen before starting the first question?
//	this.showQuestion(0);
};

questionair.prototype.builddom = function(container)
{
	var self = this;
	this.dom = {};
	this.dom.container = container;

	//console.log('building dom');

	this.navpanel = document.createElement('div');
	this.navpanel.className = 'questionair_nav';

	this.btnprev = document.createElement('div');
	this.btnprev.className = 'btnprev';
	this.btnprev.appendChild(document.createTextNode('<'));
	this.btnprev.onclick = function() { self.prevQuestion(); };

	this.domprogress = document.createElement('div');
	this.domprogress.className = 'qprogress';

	this.domprogresstxt = document.createElement('span');
	this.domprogresstxt.className = 'qprogresstxt';

	this.domprogressbar = document.createElement('div');
	this.domprogressbar.className = 'qprogressbar';

	this.btnnext = document.createElement('div');
	this.btnnext.className = 'btnnext';
	this.btnnext.appendChild(document.createTextNode('>'));
	this.btnnext.onclick = function() { self.nextQuestion(); };

	var btnvalidate = this.dom.btn_validate = document.createElement('div');
	btnvalidate.className = 'validatebutton';
	btnvalidate.innerHTML = 'Nakijken';
	btnvalidate.onclick = function() { self.validateanswer(); };
	//container.appendChild(btnvalidate);
	
	this.navpanel.appendChild(this.btnprev);
	this.navpanel.appendChild(this.domprogress);
	this.domprogress.appendChild(this.domprogressbar);
	this.domprogress.appendChild(this.domprogresstxt);
	this.navpanel.appendChild(this.btnnext);

	this.navpanel.appendChild(btnvalidate);
	
	container.appendChild(this.navpanel);
}

questionair.prototype.prevQuestion = function()
{
	if (this.currentquestionid > 0)
		this.showQuestion(this.currentquestionid-1);
}

questionair.prototype.nextQuestion = function()
{
	if (this.currentquestionid < this.questions.length-1)
		this.showQuestion(this.currentquestionid+1);
}

// TODO: storestate/restorestate in question itself
questionair.prototype.storestate = function()
{
	if (this.currentquestionid == -1)
		return;

	//console.log('storevalue for question '+this.currentquestionid+" ("+this.currentquestion.name+')');

	var valuex = this.currentquestion.getvalue();

	if (typeof valuex != 'undefined')
		this.questions[this.currentquestionid].givenanswer = valuex;

	// FIXME: or have a object called state to store this and have a GetState() ?
	this.questions[this.currentquestionid].locked = this.currentquestion.locked; // FIXME
	this.questions[this.currentquestionid].validated = this.currentquestion.validated;
}
questionair.prototype.restorestate = function()
{
	if (this.currentquestionid == -1)
		return;

	var givenanswer = this.questions[this.currentquestionid].givenanswer;

	if (typeof givenanswer != 'undefined')
		this.currentquestion.setvalue(givenanswer);
		
	if (this.questions[this.currentquestionid].validated)
		this.validateanswer();
}

questionair.prototype.showQuestion = function(qnr)
{
	//console.log('showQuestion '+qnr);

	this.storestate();

	var self = this;
	var question = this.questions[qnr];
	this.currentquestionid = qnr;

	this.currentanswers = [];
	
	var container = document.createElement('div');
	container.className = 'questionpanel interactive';
	container.onclick = function(event) { return self.selectanswer(event); };
	this.questioncontainer = container;
	
	//this.domprogress.textContent = 'Vraag '+(qnr+1)+' van de '+this.questions.length;
	// textContent - innerText
	this.domprogresstxt.innerHTML = 'Vraag '+(qnr+1)+' van de '+this.questions.length;
	this.domprogressbar.style.width = (100*(qnr+1)/this.questions.length)+'%'

	var info = { questionairid: this.id
			   , questionid:    qnr
			   , container:     container
			   , question:      question
			   };

	//console.log(question);

	// TODO: keep it this way?
	if (question.type == 1 && question.maxselect > 1)
		question.type == 2;
	
	switch(question.type)
	{
		case 1: this.currentquestion = new question_mc(info);
				break;
		case 2: this.currentquestion = new question_mc_multianswer(info);
				break;
		case 3: this.currentquestion = new question_open(info);
				break;
		default:	this.currentquestion = new question_placeholder(info);
					break;
	}
	
	this.currentquestion.data = question;
	//this.currentquestion.onselect = self.validateanswer;

	if (this.currentquestionpanel)
		this.dom.container.replaceChild(container, this.currentquestionpanel);
	else
		this.dom.container.appendChild(container);

	this.currentquestionpanel = container;	
	this.restorestate();

}

questionair.prototype.validateanswer = function()
{
	if (this.currentquestion.validated)
		return;

	this.currentquestion.locked = true; // answer cannot be changed anymore
	this.currentquestion.validated = true;
	removeClass(this.currentquestionpanel, 'interactive')
	addClass(this.currentquestionpanel, 'locked')

	this.currentquestion.showcorrectness();

	// add explaination to the question on what the answer should be
	if (this.currentquestion.data.explain != null)
	{
		var panelexplain = document.createElement('div');
		panelexplain.className = 'question_explanation';
		panelexplain.innerHTML = this.currentquestion.data.explain;
		this.currentquestionpanel.appendChild(panelexplain);
	}
}

function getDOMtree(node,seperator)
{
	var txt = '';
	while(node)
	{
		txt = txt+(node)+'('+node.nodeType+')'+seperator;
		node=node.parentNode;
	}
	return txt;
}

questionair.prototype.selectanswer = function(evt)
{
	// don't allow selecting/changing an answer if the questionair or current question is locked
	if (this.locked || this.currentquestion.locked)
	{
		evt.preventDefault();
		return;
	}

	if (!evt)
		evt = window.event;

	// IE uses srcElement instead
	var targ = evt.target ? evt.target : evt.srcElement;

	// look up to determine to which question it belongs
	//	alert(getDOMtree(targ,"\n"));

	// Note on IE bugs:
	// - can't compare nodes directly (use node.isSameNode(othernode) instead
	// - node.ELEMENT_NODE is undefined in IE
			stopEvent(evt);

	//alert(targ.nodeType+' '+targ.tagName);
	//alert(targ.parentNode.nodeType+' '+targ.parentNode.tagName);

	var node = targ;

	//alert(typeof node); // object
	//alert(node.nodeType); // 1
	//alert(node.tagName); // A
	while(	node
			&& node.nodeType == 1 /*node.ELEMENT_NODE*/
			&& !node.hasAttribute('qoption')
			&& node != this.questioncontainer)//&& !node.isSameNode(this.questioncontainer))
	{
		var tagname = node.tagName;
		if (tagname.toUpperCase() == 'A')
		{
			stopEvent(evt);

			product.openInWindow(
						{ url:       node.href
						, className: 'iframewindow'
						, title:     node.innerText ? /*IE*/ node.innerText : /*FF*/ node.textContent
						}
					);

			return false;
		}

		node = node.parentNode;
	}

	if(!node || node.nodeType != 1 /*node.ELEMENT_NODE*/ || !node.hasAttribute('qoption'))
		return;

	var selectedoption = parseInt(node.getAttribute('qoption'));

	//console.log('answer with value '+selectedoption+' clicked.');
	
	if (this.currentquestion.togglevalue)
		this.currentquestion.togglevalue(selectedoption);
}


function question_placeholder(info)
{
	this.node = info.container;

	var dummy = document.createElement('div');
	dummy.innerHTML = '(onbekend vraagtype)';

	this.node.appendChild(dummy);
}
question_placeholder.prototype.getvalue = function() { }
question_placeholder.prototype.setvalue = function() { }


/* Multiple Choice */
function question_mc(info)
{
	this.name = 'multiplechoice';	
	this.node = info.container;
	this.locked = false;

	this.answers = [];
	this.multianswer = false;

	this.question = info.question;
	this.id = info.questionid;
	this.questionairid = info.questionairid;
	
	this.builddom();
}

question_mc.prototype.scannodeforoptions = function(parentnode)
{
	var node = parentnode.firstChild;
	while(node)
	{
		if(node.nodeType == 1 /*node.ELEMENT_NODE*/)
		{
			if (node.hasAttribute('qoption'))
			{
/*
				var optiondata = { node: node
								, value: parseInt(node.getAttribute('qoption'))
								}
*/				
				var htmloptvalue = parseInt(node.getAttribute('qoption'));

				var optiondata = this.getquestionbyoptval(htmloptvalue);
				optiondata.node = node;
				optiondata.value = htmloptvalue;
				
				var newoption = new question_mc_htmloption(optiondata);
				this.answers.push(newoption);
				
				addClass(node,'answer');
			}
			
			if(node.firstChild)
				this.scannodeforoptions(node);
		}
	
		node = node.nextSibling;
	}
}

question_mc.prototype.getquestionbyoptval = function(htmloptionvalue)
{
	var question = this.question;
	for(var tel=0; tel<question.options.length; tel++)
		if (question.options[tel].optval == htmloptionvalue)
			return question.options[tel];

	console.error('Question has a htmloptionvalue '+htmloptionvalue+' which is not a known option for this question.');
}

question_mc.prototype.builddom = function()
{
	var question = this.question;
	var radiogroupname = 'qnr'+this.questionairid+'_q'+this.id;

	var qtitle = document.createElement('div');
	qtitle.className = 'questionTitle'
	qtitle.innerHTML = question.title;

	var qbody = document.createElement('div');
	qbody.innerHTML = question.body;
	
	//alert(question.options.length);
	var optionscontainer = document.createElement('div');
	optionscontainer.className = 'qoptions';

	if (question.optionsinbody)
	{
		this.scannodeforoptions(qbody);
	}
	else
	{
		for(var tel=0; tel<question.options.length; tel++)
		{
			question.options[tel].value = question.options[tel].id;//tel;

			question.options[tel].type  = this.multianswer ? 'checkbox' : 'radio';
			question.options[tel].radiogroupname = radiogroupname;
			var newoption = new question_mc_option(question.options[tel]);		
			this.answers[tel] = newoption;
			optionscontainer.appendChild(newoption.getnode());
		}	
	}

	this.node.appendChild(qtitle);
	this.node.appendChild(qbody);
	this.node.appendChild(optionscontainer);
}

question_mc.prototype.hasselection = function()
{
	for(var tel=0; tel<this.answers.length; tel++)
	{
		if (this.answers[tel].selected)
			return true;
	}
	return false;
}

question_mc.prototype.getvalue = function()
{
	for(var tel=0; tel<this.answers.length; tel++)
	{
		if (this.answers[tel].selected)
			return this.answers[tel].value;
	}
	
	return -1; // no answer selected
}

question_mc.prototype.togglevalue = function(value,node)
{
	// set correct state for all options
	for(var tel=0; tel<this.answers.length; tel++)
	{
		if (this.answers[tel].value == value && !this.answers[tel].selected)
			this.answers[tel].select();
		else
			this.answers[tel].deselect();
	}	
}

question_mc.prototype.setvalue = function(value)
{
	// set correct state for all options
	for(var tel=0; tel<this.answers.length; tel++)
	{
		if (this.answers[tel].value == value)
			this.answers[tel].select();
		else
			this.answers[tel].deselect();
	}
}

question_mc.prototype.showcorrectness = function(value)
{
	//console.log(this.answers);

	for(var tel=0; tel<this.answers.length; tel++)
		this.answers[tel].showcorrectness();
}



function question_mc_multianswer(info)
{
	this.name = 'multiplechoice/multianswer';	
	this.node = info.container;
	this.locked = false;

	this.answers = [];
	this.multianswer = true;

	this.question = info.question;

	var question = info.question;
	
	this.builddom();
}
//questions_mc_multianswer.prototype = new question_mc();
question_mc_multianswer.prototype.builddom = question_mc.prototype.builddom;
question_mc_multianswer.prototype.hasselection = question_mc.prototype.hasselection;

question_mc_multianswer.prototype.getvalue = function()
{
	// return an array with all selected options
	var selectedvalues = [];
	for(var tel=0; tel<this.answers.length; tel++)
	{
		if (this.answers[tel].selected)
			selectedvalues.push(this.answers[tel].value);
	}
	//console.log(selectedvalues);
	return selectedvalues;
}

question_mc_multianswer.prototype.togglevalue = function(value)
{
	// set correct state for all options
	for(var tel=0; tel<this.answers.length; tel++)
	{
		if (this.answers[tel].value == value)
			this.answers[tel].toggle();
	}	
}

question_mc_multianswer.prototype.setvalue = function(selectedvalues)
{
	//console.log(selectedvalues);
	for(var sval=0; sval<selectedvalues.length; sval++)
	{
		//console.log('attempting to find value '+selectedvalues[sval]);
		for(var tel=0; tel<this.answers.length; tel++)
		{
			if (this.answers[tel].value == selectedvalues[sval])
			{
				//console('found and select value '+selectedvalues[sval]);
				this.answers[tel].select();
			}				
		}
	}
}

question_mc_multianswer.prototype.showcorrectness = function(value)
{
	for(var tel=0; tel<this.answers.length; tel++)
		this.answers[tel].showcorrectness();
}




function question_mc_option(option)
{
	this.selected = false;
	this.value = option.value; // ID of option
	this.partvalue = option.partvalue; // how many points you get for selecting it
	this.container = document.createElement('div');

	this.container.className = 'answer answer_mc';
	//qoption.onclick = function(event) { self.selectanswer(event); };
	this.container.setAttribute('qoption', option.value);
	
	var qbtn = document.createElement('input');
	qbtn.type = option.type;
	qbtn.name = option.radiogroupname;
	this.container.appendChild(qbtn);
	
	this.container.appendChild(document.createTextNode(option.title));
}

question_mc_option.prototype.getnode = function()
{
	return this.container;
}

question_mc_option.prototype.select = function()
{
	//console.log('select on value '+this.value);
	this.selected = true;

	// visual
	addClass(this.container, 'selected');
	this.container.getElementsByTagName('input')[0].checked = true;	
}

question_mc_option.prototype.deselect = function()
{
	//console.log('deselect on value '+this.value);
	this.selected = false;
	
	// visual
	removeClass(this.container, 'selected');
	this.container.getElementsByTagName('input')[0].checked = false;	
}

question_mc_option.prototype.toggle = function()
{
	if (this.selected)
		this.deselect();
	else
		this.select();
}

question_mc_option.prototype.showcorrectness = function()
{
	if (this.partvalue > 0)
		addClass(this.container, 'correct');
	else
		addClass(this.container, 'incorrect');
}





function question_open(info)
{
	this.name = 'openquestion';
	this.node = info.container;
	this.locked = false;

	this.multianswer = false;
	this.multiline   = info.question.multiline;
	this.openanswer  = info.question.openanswer;
	
	this.question = info.question;
	this.id = info.questionid;
	this.questionairid = info.questionairid;	

	this.builddom();
}

question_open.prototype.builddom = function()
{
	var question = this.question;
	var inputname = 'qnr'+this.questionairid+'_q'+this.id;

	var qtitle = document.createElement('h1');
	qtitle.innerHTML = question.title;

	var qbody = document.createElement('div');
	qbody.className = 'questiondescription';
	qbody.innerHTML = question.body;

	if (this.multiline)
	{
		var qinput = document.createElement('textarea');
		qinput.cols = 60;
		qinput.rows = 5;
	}
	else
	{
		var qinput = document.createElement('input');
		qinput.type = 'text';
	}
	qinput.id = inputname;
	qinput.className = 'answer answer_open';
	this.answernode = qinput;

	this.node.appendChild(qtitle);
	this.node.appendChild(qbody);
	this.node.appendChild(qinput);
}

question_open.prototype.getvalue = function()
{
	//console.log('getvalue (open)');
	var inputname = 'qnr'+this.questionairid+'_q'+this.id;
	var nodei = document.getElementById(inputname);
	if (nodei)
		return nodei.value;
}

question_open.prototype.setvalue = function(value)
{
	var inputname = 'qnr'+this.questionairid+'_q'+this.id;
	var nodei = document.getElementById(inputname);
	if (nodei)
		nodei.value = value;
}

question_open.prototype.showcorrectness = function(value)
{
	var thevalue = trim(this.getvalue());

	if (thevalue == this.openanswer)
//	if (this.partvalue > 0)
		addClass(this.answernode, 'correct');
	else
		addClass(this.answernode, 'incorrect');
/*	
	if (thevalue == this.openanswer)
		alert('goed gedaan');
	else
		alert('fout');
	// TODO: figure out if we can and how to implement for open questions
*/
}



function question_mc_htmloption(option)
{
	this.selected = false;
	this.value = option.value;
	this.partvalue = option.partvalue;
    this.container = option.node;
}

question_mc_htmloption.prototype.getnode = question_mc_option.prototype.getnode;
question_mc_htmloption.prototype.toggle = question_mc_option.prototype.toggle;

question_mc_htmloption.prototype.select = function()
{
	this.selected = true;
	addClass(this.container, 'selected');
	addClass(this.container, 'selectedhtmloption');
}

question_mc_htmloption.prototype.deselect = function()
{
	this.selected = false;
	removeClass(this.container, 'selected');
	removeClass(this.container, 'selectedhtmloption');
}

question_mc_htmloption.prototype.showcorrectness = function(value)
{
	if (this.partvalue > 0)
		addClass(this.container, 'correct');
	else
		addClass(this.container, 'incorrect');
}
