
var oneminutetester = function () {

    var testSessionId;
	var wordsById;
	
	var currentTestList;//list of word ids
	var numRight;
	var numWrong;
	
    var currentWordId;
    var showingPrompt;
    
    var stats;//shown at the end of the test session
    
    var showStatusInterval = null;

    function init(id, words) {
        testSessionId = id;
		stats = {
			'testSessionId': id,
			'startTime': (new Date()).getTime(), 
			'stopTime': (new Date()).getTime() + (60 * 1000), 
			'endTime': null,
			'wordsById': {},
			'numRight': 0,
			'numWrong': 0
		};
		
		wordsById = {};
		currentTestList = [];
		for(var i = 0; i < words.length; i++) {
			stats.wordsById[words[i]['id']] = {'word': words[i]['word'], 'gotRight':false, 'gotWrong':false};
			wordsById[words[i]['id']] = words[i]['word'];
			currentTestList.push(words[i]['id']);
		}
						
        showingPrompt = false;
        
		//unbind anything that was setup from a previous session
        $('#input').unbind('keypress', input_keydown);
        $('#checkword').unbind('click', submitGuess);
		//rebind
        $('#input').bind('keypress', input_keydown);
        $('#checkword').bind('click', submitGuess);
        
		$('#input').val('');
		$('#input').focus();
        nextWord();
        
        showStatusInterval = setInterval(showStatus, 1000);
    }
    
    function stop() {
		stats.endTime = (new Date()).getTime();
		clearInterval(showStatusInterval);
		endTestSession(stats);		
	    showSessionDetails();
    }
    
    function nextWord() {
		//if we have more words
        if(currentTestList.length > 0) {
			//get and remove one of the ids from the current list
            currentWordId = currentTestList.splice(Math.floor(Math.random() * currentTestList.length), 1)[0];
            showPrompt();
        } else { //ran out of words (probably will never happen)
			stop();
        }
    }
    
    function showPrompt() {
		var currentWord = wordsById[currentWordId];
		showingPrompt = true;
		
		$('#prompt').html(currentWord);
    }
	
    function hidePrompt() {
        $('#prompt').html('&nbsp;');
        showingPrompt = false;
        $('#input').css('backgroundColor', '#fff');//TODO: remove?
    }
    
    function input_keydown(e) {
		if (e.keyCode == 13 || e.keyCode == 10) {
			if($('#input').val() != "") {
				submitGuess();
			}
		} else if (showingPrompt) {
			showingPrompt = false;
			hidePrompt();
		}
    }
	
	function submitGuess() {
		var correctWord = wordsById[currentWordId].toLowerCase();
		var guess = $('#input').val();
		guess = jQuery.trim(guess);
		guess = guess.toLowerCase();
		if(guess == correctWord) {
			stats.numRight += 1;
			stats.wordsById[currentWordId].gotRight = true;
			logTestResult(testSessionId, currentWordId, true);
		} else { //got it wrong
			stats.numWrong += 1;
			stats.wordsById[currentWordId].gotWrong = true;
			logTestResult(testSessionId, currentWordId, false, $('#input').val());
			
			//penalize using a simple measure of how many characters were missed
			var charsCorrect = 0;
			for (var i = 0; i < correctWord.length; i++) {
				if (i < guess.length && correctWord.charAt(i) == guess.charAt(i)) {
					charsCorrect += 1;
				} else {
					break;
				}
			}
			var charsMissed = correctWord.length - charsCorrect;
			//var penaltySecPerChar = 0.363636;//= 2.75 char/sec = 165 char/min = 33 wpm @ 5 char/word
			//go with something more generous becasue they probably spent some time thinking
			var penaltySecPerChar = 0.24;//= 4.167 char/sec = 250 char/min = 50 wpm @ 5 char/word
			var penaltySec = penaltySecPerChar * charsMissed;
			stats.stopTime = stats.stopTime - (penaltySec * 1000);
			//animate the time to show that the penalty has been applied
			showStatus();
			$("#test_timer").css('color', '#f00').animate( { color: 'black' }, 1000);
		}
		
		showStatus();		
		
		nextWord();
		$('#input').val('');
	}
	
	function showStatus() {
		var now = (new Date()).getTime();
		var timeRemainingSec = (stats.stopTime - now) / 1000.0;
		if (timeRemainingSec > 0) {
			$("#test_timer").text(secToHHMMSS(Math.round(timeRemainingSec)));
			$("#test_num_right").text(stats.numRight);
		} else {
			stop();
		}
	}

	function showSessionDetails() {
	
		$('#test_score').text(stats.numRight);
		
		var sortedWords = [];
		var wordToId = {};
		for(var id in stats.wordsById) {
			if(typeof id == "string") {
				sortedWords.push(stats.wordsById[id].word);
				wordToId[stats.wordsById[id].word] = id;
			}
		}
		sortedWords.sort();
		
		var correctWords = [];
		var incorrectWords = [];
		for(var i = 0; i < sortedWords.length; i++) {
			var word = sortedWords[i];
			var id = wordToId[word];
			
			if (stats.wordsById[id].gotRight) {
				correctWords.push(word);
			} else if (stats.wordsById[id].gotWrong) {
				incorrectWords.push(word);
			}
		}
		
		var wordsTable = "<table border='1' cellspacing='0' cellpadding='2'>";
		wordsTable += "<tr><th> Correct </th><th> Incorrect </th></tr>";
		for(var i = 0; i < correctWords.length || i < incorrectWords.length; i++) {
			wordsTable += "<tr><td>";
			if(i < correctWords.length)
				wordsTable += "<a target=\"dict\" title=\"Define\" href=\"http://www.google.com/dictionary?aq=f&langpair=en|en&q=" + correctWords[i] + "\">" + correctWords[i] + "</a>";
			wordsTable += "</td><td style='color:red'>";
			if(i < incorrectWords.length)
				wordsTable += "<a target=\"dict\" title=\"Define\" href=\"http://www.google.com/dictionary?aq=f&langpair=en|en&q=" + incorrectWords[i] + "\">" + incorrectWords[i] + "</a>";
			wordsTable += "</td></tr>";
		}
		wordsTable += "</table>";
		
		$('#test_words').html(wordsTable);
	}
	

	//expose public API
    return {
        'init':init
    };
}();
