/*** UTILITY FUNCTIONS ***/

//used for inheritance
if (typeof Object.create !== 'function') 
{  
	Object.create = function (o) 
	{  
		function F() {}
		F.prototype = o;  
		return new F();  
	};
}

getIEVersion = function()
{
	var rv = -1; // Return value assumes failure.
	if (navigator.appName == 'Microsoft Internet Explorer')
	{
		var ua = navigator.userAgent;
		var re  = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})");
		if (re.exec(ua) != null)
		rv = parseFloat( RegExp.$1 );
	}
	return rv;
};

writeStatus = function(message)
{
	document.getElementById("status").innerHTML += message + "<BR>";
};

var padZero = function(num)
{
	if ( num === 0 ) {
		return "00";
	}
	if ( num < 10 ) {
		return "0" + num;
	}
	return "" + num;
};

var getKeyCode = function(e)
{
	if (document.all) {
		return window.event.keyCode;
	}
	else { 
		return e.which;
	}
};

String.prototype.getMatchString = function() {
	return this.toUpperCase().replace(/[^A-Z0-9]/g,"");
};

String.prototype.trim = function() {
	return this.replace(/^\s+|\s+$/g,"");
};

/*** GLOBAL FUNCTIONS ***/

var stumble = function()
{
	window.open("http://www.stumbleupon.com/submit?url=" + document.location.href + "?lx=su&title=" + escape(document.title)); return;
};

// animate from green to white
var animate = function(x, level)
{
    var decColor = (255-level) + 256 * 255 + 65536 * (255-level);
	document.getElementById(x).style.backgroundColor = "#" + decColor.toString(16);
	if ( level > 0 ) {
		setTimeout( function() { animate(x,level-6); }, 40 );
	}
};

var showLoginStatus = function()
{
	if ( screenName != "" ) {
		$("#accountIn").show();	
		$("#accountIn1").html('Welcome ' + screenName + '</a>');
		$("#accountOut").hide();	
	}
	else {
		$("#accountIn").hide();
		$("#accountOut").show();
	}
};

var logout = function()
{
	$.get("/quizzes/user/logout.php", 
	function(data){
		if ( data == "200" ) {
			screenName = "";
			showLoginStatus();
			alert("You are now logged out.");
		}
		else {
			alert("Error. " + data);
		}
	});
};

var login = function()
{
	var u = $("#loginUser").val();
	var p = $("#loginPass").val();
	p = sha1Hash(p);

	var r = 0;
	if ( $("#loginRemember:checked").val() == "on" ) {
		r = 1;
	}

	$("#loginLoader").show();
	
	$.post("/quizzes/user/login.php", { user: u, password: p, remember: r },
		function(data){
			$("#loginLoader").hide();
			document.getElementById("btnVerify").style.visibility = "hidden";
			var lines = data.split("\n");
			if ( lines[0] == "200" ) {
				screenName = lines[1];
				showLoginStatus();
				alert("Welcome " + screenName + ". You are now logged in.");
				loginW.close();
			}
			else if ( lines[0] == "300" ) {
				alert("This account has not been verified.\r\n\r\nTo verify your account, please click the link in the e-mail we sent you.");
				//jQuery doesn't work for this!
				document.getElementById("btnVerify").style.visibility = "visible";
				q.verifyCode = lines[1];
			}
			else {
				alert("Error. " + data);
			}
		});
};

var createAccount = function()
{
	var e = $("#createEmail").val().trim();
	if ( e.length === 0 ) {
		alert("Your e-mail address must not be blank.");
		return false;
	}
	if ( e.length > 255 ) {
		alert("Your e-mail address must not be longer than 255 characters.");
		return false;
	}
	if ( e.indexOf("@") < 0 ) {
		alert("You e-mail address must be real.");
		return false;
	}
	var s = $("#createScreen").val().trim();
	if ( s.length === 0 ) {
		alert("Your screen name must not be blank.");
		return false;
	}
	if ( s.length > 32 ) {
		alert("Your screen name must not be longer than 32 characters.");
		return false;
	}
	var p1 = $("#createPass1").val();
	if ( p1.trim() != p1 ) {
		alert("Your password can't start or end with a space.");
		return false;
	}
	if ( p1 != $("#createPass2").val() ) {
		alert("Your passwords don't match.");
		return false;
	}
	p1 = sha1Hash(p1);

	var qm = 0;
	if ( $("#createCheck1:checked").val() == "on" ) {
		qm = 1;
	}
	var tm = 0;
	if ( $("#createCheck2:checked").val() == "on" ) {
		tm = 1;
	}

	$("#loginLoader").show();
	
	$.post("/quizzes/user/create-user.php", { email: e, screenName: s, password: p1, quizMail: qm, travelMail: tm },
		function(data){
			$("#loginLoader").hide();
			var lines = data.split("\n");
			if ( lines[0] == "200" ) {
				alert("Success! Your account has been created.\n\nYou are now logged in.");
				screenName = lines[1];
				showLoginStatus();
				loginW.close();
			}
			else {
				alert("Error. " + data);
			}
		});
};

var resetPassword = function()
{
	var e = $("#resetEmail").val();
	$("#loginLoader").show();

	$.post("/quizzes/user/send-reset-email.php", { email: e },
	function(data){
		var lines = data.split("\n");
		$("#loginLoader").hide();
		if ( lines[0] == "200" ) {
			alert("We sent you an e-mail with a link to reset your password.");
		}
		else {
			alert("Error. " + data);
		}
	});
};

var oneSecond = function() 
{ 
	q.decrementClock(); 
	if ( !q.done ) {
		setTimeout( oneSecond, 1000 );
	}
};

var typing = function(e) { 
	q.typing(e); 
};

var showAnswersNext = function()
{
	q.setResults();
};

var showAnswers = function()
{
	$("#askBox").hide();
	if ( $("#rWanna1:checked").val() == "on" )
	{
		$("#askBox").hide();
		loginW.launch(2, showAnswersNext);
	}
	else {
		showAnswersNext();
	}
};

var showAnswersFinal = function()
{
	$("#quiz .scrollable").css("overflow", "visible");
	$("#quiz .scrollable").css("height", "auto");
	$("#controls").hide();
	$("#postGameControls").show();
	$("#overlay").hide();
	q.drawCells();
	statsW.launch();
};

var resendVerification = function()
{
	$("#loginLoader").show();
	$.post("/quizzes/user/resend-verification.php", { verify: q.verifyCode },
	function(data){
		var lines = data.split("\n");
		$("#loginLoader").hide();
		if ( lines[0] == "200" ) {
			alert("We resent the verification e-mail.");
		}
		else {
			alert("Error. " + data);
		}
	});
};


/***  QUIZ CLASS ***/
var Quiz = function()
{
	this.done = false;
	this.numGuessed = 0;
	this.numAnswers = 0;

	//for image quizzes
	this.iCells = null;

	//stats
	this.timesTaken = -1;
	this.sumOfScores = -1;
	this.userTaken = -1;
	this.userHigh = -1;

	//for resending verification e-mail
	this.verifyCode = "";

	//custom loading function 
	this.specialLoad = null;

	this.init = function()
	{
		this.mapAnswersToCells();
		for (var i in this.answers ) {
		    if ( this.answers.hasOwnProperty(i) ) {
				this.numAnswers++;
			}
		}
		$("#txtUser").attr("disabled", "");
		this.updateNumGuessed();
		this.drawClock();
		if ( this.bigImages != null ) {
			for (var i=0; i<this.bigImages.length; i++)
			{
				var bi = this.bigImages[i];
				$("#" + bi.div).click(
					function() {
						displayBigImage( $(this).attr('id') );
					}
				);
			}
		}
		if ( this.specialLoad != null ) {
			q.specialLoad();
		}
		setTimeout( oneSecond, 1000 );
	};

	this.typing = function(e)
	{
		var txt = $("#txtUser").val().getMatchString();
		var foundMatch = false;
		var code = getKeyCode(e);
		var alreadyGuessed = [];
		$("#alreadyGuessed").hide();
		for (var i in this.answers )
		{
			if ( this.answers.hasOwnProperty(i) ) {
				var a = this.answers[i];
				if ( a.answered && code != 13 ) {
					continue;
				}
				if ( a.isMatch(txt) )
				{
					if ( a.answered && code == 13 ) {
						alreadyGuessed.push( a.displayText[0] );
						continue;
					}
					a.answered = true;
					foundMatch = true;
					a.drawCells();
					this.numGuessed++;
					this.updateNumGuessed();
					if ( this.numGuessed == this.numAnswers ) {
						this.finish();
					}
				}
			 }
		}
		if ( foundMatch ) {
			$("#txtUser").val("");
		}
		else if ( code == 13 )
		{
			if ( alreadyGuessed.length > 0 ) {
				$("#alreadyGuessed").html( alreadyGuessed.join(", ") + " was already guessed.");
			}
			else if ( txt != "" ) {
				$("#alreadyGuessed").html( "Sorry, " + $("#txtUser").val() + " is not a correct answer.");
			}
			$("#alreadyGuessed").show();
		}
	};

	this.mapAnswersToCells = function()
	{
		for (var i in this.cells)
		{ 
			if ( this.cells.hasOwnProperty(i) ) {
				var c = this.cells[i];
				if ( c.answerId != "" ) {
					c.answer = q.answers[ c.answerId ];
					c.answer.cells.push( c );
				}
			}
		}
	};

	this.decrementClock = function()
	{
		if ( this.done ) {
			return;
		}
		this.seconds--;
		this.drawClock();
		if ( this.seconds === 0 ) {
			this.finish();
		} 
	};

	this.drawClock = function()
	{
		var s = this.seconds % 60;
		var m = ( this.seconds - s ) / 60;
		$("#timer").html( m + ":" + padZero(s) );
	};

	this.updateNumGuessed = function()
	{
		$("#numGuessed").text( this.numGuessed + "/" + this.numAnswers + " guessed" );
	};

	this.finish = function()
	{
		$("#giveUp").html("");
		$("#txtUser").attr("disabled", "disabled");
		this.done = true;
		if ( screenName == "" ) {
			$("#overlay").show();
			$("#askBox").show();
		} 
		else {
			this.setResults();
		}

	};

	this.setResults = function()
	{
		$("#overlay").show();
		$("#loading").show();

		var x = [];
		for ( var i in q.answers )
		{
			if ( q.answers.hasOwnProperty(i) ) {
				var a = q.answers[i];
				if ( a.answered ) {
					x.push( a.id + ":1" );
				}
				else {
					x.push( a.id + ":0" );
				}
			}
		}
		cereal = x.join(";");
	
		$.post("/quizzes/php/t-set-results.php", { quiz: q.id, timeLeft: q.seconds, guesses: cereal },
			function(data){
				$("#loading").hide();
				var lines = data.split("\n");
				if ( lines[0] == "200" ) {
					q.readStats(lines);
					showAnswersFinal();
				}
				else {
					alert("Error. " + data);
					$("#overlay").hide();
				}
			});
	};


	this.readStats = function(lines)
	{
		for (var i=1; i<lines.length; i++)
		{
			var x = lines[i].trim();
			if ( x == "" ) {
				continue;
			}
			var tabs = x.split("\t");
			switch ( tabs[0] )
			{
				case "QUIZ":
					this.timesTaken = parseInt(tabs[1],10);
					this.sumOfScores = parseInt(tabs[2],10);
					if ( this.numGuessed === 0 ) {
						this.percentile = 0;
					}
					else if ( this.numGuessed == this.numAnswers ) {
						this.percentile = 100;
					}
					else {
						var better = parseInt(tabs[3],10);
						this.percentile = ((this.timesTaken-better)*100)/this.timesTaken;
						this.percentile = this.percentile.toFixed(1);
					}
					this.userTaken = parseInt(tabs[4],10);
					this.userHigh = parseInt(tabs[5],10);
					break;
				case "ANSWER":
					var id = tabs[1];
					var a = this.answers[id];
					a.timesGuessed = parseInt(tabs[2],10);
					a.userGuessed = parseInt(tabs[3],10);
					break;
			}
		}
	};

	this.drawCells = function()
	{
		for (var i in this.cells)
		{ 
			if ( this.cells.hasOwnProperty(i) ) {
				this.cells[i].draw();
			}
		}
	};

	this.preloadMapCells = function()
	{
		for (var i in this.cells)
		{ 
			if ( this.cells.hasOwnProperty(i) ) 
			{
				var c = this.cells[i];
				var i1 = new Image();
				i1.src = "/quizzes/img/quiz-img/correct/" + c.fN;
				var i2 = new Image();
				i2.src = "/quizzes/img/quiz-img/incorrect/" + c.fN;
			}
		}

	}
};

/*** BIG IMAGE ***/
var BigImage = function(div, file, credit)
{
	this.div = div;
	this.file = file;
	this.credit = credit;

	this.display = function()
	{
		$("#overlay").show();
		$("#bibImage").html("<img src='/quizzes/img/quiz-img/" + q.id + "/" + this.file + "'></img>");
		$("#bigImageBox").show();
	};
};

var displayBigImage = function(which)
{
	for (var i=0; i<q.bigImages.length; i++)
	{
		var bi = q.bigImages[i];
		if ( bi.div == which )
		{
			bi.display();
			return;
		}
	}
};

var bibClose = function()
{
	$("#overlay").hide();
	$("#bigImageBox").hide();
};


/*** CELL CLASS ***/
var Cell = function(id, answerId)
{
	this.id = id;
	this.answerId = answerId;
	this.answer = null;
};

Cell.prototype = {
	draw: function() {
		alert( "drawParent: " + this.answerId);
	},
	standardDraw: function(col)
	{
		var x = "#" + this.id;
		$(x).html( this.answer.displayText[ col ] );
		if ( this.answer.answered ) {
			$(x).addClass("correct");
		}
		else {
			$(x).addClass("incorrect");
		}
		if ( !q.done ) {
			animate(this.id, 96);
		}
	}
};


//normal cell
var ACell = function(id, answerId)
{
	Cell.apply(this, [id, answerId] );  
};
ACell.prototype = Object.create(Cell.prototype);  
ACell.prototype.draw = function()
{
	this.standardDraw(0);
};

//draw comes from a custom column
var CCell = function(id, answerId, drawCol)
{
	Cell.apply(this, [id, answerId] );  
	this.drawCol = drawCol;
};
CCell.prototype = Object.create(Cell.prototype);  
CCell.prototype.draw = function()
{
	this.standardDraw(this.drawCol);
};


//fill in the blank
var FCell = function(id, answerId)
{
	Cell.apply(this, [id, answerId] );  
};
FCell.prototype = Object.create(Cell.prototype);  
FCell.prototype.draw = function()
{
	var x = "#" + this.id;

	$(x).html( this.answer.displayText[ 0 ] );
	if ( this.answer.answered ) {
		$(x + " span.f").addClass("correct");
		$(x + " span.f").addClass("under");
	}
	else {
		$(x + " span.f").addClass("incorrect");
		$(x + " span.f").addClass("under");
	}
};

//for maps
var MCell = function(id, mId, answerId, fN)
{
	Cell.apply(this, [id, answerId] );  
	this.mId = mId;
	this.fN = fN;
};
MCell.prototype = Object.create(Cell.prototype);  
MCell.prototype.draw = function()
{
	this.standardDraw(0);

	var iPath = "/quizzes/img/quiz-img/" + q.id + "/"
	if ( this.answer.answered ) {
		iPath += "correct/";
	}
	else {
		iPath += "incorrect/";
	}
	iPath += this.fN;
	$("#" + this.mId).html( "<img src=\"" + iPath + "\">" );
};


var Answer = function(id, displayText, matchText)
{
	this.id = id;
	this.displayText = displayText;
	this.matchText = matchText;
	this.answered = false;
	this.cells = [];

	this.timesGuessed = -1;
	this.userGuessed = -1;

	this.drawStatRow = null;

	this.isMatch = function(txt)
	{
		for (var i=0; i<this.matchText.length; i++) 
		{
			if ( txt.match(this.matchText[i]) ) {
				return true;
			}
		}
		return false;
	};

	this.drawCells = function()
	{
		for (var i in this.cells)
		{ 
			if ( this.cells.hasOwnProperty(i) ) {
				this.cells[i].draw();
			}
		}
	};
};

Answer.cmp = function(a, b)
{
	if ( a.answered && !b.answered ) {
		return -1;
	}
	else if ( b.answered && !a.answered ) {
		return 1;
	}
	else if ( a.timesGuessed > b.timesGuessed ) {
		return -1;
	}
	else if ( a.timesGuessed < b.timesGuessed ) {
		return 1;
	}
	return 0;
};

var LoginWindow = function()
{
	this.selTab = 1;
	this.callback = null;

	this.launch = function( defaultTab, callback  )
	{
		document.getElementById("btnVerify").style.visibility = "hidden";
		this.selectTab( defaultTab );
		$("#overlay").show();
		$("#loginO").show();
		$("#tabContent" + this.selTab).show();
		this.callback = callback;
	};

	this.selectTab = function(n)
	{
		if ( this.selTab != n )
		{
			$("#tab" + this.selTab).removeClass("selTab");
			$("#tab" + n).addClass("selTab");
			$("#tabContent" + this.selTab).hide();
			$("#tabContent" + n).show();
			this.selTab = n;
		}
	};

	this.close = function()
	{
		$("#overlay").hide();
		$("#loginO").hide();
		if ( this.callback !== null ) {
			this.callback();
		}
	};
};

var StatsWindow = function()
{
	this.answers = null;
	this.data = null;
	this.headers = [];
	this.template = [];
	this.drawStatRow = StatsWindow.drawStatRow1;

	this.launch = function()
	{
		this.draw();
		this.drawStatBox1();
	};

	this.drawStatBox1 = function()
	{
		var pct = Math.round( (q.numGuessed / q.numAnswers ) * 100);
		var average = 0;
		if ( q.timesTaken > 0 )
		{
			average = Math.floor( q.sumOfScores / q.timesTaken );
		}
		$("#statLine1").html("You scored <span class='big'>" + q.numGuessed + "/" + q.numAnswers + "</span> = <span class='big'>" + pct + "</span>%.");
		$("#statLine2").html("This beats or equals " + q.percentile + "% of test takers.");
		$("#statLine3").html("The average score is " + average + ".");
		if ( screenName != "" ) {
			$("#statLine4").html("Your high score is " + q.userHigh + ".");
			$("#statLine4").show();
		}
		else {
			$("#statLine4").hide();
		}
		$("#statBox1").show();
	};

	this.draw = function()
	{
		this.answers = [];
		for (var i in q.answers) {
			if ( q.answers.hasOwnProperty(i) ) 
			{
				this.answers.push( q.answers[i] );
			}
		}
		this.answers.sort( Answer.cmp );

		var html = [];
		html.push('<table cellpadding="0" cellspacing="0">');
		for (i=0; i<this.headers.length; i++)
		{
			html.push("<th>" + this.headers[i] + "</th>");
		}
		html.push("<th class='a'>% Guessed Correct</th>");
		if ( screenName != "" ) {
			html.push("<th class='a'>Your Average</th>");
		}
		for (i=0; i<this.answers.length; i++)
		{
			var a = this.answers[i];
			html.push("<tr>");
			if ( a.drawStatRow !== null ) {
				a.drawStatRow(html);
			}
			else {
				this.drawStatRow(a, html);
			}
			html.push( this.getStatBar( a.timesGuessed, q.timesTaken, a.answered ) );
			if ( screenName != "" ) {
				html.push( this.getStatBar( a.userGuessed, q.userTaken, a.answered ) );
			}
			html.push("</tr>");
		}
		html.push("</table>");
		$("#statsInner").html( html.join('') );
		$("#stats").show();
	};

	this.getStatBar = function( guessed, taken, correct )
	{
		var pct = 0;
		if ( taken !== 0 ) {
			pct = Math.floor( (guessed/taken) * 100 );
		}
		var c;
		if ( correct ) {
			c = "correct";
		} else {
			c = "incorrect";
		}
		return '<td><div class="pct ' + c + '">' + pct + '%</div><div class="bout"><div class="bar b' + c + '" style="width: ' + pct + 'px;"></div></div></td>';
	};
};

// default stat row
StatsWindow.drawStatRow1 = function(a, html)
{
	for (var i=0; i<this.template.length; i++)
	{
		html.push( "<td>" + a.displayText[ this.template[i] ] + "</td>");
	}
};

var loginW = new LoginWindow();
var statsW = new StatsWindow();

$(document).ready(function() {
	var x = getIEVersion();
	if ( x > 0 && x < 7 )
	{
		$("#lowIe").show();
	}
	q.init();
	$("#tab1").click( function() { loginW.selectTab(1); } );
	$("#tab2").click( function() { loginW.selectTab(2); } );
	$("#tab3").click( function() { loginW.selectTab(3); } );
	$("#close").click( function() { loginW.close(); } );
	$("#bibClose").click( function() { bibClose(); } );
	$("#btnLogin").click( function() { login(); } );
	$("#btnCreate").click( function() { createAccount(); } );
	$("#btnReset").click( function() { resetPassword(); } );
	$("#btnShowAnswers").click( function() { showAnswers(); } );
	$("#btnRetake").click( function() { window.location.reload(); } );
	$("#btnVerify").click( function() { resendVerification(); } );
});

function load() {
	showLoginStatus();
}
