//////////////////////////////////////////////////////////////
//															//
//	© 2005 - 2007 Vereyon									//
//  http://www.vereyon.nl									//
//	All rights reserved										//
//															//
//////////////////////////////////////////////////////////////
Editor.prototype.__type = "Editor";
Editor.prototype.bInitializing = false;
Editor.prototype.bErrorMode = false;
Editor.prototype.bTestCancelled = false;
Editor.prototype.bLoggedIn = false;

Editor.prototype.hEditButton = null;
Editor.prototype.hTestButton = null;
Editor.prototype.hLoadingDiv = null;
Editor.prototype.hInputDiv = null;
Editor.prototype.hTestDiv = null;
Editor.prototype.hTestResultDiv = null;
Editor.prototype.hEditorContentParent = null;
Editor.prototype.hLastRow = null;

Editor.prototype.hStatusBar = null;
Editor.prototype.hStatusBarTimer = null;
Editor.prototype.strStatusBarCurrentMessage = null;
Editor.prototype.strStatusBarDefaultMessage = null;
Editor.prototype.hTitleBar = null;
Editor.prototype.hToolBar = null;

Editor.prototype.hWordTable = null;
Editor.prototype.hWordTablePriLangHeader = null;
Editor.prototype.hWordTablePriRemarkHeader = null;
Editor.prototype.hWordTableSecLangHeader = null;
Editor.prototype.hWordTableSecRemarkHeader = null;

Editor.prototype.hTestHistroyTableDiv = null;
Editor.prototype.hTestHistroyTable = null;
Editor.prototype.hTestInputDiv = null;
Editor.prototype.hTestAnswerInput = null;
Editor.prototype.hTestStatsDiv = null;
Editor.prototype.hTestStatsDivLeft = null;
Editor.prototype.hTestStatsDivRight = null;
Editor.prototype.hTestStatsDivProgressBar = null;
Editor.prototype.hTestStatsDivLargeScore = null;
Editor.prototype.arrMultipleChoiceAnswers = null;
Editor.prototype.hMultipleChoiceTestTimeout = null;
Editor.prototype.hAnswerTimeProgressBar = null;

Editor.prototype.hTestResultDivContent = null;
Editor.prototype.hTestResultDivTableHeader = null;
Editor.prototype.hTestResultDivTable = null;
Editor.prototype.hTestResultStatusDiv = null;

Editor.prototype.ajaxRequest = null;
Editor.prototype.resultsAjaxRequest = null;
Editor.prototype.notifyTestAjaxRequest = null;
Editor.prototype.planningProgressRequest = null;
Editor.prototype.symbolPicker = null;
Editor.prototype.timer = null;
Editor.prototype.testStartTime = null;
Editor.prototype.testQuestionCount = null;
Editor.prototype.testErrorCount = null;
Editor.prototype.speech = null;
Editor.prototype.oPrimaryVoice = null;
Editor.prototype.oSecondaryVoice = null;
Editor.prototype.answerTimer = null;

Editor.prototype.learningEngine = null;
Editor.prototype.wordList = null;
Editor.prototype.mode = null;
Editor.prototype.targetMode = null;
Editor.prototype.operationMode = null;

Editor.prototype.hActiveInput = null;

Editor.prototype.openButton = null;
Editor.prototype.saveButton = null;
Editor.prototype.undoButton = null;
Editor.prototype.redoButton = null;
Editor.prototype.repeatButton = null;
Editor.prototype.lineInputButton = null;
Editor.prototype.newWordButton = null;
Editor.prototype.insertSymbolButton = null;
Editor.prototype.propertiesButton = null;
Editor.prototype.deleteSelectionButton = null;
Editor.prototype.speechSettingsButton = null;

Editor.prototype.startNewTestButton = null;
Editor.prototype.restartTestButton = null;
Editor.prototype.stopTestButton = null;
Editor.prototype.testProgressButton = null;
Editor.prototype.saveTestResultsButton = null;

Editor.prototype.iCurrentPlanning = null;
Editor.prototype.iCurrentPlanningDateId = null;

function Editor(mode, wordlist) {

	this.Initialize = function() {
	
		this.bInitializing = true;
		this.operationMode = "normal";
	
		this.wordList = new Wordlist();
		this.wordList.OnLog.Suscribe(this.OnWordlistLog, this);
		this.wordList.OnLoad.Suscribe(this.OnWordlistLoad, this);
		this.wordList.OnSave.Suscribe(this.OnWordlistSave, this);
		this.wordList.hEditor = this;
		
		// Load wordlist
		this.bLoadingWordlist = false;
		
		this.learningEngine = new LearningEngine();
		this.learningEngine.wordList = this.wordList;
		
		// Bind mode buttons
		this.hEditButton = document.getElementById("EditButton");
		this.hEditButton.owningClass = this;
		this.hEditButton.onclick = this.OnEditModeButtonClick;
		this.hTestButton = document.getElementById("TestButton");
		this.hTestButton.owningClass = this;
		this.hTestButton.onclick = this.OnTestModeButtonClick;
		
		// Bind loading div
		this.hLoadingDiv = document.getElementById("LoadingDiv");
		
		// Bind content parent div
		this.hEditorContentParent = document.getElementById("contentDivParent");
		
		// Bind status bar
		this.hStatusBar = document.getElementById("StatusBar");
		this.hTitleBar = document.getElementById("TitleBar");
		this.hToolBar = document.getElementById("ToolBar");
		this.SetStatusBarDefaultMessage(TEXT['Editor.Loading']);
		
		// Initialize symbolpicker
		this.symbolPicker = new SymbolPicker(this.hEditorContentParent);
		this.symbolPicker.CallbackFunction = this.SymbolPickerCallback;
		this.symbolPicker.CallbackClass = this;
		
		// Initialize content div's
		this.InitializeInputDiv();
		this.InitializeTestDiv();
		this.InitializeTestResultDiv();
		this.InitializeToolbar();
		
		// Load speech component
		this.speech = new Speech.SpeechControl();
		this.speech.OnLoad.Suscribe(this.OnSpeechLoaded, this);
		
		// Install onbeforeunload event handler
		window.onbeforeunload = this.OnBeforePageUnload.Bind(this);
		
		// Attempt to finish initialization
		this.FinalizeInitialization();
		
		// Attempt to notift google analytics
		try {
			urchinTracker("/analytics/editorloaded");
		}
		catch(ex) {}
	};
	
	this.InitializeInputDiv = function Editor$InitializeInputDiv() {
		
		// Declare variables
		var newRow, newCell, newP, newInput;
		
		// Create div
		this.hInputDiv = document.createElement("DIV");
		this.hInputDiv.className = "editorContentDiv";
		this.hInputDiv.style.visibility = "hidden";
		this.hEditorContentParent.appendChild(this.hInputDiv);
		
		// Create wordtable
		this.hWordTable = document.createElement("TABLE");
		this.hWordTable.cellSpacing = "0px";
		this.hWordTable.cellPadding = "0px";
		this.hWordTable.className = "editorWordTable";
		this.hInputDiv.appendChild(this.hWordTable);
		
		// Create wordtable header
			newRow = this.hWordTable.insertRow(-1);
			newCell = newRow.insertCell(-1);
			newCell.className = "editorWordTableHeader";
			newInput = document.createElement("INPUT");
			newInput.type = "checkbox";
			newInput.owningClass = this;
			newInput.onchange = this.OnSelectAllCheckboxChange;
			newCell.appendChild(newInput);
			this.hWordTableSecRemarkHeader = newP;
			
			newCell = newRow.insertCell(-1);
			newCell.className = "editorWordTableHeader";
			newP = document.createElement("P");
			newP.appendChild(document.createTextNode(TEXT['Editor.PrimaryTranslation']));
			newCell.appendChild(newP);
			this.hWordTablePriLangHeader = newP;
			
			newCell = newRow.insertCell(-1);
			newCell.className = "editorWordTableHeader";
			newP = document.createElement("P");
			newP.appendChild(document.createTextNode(TEXT['Editor.PrimaryRemark']));
			newCell.appendChild(newP);
			this.hWordTablePriRemarkHeader = newP;
			
			newCell = newRow.insertCell(-1);
			newCell.className = "editorWordTableHeader";
			newP = document.createElement("P");
			newP.appendChild(document.createTextNode(TEXT['Editor.SecondaryTranslation']));
			newCell.appendChild(newP);
			this.hWordTableSecLangHeader = newP;
			
			newCell = newRow.insertCell(-1);
			newCell.className = "editorWordTableHeader";
			newP = document.createElement("P");
			newP.appendChild(document.createTextNode(TEXT['Editor.SecondaryRemark']));
			newCell.appendChild(newP);
			this.hWordTableSecRemarkHeader = newP;
	}
	
	this.ClearWordTable = function Editor$ClearWordTable() {
	
		// Delete all rows except header row
		while(this.hWordTable.rows.length > 1) {
			this.hWordTable.deleteRow(1);
		}
	}
	
	this.CreateWordTableFromWordlist = function Editor$CreateWordTableFromWordlist() {
	
		// Clear the word table
		this.ClearWordTable();
		
		// Iterate trough words
		for(i = 0; i < this.wordList.Count(); i++) {
			
			// Load values
			this.CreateWordTableRow(this.hWordTable, i, -1);
		}
	}
	
	this.CreateNewWordTableRow = function Editor$CreateNewWordTableRow(hTable) {
	
		// Declare variables
		var newRow, newCell, newInput;
		var wordIndex;
		
		// Create word
		wordIndex = this.wordList.AppendNewWord();
		
		// Create row
		newRow = this.CreateWordTableRow(hTable, wordIndex, -1);
		
		return newRow;
	}
	
	this.CreateWordTableRow = function Editor$CreateWordTableRow(hTable, wordIndex, iIndex) {
	
		// Declare variables
		var newRow, newCell, newInput;
		
		// Create row
		newRow = hTable.insertRow(iIndex);
		newRow.wordId = this.wordList.GetValue(wordIndex, 0);
		newRow.wordIndex = wordIndex;
		this.hLastRow = newRow;
		
		// Create select cell
		newCell = newRow.insertCell(-1);
		newCell.className = "editorWordTableSelectCell";
		newInput = document.createElement("INPUT");
		newInput.type = "checkbox";
		newRow.rowSelectInput = newInput;
		newCell.appendChild(newInput);
		
		// Create primary language cell
		newCell = newRow.insertCell(-1);
		newCell.className = "editorWordTableLanguageCell";
		newInput = document.createElement("INPUT");
		newInput.type = "text";
		newInput.value = this.wordList.GetValue(wordIndex, 1);
		newInput.owningClass = this;
		newInput.onchange = this.OnInputChanged;
		newInput.onfocus = this.OnInputFocus;
		newInput.onblur = this.OnInputBlur;
		newInput.onmouseup = this.OnInputClick;
		newInput.onkeyup = this.OnInputKeyUp;
		newInput.wordIndex = wordIndex;
		newInput.columnIndex = 1;
		newInput.hRow = newRow;
		newRow.primaryTranslationInput = newInput;
		newCell.appendChild(newInput);
		
		// Create primary remark cell
		newCell = newRow.insertCell(-1);
		newCell.className = "editorWordTableRemarkCell";
		newInput = document.createElement("INPUT");
		newInput.type = "text";
		newInput.value = this.wordList.GetValue(wordIndex, 3);
		newInput.owningClass = this;
		newInput.onchange = this.OnInputChanged;
		newInput.onfocus = this.OnInputFocus;
		newInput.onblur = this.OnInputBlur;
		newInput.onmouseup = this.OnInputClick;
		newInput.onkeyup = this.OnInputKeyUp;
		newInput.wordIndex = wordIndex;
		newInput.columnIndex = 3;
		newInput.hRow = newRow;
		newRow.primaryRemarkInput = newInput;
		newCell.appendChild(newInput);
		
		// Create secondary language cell
		newCell = newRow.insertCell(-1);
		newCell.className = "editorWordTableLanguageCell";
		newInput = document.createElement("INPUT");
		newInput.type = "text";
		newInput.value = this.wordList.GetValue(wordIndex, 2);
		newInput.owningClass = this;
		newInput.onchange = this.OnInputChanged;
		newInput.onfocus = this.OnInputFocus;
		newInput.onblur = this.OnInputBlur;
		newInput.onmouseup = this.OnInputClick;
		newInput.onkeyup = this.OnInputKeyUp;
		newInput.wordIndex = wordIndex;
		newInput.columnIndex = 2;
		newInput.hRow = newRow;
		newRow.secondaryTranslationInput = newInput;
		newCell.appendChild(newInput);
		
		// Create secondary remark cell
		newCell = newRow.insertCell(-1);
		newCell.className = "editorWordTableRemarkCell";
		newInput = document.createElement("INPUT");
		newInput.type = "text";
		newInput.value = this.wordList.GetValue(wordIndex, 4);
		newInput.owningClass = this;
		newInput.onchange = this.OnInputChanged;
		newInput.onfocus = this.OnInputFocus;
		newInput.onblur = this.OnInputBlur;
		newInput.onmouseup = this.OnInputClick;
		newInput.onkeyup = this.OnInputKeyUp;
		newInput.wordIndex = wordIndex;
		newInput.columnIndex = 4;
		newInput.hRow = newRow;
		newRow.secondaryRemarkInput = newInput;
		newCell.appendChild(newInput);
		
		return newRow;
	}
	
	this.OnInputChanged = function Editor$OnInputChanged(e) {
	
		// Declare variables
		var srcClass, oEvent;
		
		srcClass = this.owningClass;
		
		if(window.event) {
		
			// Windows IE and DOM level 2
			// Bug: using window.event seems to slowdown event handling in IE. Perhaps IE takes a lot of time setting the window.event object.
			oEvent = window.event;
		} else {
		
			// Firefox
			oEvent = e;
		}
		
		// Check if input firing change event is last part of last word
		if(this.parentNode.parentNode == srcClass.hLastRow) {
		
			if(oEvent.keyCode == 9 || this.value != "") {
			
				// Create new word
				srcClass.CreateNewWordTableRow(srcClass.hWordTable);
			}
		}
		
		// Set changed word values
		if(this.wordIndex != undefined && this.columnIndex != undefined) {
			srcClass.wordList.SetValue(this.wordIndex, this.columnIndex, this.value);
		}
			
			
		srcClass.Invalidate();
	}
	
	this.OnInputFocus = function Editor$OnInputFocus(e) {
	
		// Declare variables
		var srcClass, oEvent;
		
		srcClass = this.owningClass;
		
		if(window.event) {
		
			// Windows IE and DOM level 2
			// Bug: using window.event seems to slowdown event handling in IE. Perhaps IE takes a lot of time setting the window.event object.
			oEvent = window.event;
		} else {
		
			// Firefox
			oEvent = e;
		}
		
		srcClass.hActiveInput = this;
		srcClass.insertSymbolButton.Enable();
	}
	
	this.OnInputBlur = function Editor$OnInputBlur(e) {
	
		// Declare variables
		var srcClass, oEvent;
		
		srcClass = this.owningClass;
		
		if(window.event) {
		
			// Windows IE and DOM level 2
			// Bug: using window.event seems to slowdown event handling in IE. Perhaps IE takes a lot of time setting the window.event object.
			oEvent = window.event;
		} else {
		
			// Firefox
			oEvent = e;
		}
		
		/*
		if(srcClass && srcClass.hActiveInput == this) {
			srcClass.hActiveInput = null;
			srcClass.insertSymbolButton.Disable();
		}
		*/
		
		// If input is a word input, check if the word was changed
		if(this.wordIndex != undefined && this.columnIndex != undefined) {
			if (srcClass.wordList.GetValue(this.wordIndex, this.columnIndex) != this.value) {
				srcClass.wordList.SetValue(this.wordIndex, this.columnIndex, this.value);
				
				// Check if input firing change event is last part of last word
				if(this.parentNode.parentNode == srcClass.hLastRow) {
				
					if(oEvent.keyCode == 9 || this.value != "") {
					
						// Create new word
						srcClass.CreateNewWordTableRow(srcClass.hWordTable);
					}
				}
			}
		}
		
		srcClass.Invalidate();
	}
	
	this.OnInputKeyUp = function Editor$OnInputKeyUp(e) {
	
		// Declare variables
		var srcClass, oEvent;
		var hRow;
		
		srcClass = this.owningClass;
		
		if(window.event) {
		
			// Windows IE and DOM level 2
			// Bug: using window.event seems to slowdown event handling in IE. Perhaps IE takes a lot of time setting the window.event object.
			oEvent = window.event;
		} else {
		
			// Firefox
			oEvent = e;
		}
		
		if(oEvent.keyCode == 38) {
			
			// Attempt to focus on the text input above (if exists)
			hRow = this.hRow.previousSibling;
			if(hRow) {
				if(hRow.wordId) {
					switch(this.columnIndex) {
						case 1:
							hRow.primaryTranslationInput.focus();
							break;
						case 2:
							hRow.secondaryTranslationInput.focus();
							break;
						case 3:
							hRow.primaryRemarkInput.focus();
							break;
						case 4:
							hRow.secondaryRemarkInput.focus();
							break;
					}
				}
			}
		} else if(oEvent.keyCode == 40) {
			
			// Attempt to focus on the text input below (if exists)
			hRow = this.hRow.nextSibling;
			if(hRow) {
				if(hRow.wordId) {
					switch(this.columnIndex) {
						case 1:
							hRow.primaryTranslationInput.focus();
							break;
						case 2:
							hRow.secondaryTranslationInput.focus();
							break;
						case 3:
							hRow.primaryRemarkInput.focus();
							break;
						case 4:
							hRow.secondaryRemarkInput.focus();
							break;
					}
				}
			}
		}
	}
	
	this.OnWordlistLoad = function Editor$OnWordlistLoad() {
		
		this.bLoadingWordlist = false;
		this.CreateWordTableFromWordlist();
		this.FinalizeInitialization();
	}
	
	this.OnWordlistSave = function Editor$OnWordlistSave(strMessage) {
	
		this.SetStatusBarMessage(strMessage, 2000);
	}
	
	this.OnSaveButtonClick = function Editor$OnSaveButtonClick() {
	
		// Attempt to save the wordlist
		this.owningClass.wordList.SaveToXml("xml.php?page=savewordlist");
	}
	
	this.InitializeTestDiv = function Editor$InitializeTestDiv() {
	
		// Declare variables
		var strPriLanguage, strSecLanguage;
		var newDiv, newTable, newP, newRow, newCell, newInput, newB;
		
		// Check if test div is already created
		if(this.hTestDiv) {
			this.hEditorContentParent.removeChild(this.hTestDiv);
		}
		
		// Create div
		this.hTestDiv = document.createElement("DIV");
		this.hTestDiv.className = "editorContentDiv";
		this.hTestDiv.style.visibility = "hidden";
		this.hEditorContentParent.appendChild(this.hTestDiv);
		
		// Test statistics div
			this.hTestStatsDiv = document.createElement("DIV");
			this.hTestStatsDiv.className = "testStatsDiv";
			this.hTestDiv.appendChild(this.hTestStatsDiv);
			
			this.hTestStatsDivLeft = document.createElement("DIV");
			this.hTestStatsDivLeft.className = "testStatsDivLeft";
			this.hTestStatsDiv.appendChild(this.hTestStatsDivLeft);
			
			this.hTestStatsDivRight = document.createElement("DIV");
			this.hTestStatsDivRight.className = "testStatsDivRight";
			this.hTestStatsDiv.appendChild(this.hTestStatsDivRight);
			
			this.hTestStatsDivLargeScore = document.createElement("P");
			this.hTestStatsDivLargeScore.className = "testStatsDivLargeScore";
			this.hTestStatsDivRight.appendChild(this.hTestStatsDivLargeScore);
			
			this.SetTestStatistics("", "", "");
		
		// Test control div
			newDiv = document.createElement("DIV");
			newDiv.className = "testControlDiv";
			this.hTestDiv.appendChild(newDiv);
			
			newP = document.createElement("P");
			newDiv.appendChild(newP);
			this.startNewTestButton = document.createElement("INPUT");
			this.startNewTestButton.type = "button";
			this.startNewTestButton.className = "testControlDivButton";
			this.startNewTestButton.value = TEXT['Editor.StartNewTestButton'];
			this.startNewTestButton.owningClass = this;
			this.startNewTestButton.onclick = this.OnNewTestButtonClick;
			newP.appendChild(this.startNewTestButton);
			
			this.stopTestButton = document.createElement("INPUT");
			this.stopTestButton.type = "button";
			this.stopTestButton.className = "testControlDivButton";
			this.stopTestButton.value = TEXT['Editor.StopTestButton'];
			this.stopTestButton.owningClass = this;
			this.stopTestButton.onclick = this.OnStopTestButtonClick;
			newP.appendChild(this.stopTestButton);
			
			this.restartTestButton = document.createElement("INPUT");
			this.restartTestButton.type = "button";
			this.restartTestButton.className = "testControlDivButton";
			this.restartTestButton.value = TEXT['Editor.RestartTestButton'];
			this.restartTestButton.onclick = this.OnRestartTestButtonClick.Bind(this);
			newP.appendChild(this.restartTestButton);
			
			this.testProgressButton = document.createElement("INPUT");
			this.testProgressButton.type = "button";
			this.testProgressButton.className = "testControlDivButton";
			this.testProgressButton.value = TEXT['Editor.ProgressButton'];
			this.testProgressButton.owningClass = this;
			this.testProgressButton.disabled = true;
			//this.testProgressButton.onclick = this.OnTestProgressButtonClick;
			newP.appendChild(this.testProgressButton);
			
			newP = document.createElement("P");
			newDiv.appendChild(newP);
			newInput = document.createElement("INPUT");
			newInput.type = "checkbox";
			newInput.owningClass = this;
			newInput.onclick = this.ToggleTestHistoryTableDiv;
			try {
				newInput.checked = Sys.Settings.Editor.HideLog;
			}
			catch(ex) {
				newInput.checked = false;
			}
			newP.appendChild(newInput);
			newP.appendChild(document.createTextNode(TEXT['Editor.HideAnswerLog']));
		
			// Test input div
			this.hTestInputDiv = document.createElement("DIV");
			this.hTestInputDiv.className = "testInputDiv";
			this.hTestDiv.appendChild(this.hTestInputDiv);
			
			newP = document.createElement("P");
			newP.className = "testInputIdle";
			newP.onclick = this.OnNewTestButtonClick;
			this.hTestInputDiv.appendChild(newP);
			newP.appendChild(document.createTextNode(TEXT['Editor.StartNewTestDiv']));
		
		
		// Test history div
		// The Sys.Settings.Editor.HideLog setting sometimes does not seems to be loaded correctly,
		// therefor, execute code in try block.
		this.hTestHistroyTableDiv = document.createElement("DIV");
		try {
			if(Sys.Settings.Editor.HideLog) {
				this.hTestHistroyTableDiv.className = "testHistoryTableDivHidden";
			} else {
				this.hTestHistroyTableDiv.className = "testHistoryTableDiv";
			}
		}
		catch(ex) {
			this.hTestHistroyTableDiv.className = "testHistoryTableDiv";
		}
		this.hTestDiv.appendChild(this.hTestHistroyTableDiv);
		
		// Test histroy table header
			newTable = document.createElement("TABLE");
			newTableclassName = "testHistoryTable";
			newTable.cellSpacing = 0;
			newTable.cellPadding = 0;
			this.hTestHistroyTableDiv.appendChild(newTable);
			
			newRow = newTable.insertRow(-1);
			newCell = newRow.insertCell(-1);
			newCell.className = "testHistoryTableHeader";
			newCell.width = "75";
			newP = document.createElement("P");
			newP.appendChild(document.createTextNode(TEXT['Editor.Log.Time']));
			newCell.appendChild(newP);

			newCell = newRow.insertCell(-1);
			newCell.className = "testHistoryTableHeader";
			newCell.width = "225";
			newP = document.createElement("P");
			newP.appendChild(document.createTextNode(TEXT['Editor.Log.Question']));
			newCell.appendChild(newP);

			newCell = newRow.insertCell(-1);
			newCell.className = "testHistoryTableHeader";
			newCell.width = "225";
			newP = document.createElement("P");
			newP.appendChild(document.createTextNode(TEXT['Editor.Log.GivenAnswer']));
			newCell.appendChild(newP);
			
			newCell = newRow.insertCell(-1);
			newCell.className = "testHistoryTableHeader";
			newCell.width = "225";
			newP = document.createElement("P");
			newP.appendChild(document.createTextNode(TEXT['Editor.Log.CorrectAnswer']));
			newCell.appendChild(newP);

			newCell = newRow.insertCell(-1);
			newCell.className = "testHistoryTableHeader";
			newCell.width = "158";
			newP = document.createElement("P");
			newP.appendChild(document.createTextNode(TEXT['Editor.Log.Score']));
			newCell.appendChild(newP);
		
		// Test histroy table scroll div
		newDiv = document.createElement("DIV");
		newDiv.className = "testHistoryTableScrollDiv";
		this.hTestHistroyTableDiv.appendChild(newDiv);
		
		// Test history table
		// Total width: 892px
		this.hTestHistroyTable = document.createElement("TABLE");
		this.hTestHistroyTable.className = "testHistoryTable";
		this.hTestHistroyTable.cellSpacing = 0;
		this.hTestHistroyTable.cellPadding = 0;
		newDiv.appendChild(this.hTestHistroyTable);
	}
	
	this.InitializeToolbar = function Editor$InitializeToolbar() {
		
		// Declare variables
		var newDiv
		
		this.openButton = new UI.ToolBarButton(this.hToolBar);
		this.openButton.SetImage("images/icon-open.png", "images/icon-open-grey.png");
		this.openButton.SetToolTip(TEXT['Editor.Toolbar.OpenWordlist']);
		this.openButton.onClick.Suscribe(this.OnOpenButtonClick, this);
		
		this.saveButton = new UI.ToolBarButton(this.hToolBar);
		this.saveButton.SetImage("images/icon-save-16.png", "images/icon-save-16-grey.png");
		this.saveButton.SetToolTip(TEXT['Editor.Toolbar.SaveWordlist']);
		this.saveButton.onClick.Suscribe(this.OnSaveButtonClick, this);
		
		newDiv = document.createElement("DIV");
		newDiv.className = "toolbarSpacerDiv";
		this.hToolBar.appendChild(newDiv);
		
		this.undoButton = new UI.ToolBarButton(this.hToolBar);
		this.undoButton.SetImage("images/icon-undo.png", "images/icon-undo-grey.png");
		this.undoButton.SetToolTip(TEXT['Editor.Toolbar.Undo']);
		this.undoButton.onClick.Suscribe(this.OnUndoButtonClick, this);
		
		this.redoButton = new UI.ToolBarButton(this.hToolBar);
		this.redoButton.SetImage("images/icon-redo.png", "images/icon-redo-grey.png");
		this.redoButton.SetToolTip(TEXT['Editor.Toolbar.Redo']);
		this.redoButton.onClick.Suscribe(this.OnRedoButtonClick, this);
		
		this.repeatButton = new UI.ToolBarButton(this.hToolBar);
		this.repeatButton.SetImage("images/icon-repeat.png", "images/icon-repeat-grey.png");
		this.repeatButton.SetToolTip(TEXT['Editor.Toolbar.Repeat']);
		this.repeatButton.onClick.Suscribe(this.OnRepeatButtonClick, this);
		
		newDiv = document.createElement("DIV");
		newDiv.className = "toolbarSpacerDiv";
		this.hToolBar.appendChild(newDiv);
		
		this.lineInputButton = new UI.ToolBarButton(this.hToolBar);
		this.lineInputButton.SetImage("images/icon-line-input.png", "images/icon-line-input-grey.png");
		this.lineInputButton.SetToolTip(TEXT['Editor.Toolbar.SeperatedTextToolTip']);
		this.lineInputButton.SetText(TEXT['Editor.Toolbar.SeperatedText']);
		this.lineInputButton.onClick.Suscribe(this.OnLineInputButtonClick, this);
		
		this.newWordButton = new UI.ToolBarButton(this.hToolBar);
		this.newWordButton.SetImage("images/icon-add.png", "images/icon-add-grey.png");
		this.newWordButton.SetToolTip(TEXT['Editor.Toolbar.AddWord']);
		this.newWordButton.onClick.Suscribe(this.OnNewWordButtonClick, this);
		
		this.insertSymbolButton = new UI.ToolBarButton(this.hToolBar);
		this.insertSymbolButton.SetImage("images/icon-symbol.png", "images/icon-symbol-grey.png");
		this.insertSymbolButton.SetToolTip(TEXT['Editor.Toolbar.InsertSymbol']);
		this.insertSymbolButton.onClick.Suscribe(this.OnInsertSymbolButtonClick, this);
		
		this.deleteSelectionButton = new UI.ToolBarButton(this.hToolBar);
		this.deleteSelectionButton.SetImage("images/icon-delete-16.png", "images/icon-delete-16.png");
		this.deleteSelectionButton.SetToolTip(TEXT['Editor.Toolbar.DeleteWordsToolTip']);
		this.deleteSelectionButton.SetText(TEXT['Editor.Toolbar.DeleteWords']);
		this.deleteSelectionButton.onClick.Suscribe(this.OnDeleteSelectionButtonClick, this);
		
		newDiv = document.createElement("DIV");
		newDiv.className = "toolbarSpacerDiv";
		this.hToolBar.appendChild(newDiv);
		
		this.propertiesButton = new UI.ToolBarButton(this.hToolBar);
		this.propertiesButton.SetImage("images/icon-properties.png", "images/icon-properties-grey.png");
		this.propertiesButton.SetToolTip(TEXT['Editor.Toolbar.WordlistPropertiesToolTip']);
		this.propertiesButton.SetText(TEXT['Editor.Toolbar.WordlistProperties']);
		this.propertiesButton.onClick.Suscribe(this.OnPropertyButtonClick, this);
		
		this.speechSettingsButton = new UI.ToolBarButton(this.hToolBar);
		this.speechSettingsButton.SetImage("images/icon-audio-16.png", "images/icon-audio-grey-16.png");
		this.speechSettingsButton.SetToolTip(TEXT['Editor.Toolbar.SpeechSettingsToolTip']);
		this.speechSettingsButton.SetText(TEXT['Editor.Toolbar.SppechSettings']);
		this.speechSettingsButton.onClick.Suscribe(this.OnSpeechSettingsButtonClick, this);
		
		newDiv = document.createElement("DIV");
		newDiv.className = "toolbarSpacerDiv";
		this.hToolBar.appendChild(newDiv);
		
		this.helpButton = new UI.ToolBarButton(this.hToolBar);
		this.helpButton.SetImage("images/icon-help.png", "images/icon-help-grey.png");
		this.helpButton.SetToolTip(TEXT['Editor.Toolbar.Help']);
		this.helpButton.onClick.Suscribe(this.OnHelpButtonClick, this);
		this.helpButton.Enable();
	}
	
	this.FinalizeInitialization = function Editor$FinalizeInitialization() {
		
		// Check if intitializing
		if(this.bInitializing) {
		
			// Check if all procedures have been finished
			if(!this.bLoadingWordlist) {
				this.SetMode(this.targetMode);
				
				this.RefreshWordTableHeaders();
				this.RefreshTestSettings();
				this.Invalidate();
				this.InvalidateTestDiv();
			}
		}
	}
	
	this.Invalidate = function Editor$Invalidate() {
	
		// Declare variables
		var strStatusText;
		
		switch(this.mode) {
			case "edit":
			
				// Count words
				strStatusText = this.wordList.Count();
				strStatusText += TEXT['Editor.WordCount'];
				this.SetStatusBarDefaultMessage(strStatusText);
				
				// Set titlebar text
				this.SetTitleBarText(this.wordList.strName + TEXT['Editor.Edit']);
				
				break;
			case "test":
			
				// Set titlebar text
				this.SetTitleBarText(this.wordList.strName + TEXT['Editor.Test']);
				
				break;
		}
	}
	
	this.SetTitleBarText = function Editor$SetTitleBarText(text) {
	
		// Replace titlebar text
		this.hTitleBar.replaceChild(document.createTextNode(text), this.hTitleBar.firstChild);
	}
	
	this.RefreshWordTableHeaders = function Editor$RefreshWordTableHeaders() {
	
		// Declare variables
		var hP;
		var strPriLanguage, strSecLanguage;
		
		strPriLanguage = this.wordList.priLanguage;
		strSecLanguage = this.wordList.secLanguage;
		
		this.hWordTablePriLangHeader.replaceChild(document.createTextNode(strPriLanguage), this.hWordTablePriLangHeader.firstChild);
		this.hWordTablePriRemarkHeader.replaceChild(document.createTextNode(TEXT['Editor.Remark'] + " " + strPriLanguage + " " + TEXT['Editor.Optional']), this.hWordTablePriRemarkHeader.firstChild);
		this.hWordTableSecLangHeader.replaceChild(document.createTextNode(strSecLanguage), this.hWordTableSecLangHeader.firstChild);
		this.hWordTableSecRemarkHeader.replaceChild(document.createTextNode(TEXT['Editor.Remark'] + " " + strSecLanguage + " " + TEXT['Editor.Optional']), this.hWordTableSecRemarkHeader.firstChild);
	}
	
	this.OnWordlistLog = function Editor$OnWordlistLog() {
		
		// Enable / disable toolbar buttons
		this.InvalidateEditButtons();
		
		this.Invalidate();
	}
	
	this.InvalidateEditButtons = function Editor$InvalidateEditButtons() {
		
		switch(this.mode) {
			case "edit":
				if(this.wordList.CanUndo()) {
					this.undoButton.Enable();
					this.undoButton.SetToolTip(TEXT['Editor.Toolbar.UndoDescriber'] + this.wordList.CurrentTransaction().GetDescription());
				} else {
					this.undoButton.Disable();
					this.undoButton.SetToolTip(TEXT['Editor.Toolbar.Undo']);
				}
				
				if(this.wordList.CanRedo()) {
					this.redoButton.Enable();
					this.redoButton.SetToolTip(TEXT['Editor.Toolbar.RedoDescriber'] + this.wordList.GetNextTransaction().GetDescription());
				} else {
					this.redoButton.Disable();
					this.redoButton.SetToolTip(TEXT['Editor.Toolbar.Redo']);
				}
				
				if(this.wordList.CanRepeat()) {
					this.repeatButton.Enable();
					this.repeatButton.SetToolTip(TEXT['Editor.Toolbar.RepeatDescriber'] + this.wordList.CurrentTransaction().GetDescription());
				} else {
					this.repeatButton.Disable();
					this.repeatButton.SetToolTip(TEXT['Editor.Toolbar.Repeat']);
				}
				break;
				
			case "test":
				this.undoButton.Disable();
				this.undoButton.SetToolTip(TEXT['Editor.Toolbar.Undo']);
				this.redoButton.Disable();
				this.redoButton.SetToolTip(TEXT['Editor.Toolbar.Redo']);
				this.repeatButton.Disable();
				this.repeatButton.SetToolTip(TEXT['Editor.Toolbar.Repeat']);
				break;
			
			case "testresult":
				this.undoButton.Disable();
				this.undoButton.SetToolTip(TEXT['Editor.Toolbar.Undo']);
				this.redoButton.Disable();
				this.redoButton.SetToolTip(TEXT['Editor.Toolbar.Redo']);
				this.repeatButton.Disable();
				this.repeatButton.SetToolTip(TEXT['Editor.Toolbar.Repeat']);
				break;
		}
	}
	
	this.OnUndoButtonClick = function Editor$OnUndoButtonClick() {
	
		// Declare variables
		var transaction;
		var hRow;
		
		// Check if undoing is really available
		if(this.wordList.CanUndo()) {
			transaction = this.wordList.Undo();
			
			switch(transaction.transactionType) {
				case "new":
					
					// Search in reverse because most words to be removed will be the newest ones (at the end of the list)
					for(i = this.hWordTable.rows.length - 1; i >= 0; i--) {
						hRow = this.hWordTable.rows[i];
						if(hRow.wordIndex == transaction.wordIndex)
							this.hWordTable.deleteRow(i);
					}
					
					// Update lastRow pointer
					this.hLastRow = this.hWordTable.rows[this.hWordTable.rows.length - 1];
					
					break;
				case "edit":
				
					// Search in reverse because most words to be removed will be the newest ones (at the end of the list)
					for(i = this.hWordTable.rows.length - 1; i >= 0; i--) {
						hRow = this.hWordTable.rows[i];
						if(hRow.wordIndex == transaction.wordIndex)
							break;
					}
					
					switch(transaction.columnIndex) {
						case 1:
							hRow.primaryTranslationInput.value = transaction.oldValue;
							break;
						case 2:
							hRow.secondaryTranslationInput.value = transaction.oldValue;
							break;
						case 3:
							hRow.primaryRemarkInput.value = transaction.oldValue;
							break;
						case 4:
							hRow.secondaryRemarkInput.value = transaction.oldValue;
							break;
					}
					
					break;
				case "delete":
				
					// Declare variables
					var bAdded = false;
				
					// if the word table is empty, add the word as the first word (length == 1 (header))
					if(this.hWordTable.rows.length == 1) {
						
						this.CreateWordTableRow(this.hWordTable, transaction.wordIndex, 1);
					} else {
					
						// Search the insertion point in the word table
						// i = 1 (skip table header)
						
						for(i = 1; i < this.hWordTable.rows.length; i++) {
							hRow = this.hWordTable.rows[i];
							if(hRow.wordIndex == transaction.wordIndex) {
							
								// Insert word at this position
								this.CreateWordTableRow(this.hWordTable, transaction.wordIndex, i);
								bAdded = true;
								break;
							}
						}
						
						// Check if word has been added
						if(!bAdded) {
							this.CreateWordTableRow(this.hWordTable, transaction.wordIndex, -1);
						}
						
						// Update word indexes of following table rows
						for(i++; i < this.hWordTable.rows.length; i++) {
							hRow = this.hWordTable.rows[i];
							hRow.wordIndex++;
						}
					}
					
					break;
			}
		}
	}
	
	this.OnRedoButtonClick = function Editor$OnRedoButtonClick() {
	
		// Declare variables
		var transaction;
		var hRow;
		var iIndex;
		
		// Check if redoing is really available
		if(this.wordList.CanRedo()) {
			transaction = this.wordList.Redo();
			
			switch(transaction.transactionType) {
				case "new":
				
					// Search in reverse because most words to be added will probably be the newest ones (at the end of the list)
					for(i = this.hWordTable.rows.length - 1; i >= 0; i--) {
						hRow = this.hWordTable.rows[i];
						if(hRow.wordIndex > transaction.wordIndex)
							continue;
						if(hRow.wordIndex < transaction.wordIndex)
							break;
					}
					iIndex = i + 1;
					
					// Index may not be lower than 1 (this would case incorrect placement of the row)
					if(iIndex < 1)
						iIndex = 1;
					
					// Create the new row
					this.CreateWordTableRow(this.hWordTable, transaction.wordIndex, iIndex);
					
					// Update lastRow pointer
					this.hLastRow = this.hWordTable.rows[this.hWordTable.rows.length - 1];
					
					break;
				case "edit":
				
					// Search in reverse because most words to be removed will be the newest ones (at the end of the list)
					for(i = this.hWordTable.rows.length - 1; i >= 0; i--) {
						hRow = this.hWordTable.rows[i];
						if(hRow.wordIndex == transaction.wordIndex)
							break;
					}
					
					switch(transaction.columnIndex) {
						case 1:
							hRow.primaryTranslationInput.value = transaction.newValue;
							break;
						case 2:
							hRow.secondaryTranslationInput.value = transaction.newValue;
							break;
						case 3:
							hRow.primaryRemarkInput.value = transaction.newValue;
							break;
						case 4:
							hRow.secondaryRemarkInput.value = transaction.newValue;
							break;
					}
					
					break;
				case "delete":
				
					// i = 1 (skip table header)
					for(i = 1; i < this.hWordTable.rows.length; i++) {
						hRow = this.hWordTable.rows[i];
						if(hRow.wordIndex == transaction.wordIndex) {
							
							// Delete the found row
							this.hWordTable.deleteRow(i);
							break;
						}
					}
					
					// Update the word indexes of the following table
					for(i; i < this.hWordTable.rows.length; i++) {
						hRow = this.hWordTable.rows[i];
						hRow.wordIndex--;
					}
					
					break;
			}
		}
	}
	
	this.OnRepeatButtonClick = function Editor$OnRepeatButtonClick() {
	
		// Declare variables
		var transaction;
		var hRow;
		var iIndex;
		
		// Check if repeating is really available
		if(this.wordList.CanRepeat()) {
			transaction = this.wordList.Repeat();
			
			switch(transaction.transactionType) {
				case "new":
					
					// Create the new row
					this.CreateWordTableRow(this.hWordTable, this.wordList.iLastIndex, -1);
					
					// Update lastRow pointer
					this.hLastRow = this.hWordTable.rows[this.hWordTable.rows.length - 1];
					
					break;
			}
		}
	}
	
	this.OnLineInputButtonClick = function Editor$OnLineInputButtonClick() {
	
		window.core.ShowDialog("dialog.php?page=textinput", [], 820, 300);
	}
	
	this.LineInputCallback = function Editor$LineInputCallback(strInput, cSeperator, bClearList) {
		
		// Declare variables
		var arrLines, arrPieces;
		var strLine, strWord, strRemark;
		var iWordIndex, firstIndex, lastIndex;
		
		// Clear word table and word list
		this.ClearWordTable();
		if(bClearList)
			this.wordList.Clear();
		
		// Split input
		arrLines = strInput.split("\n");
		
		for(var i in arrLines) {
		
			// Split line
			strLine = arrLines[i].trim();
			arrPieces = strLine.split(cSeperator);
			
			if(arrPieces.length >= 2) {
			
				// Create new word
				iWordIndex = this.wordList.AppendNewWord();
				
				// Check if remark is present in primary translation
				strWord = arrPieces[0];
				strRemark = "";
				firstIndex = -1;
				lastIndex = -1;
				firstIndex = strWord.indexOf("{");
				lastIndex = strWord.indexOf("}", firstIndex);
				if(firstIndex > 0 && lastIndex > 0) {
					strRemark = strWord.substr(firstIndex + 1, (lastIndex - firstIndex) - 1);
					strRemark = strRemark.trim();
					strWord = strWord.substr(0, firstIndex);
				}
				strWord = strWord.trim();
				
				// Store values
				this.wordList.SetValue(iWordIndex, 1, strWord);
				this.wordList.SetValue(iWordIndex, 3, strRemark);
				
				// Check if remark is present in secondary translation
				strWord = arrPieces[1];
				strRemark = "";
				firstIndex = -1;
				lastIndex = -1;
				firstIndex = strWord.indexOf("{");
				lastIndex = strWord.indexOf("}", firstIndex);
				if(firstIndex > 0 && lastIndex > 0) {
					strRemark = strWord.substr(firstIndex + 1, (lastIndex - firstIndex) - 1);
					strRemark = strRemark.trim();
					strWord = strWord.substr(0, firstIndex);
				}
				strWord = strWord.trim();
				
				// Store values
				this.wordList.SetValue(iWordIndex, 2, strWord);
				this.wordList.SetValue(iWordIndex, 4, strRemark);
			}
		}
		
		this.wordList.AppendNewWord();
		this.CreateWordTableFromWordlist();
		this.Invalidate();
	}
	
	this.OnSpeechSettingsButtonClick = function Editor$OnSpeechSettingsButtonClick() {
		
		core.ShowDialog("dialog.php?page=speechsettings", [], 370, 500);
	}
	
	this.OnNewWordButtonClick = function Editor$OnNewWordButtonClick() {
	
		// Append new word
		this.CreateNewWordTableRow(this.hWordTable);
	}
	
	this.OnDeleteSelectionButtonClick = function Editor$OnDeleteSelectionButtonClick() {
	
		// Declare variables
		var arrWordsId, arrRowIndexes;
		var hWordTable, hRow;
		var iWordIndex, iRowIndex;
		var hCell;
		
		arrWordsId		= new Array();
		arrRowIndexes	= new Array();
		
		// Catalog wordId's and table indexes of words to be deleted
		// i = 1 (skip table header)
		hWordTable = this.hWordTable;
		for(i = 1; i < hWordTable.rows.length; i++) {
			hRow = hWordTable.rows[i];
			
			if(hRow.rowSelectInput.checked) {
				arrWordsId.push(hRow.wordIndex);
				arrRowIndexes.push(i);
			}
		}
		
		// Delete words and word table rows
		while(arrWordsId.length > 0) {
			iWordIndex = arrWordsId.pop();
			iRowIndex = arrRowIndexes.pop();
			
			this.wordList.RemoveWordAt(iWordIndex);
			this.hWordTable.deleteRow(iRowIndex);
			
			// Update word indexes on table rows
			for(; iRowIndex < hWordTable.rows.length; iRowIndex++) {
				if (iWordIndex > 0) {
					hWordTable.rows[iRowIndex].wordIndex--;
				}
				
				for(i = 1; i < hWordTable.rows[iRowIndex].cells.length; i++) {
					hCell = hWordTable.rows[iRowIndex].cells[i];
					hCell.firstChild.wordIndex--;
				}
			}
		}
		
		this.Invalidate();
	}
	
	this.OnInsertSymbolButtonClick = function Editor$OnInsertSymbolButtonClick(oEvent) {
	
		// Declare variables
		var hSymbolPicker, oEvent;
		
		hSymbolPicker = this.symbolPicker;
		
		// Show the symbol picker
		hSymbolPicker.ShowDialog(oEvent.clientX + document.documentElement.scrollLeft, oEvent.clientY + document.documentElement.scrollTop);
	}
	
	this.OnInputClick = function Editor$OnInputClick(e) {
	
		// Declare variables
		var srcClass, oEvent;
		
		srcClass = this.owningClass;
		
		if(window.event) {
		
			// Windows IE and DOM level 2
			// Bug: using window.event seems to slowdown event handling in IE. Perhaps IE takes a lot of time setting the window.event object.
			oEvent = window.event;
		} else {
		
			// Firefox
			oEvent = e;
		}
		
		// Toggle character picker visibility
		if(!srcClass.symbolPicker.bVisible && oEvent.button == 2) {
			this.hActiveInput = this;
			srcClass.symbolPicker.ShowDialog(oEvent.clientX + document.documentElement.scrollLeft, oEvent.clientY + document.documentElement.scrollTop - 85);
		} else if(srcClass.symbolPicker.bVisible && oEvent.button == 2 && this.hActiveInput != this) {
			this.hActiveInput = this;
			srcClass.symbolPicker.ShowDialog(oEvent.clientX + document.documentElement.scrollLeft, oEvent.clientY + document.documentElement.scrollTop - 85);
		} else if(srcClass.symbolPicker.bVisible) {
			srcClass.symbolPicker.CloseDialog();
		}
		
		return false;
	}
	
	this.SymbolPickerCallback = function Editor$SymbolPickerCallback(text) {
	
		if(this.CallbackClass.hActiveInput == null || this.CallbackClass.hActiveInput == undefined || !this.CallbackClass.hActiveInput)
			return;
		
		// Declare variables
		var hSelection;
		var iSelectionStart, iSelectionEnd;
		var strSelection;
		
		// Suspend logging
		this.CallbackClass.wordList.SuspendLogging();
		
		// Append the chosen character to the current selection in the text area
		try {
			
			this.CallbackClass.hActiveInput.focus();
			//if(document.selection) {
			
				// IE
			//	this.CallbackClass.hActiveInput.focus();
			//	hSelection = document.selection.createRange();
			//	hSelection.text = text;
			//} else 
			if(this.CallbackClass.hActiveInput.selectionStart || this.CallbackClass.hActiveInput.selectionStart == '0') {
				
				// Firefox
				iSelectionStart = this.CallbackClass.hActiveInput.selectionStart;
				iSelectionEnd = this.CallbackClass.hActiveInput.selectionEnd;
				this.CallbackClass.hActiveInput.value = this.CallbackClass.hActiveInput.value.substr(0, iSelectionStart) + text + this.CallbackClass.hActiveInput.value.substr(iSelectionEnd, this.CallbackClass.hActiveInput.value.length);
			} else {
			
				// Other browsers
				this.CallbackClass.hActiveInput.value += text;
			}
			
			this.CallbackClass.hActiveInput.focus();
		}
		catch(ex) {
			//alert(ex);
		}
		
		// Resume logging
		this.CallbackClass.wordList.ResumeLogging();
		
		// Commit the next textbox value to the wordlist
		if(this.mode == "edit")
			this.CallbackClass.wordList.SetValue(this.CallbackClass.hActiveInput.hRow.wordIndex, this.CallbackClass.hActiveInput.columnIndex, this.CallbackClass.hActiveInput.value);
	}
	
	this.OnOpenButtonClick = function Editor$OnOpenButtonClick() {
		
		window.core.ShowDialog("dialog.php?page=openwordlist", [], 400, 300);
	}
	
	this.OnSaveButtonClick = function Editor$OnSaveButtonClick() {
		
		window.core.ShowDialog("dialog.php?page=savewordlist", [], 400, 250);
	}
	
	this.OnPropertyButtonClick = function Editor$OnPropertyButtonClick() {
		
		window.core.ShowDialog("dialog.php?page=wordlistproperties", [], 420, 350);
	}
	
	this.PropertyCallback = function Editor$PropertyCallback() {
		
		this.RefreshWordTableHeaders();
		this.RefreshTestSettings();
		this.Invalidate();
	}
	
	this.OnEditModeButtonClick = function Editor$OnEditModeButtonClick() {
	
		this.owningClass.SetMode("edit");
		
		this.owningClass.RefreshWordTableHeaders();
		this.owningClass.Invalidate();
	}
	
	this.OnTestModeButtonClick = function Editor$OnTestModeButtonClick() {
	
		this.owningClass.SetMode("test");
		
		this.owningClass.Invalidate();
	}
	
	this.RefreshTestSettings = function Editor$RefreshTestSettings() {
	
		// Declare variables
		var strPriLanguage, strSecLanguage;
		
		// Clear the question style selectbox
		
		strPriLanguage = this.wordList.priLanguage;
		strSecLanguage = this.wordList.secLanguage;
		
	}
	
	this.StartNewTest = function Editor$StartNewTest() {
	
		// Declare variables
		var bValid;
		
		// Make sure were in the corect mode
		this.ShowDiv("test");
	
		// Clear log table
		this.ClearQuestionLogTable();
		
		// Check if wordlist is not empty or doesn't contain any valid words
		bValid = false;
		if(this.wordList.Count() > 0) {
			for(i = 0; i < this.wordList.Count(); i++) {
			
				// Check if word is valid
				if(this.wordList.GetValue(i, 1) != "" && this.wordList.GetValue(i, 2) != "") {
					bValid = true;
					break;
				}	
			}
		}
		
		// Show error message is wordlist is invalid
		if(!bValid) {
			alert(TEXT['Editor.CannotStartTestListInvalid']);
			return false;
		}
		
		// Clear count values
		this.testQuestionCount = 0;
		this.testErrorCount = 0;
		
		// Attempt to solve languages for text-to-speech
		this.oPrimaryVoice = Speech.GetVoice(this.wordList.priLanguage);
		this.oSecondaryVoice = Speech.GetVoice(this.wordList.secLanguage);
	
		// Create timer
		this.timer = setInterval("window.editor.OnTimerTick()", 1000);
		this.testStartTime = new Date();
	
		this.bTestCancelled = false;
		this.learningEngine.StartNewTest();
		this.SetTestStatistics("0:00", "0/0 " + TEXT['Editor.Correct'], "");
		this.InvalidateTestDiv();
		
		this.PopNextTestQuestion();
		
		// Notify server this wordlist is being tested
		this.NotifyServerWordlistTest();
	}
	
	this.StopTest = function Editor$StopTest() {
	
		this.learningEngine.StopTest();
		
		// Show score form
		this.FinalizeTest();
	}
	
	this.OnTimerTick = function Editor$OnTimerTick() {
	
		// Declare variables
		var currentDate, elapsedTime;
		var strTime, strScore;
		var iScore, iCorrectAnswers
		
		// Calculate elapsed time
		currentDate = new Date();
		elapsedTime = new Date();
		elapsedTime.setTime(currentDate.getTime() - this.testStartTime.getTime())
		
		// Format elapsed time
		//if(elapsedTime.getHours() > 0)
		//	strTime = elapsedTime.getHours() + ":";
		strTime = elapsedTime.getMinutes() + ":";
		if(elapsedTime.getSeconds() < 10) {
			strTime += "0" + elapsedTime.getSeconds();
		} else {
			strTime += elapsedTime.getSeconds();
		}
		
		// Format score
		iCorrectAnswers = this.learningEngine.iQuestionCount - this.learningEngine.iErrorCount;
		iScore = iCorrectAnswers / this.learningEngine.iQuestionCount;
		if(isNaN(iScore)) {
			strScore = "?";
			iScore = "?";
		} else {
			strScore = Math.round(iScore * 10) + " (" + Math.round(iScore * 100) + "% Goed)";
		}
		
		this.SetTestStatistics(strTime, strScore, iScore);
	}
	
	this.AppendHistoryRow = function Editor$AppendHistoryRow(strTime, strQuestion, strUserAnswer, strCorrectAnswer, strScore, bCorrect) {
	
		// Declare variables
		var newDiv, newTable, newP, newRow, newCell, strStyle;
		
		if(bCorrect) {
			strStyle = "testHistoryTableCell";
		} else {
			strStyle = "testHistoryTableCellFault";
		}
		
		newRow = this.hTestHistroyTable.insertRow(0);
		newCell = newRow.insertCell(-1);
		newCell.className = strStyle;
		newCell.width = "75";
		newP = document.createElement("P");
		newP.appendChild(document.createTextNode(strTime));
		newCell.appendChild(newP);

		newCell = newRow.insertCell(-1);
		newCell.className = strStyle;
		newCell.width = "225";
		newP = document.createElement("P");
		newP.appendChild(document.createTextNode(strQuestion));
		newCell.appendChild(newP);

		newCell = newRow.insertCell(-1);
		newCell.className = strStyle;
		newCell.width = "225";
		newP = document.createElement("P");
		newP.appendChild(document.createTextNode(strUserAnswer));
		newCell.appendChild(newP);
		
		newCell = newRow.insertCell(-1);
		newCell.className = strStyle;
		newCell.width = "225";
		newP = document.createElement("P");
		newP.appendChild(document.createTextNode(strCorrectAnswer));
		newCell.appendChild(newP);

		newCell = newRow.insertCell(-1);
		newCell.className = strStyle;
		newCell.width = "142";
		newP = document.createElement("P");
		newP.appendChild(document.createTextNode(strScore));
		newCell.appendChild(newP);
	}
	
	this.OnNewTestButtonClick = function Editor$OnNewTestButtonClick() {
	
		// Show new test dialog
		window.core.ShowDialog("dialog.php?page=startnewtest", [], 420, 350);
	}
	
	this.OnRestartTestButtonClick = function Editor$OnRestartTestButtonClick() {
	
		// Show restart confirmation dialog
		window.core.ShowDialog("dialog.php?page=restarttest", [], 420, 100);

	}
	
	this.OnRestartFinishedTestButtonClick = function Editor$OnRestartFinishedTestButtonClick() {
	
		// Restart the test
		this.StartNewTest();
	}
	
	this.OnTestProgressButtonClick = function Editor$OnTestProgressButtonClick() {
	
		window.core.ShowDialog("dialog.php?page=wordlistprogress&wordlist=" + this.owningClass.wordList.wordlistId, [], 908, 450);
	}
	
	this.OnStopTestButtonClick = function Editor$OnStopTestButtonClick() {
	
		// Stop the test
		this.owningClass.bTestCancelled = true;
		this.owningClass.StopTest();
	}
	
	this.ToggleTestHistoryTableDiv = function Editor$ToggleTestHistoryTableDiv() {
	
		if(this.checked) {
			this.owningClass.hTestHistroyTableDiv.className = "testHistoryTableDivHidden";
		} else {
			this.owningClass.hTestHistroyTableDiv.className = "testHistoryTableDiv";
		}
		
		Sys.Settings.Editor.HideLog = this.checked;
	}
	
	this.OnSelectAllCheckboxChange = function Editor$OnSelectAllCheckboxChange() {
	
		// Declare variables
		var bChecked;
		var hRow;
		
		// Import checkbox value
		bChecked = this.checked;
		
		// Set all checkbox values
		// i = 1 (skip header)
		for(i = 1; i < this.owningClass.hWordTable.rows.length; i++) {
			hRow = this.owningClass.hWordTable.rows[i];
			hRow.rowSelectInput.checked = bChecked;
		}
	}
	
	this.InvalidateTestDiv = function Editor$InvalidateTestDiv() {
	
		if(!this.learningEngine.bRunning && !this.learningEngine.bFinished) {
			this.startNewTestButton.disabled = false;
			this.restartTestButton.disabled = true;
			this.stopTestButton.disabled = true;
			this.testProgressButton.disabled = true;
		} else if(!this.learningEngine.bRunning && this.learningEngine.bFinished) {
			this.startNewTestButton.disabled = false;
			this.restartTestButton.disabled = false;
			this.stopTestButton.disabled = true;
			this.testProgressButton.disabled = true;
		} else if(this.learningEngine.bRunning) {
			this.startNewTestButton.disabled = false;
			this.restartTestButton.disabled = false;
			this.stopTestButton.disabled = false;
			this.testProgressButton.disabled = true;
		}
	}
	
	this.SetTestStatistics = function Editor$SetTestStatistics(strTime, strScore, iScore) {
	
		// Declare variables
		var newP, newB;
		
		// Clear the test stats div
		while(this.hTestStatsDivLeft.childNodes.length > 0)
			this.hTestStatsDivLeft.removeChild(this.hTestStatsDivLeft.firstChild)
		
		// Title
		newP = document.createElement("P");
		newB = document.createElement("B");
		newP.appendChild(newB);
		newB.appendChild(document.createTextNode(TEXT['Editor.TestStatistics']));
		this.hTestStatsDivLeft.appendChild(newP);
		
		// Running time
		if(strTime != "" && strTime != undefined) {
			newP = document.createElement("P");
			newB = document.createElement("B");
			newP.appendChild(newB);
			newB.appendChild(document.createTextNode(TEXT['Editor.Duration']));
			newP.appendChild(document.createTextNode(strTime));
			this.hTestStatsDivLeft.appendChild(newP);
		}
		
		// Score
		if(strScore != "" && strScore != undefined) {
			newP = document.createElement("P");
			newB = document.createElement("B");
			newP.appendChild(newB);
			newB.appendChild(document.createTextNode(TEXT['Editor.Score']));
			newP.appendChild(document.createTextNode(strScore));
			this.hTestStatsDivLeft.appendChild(newP);
		}
		
		// Large score
		if(this.learningEngine.bRunning && !isNaN(iScore)) {
			this.hTestStatsDivLargeScore.innerHTML = Math.round(iScore * 10);
		} else if(this.learningEngine.bRunning && isNaN(iScore)) {
			this.hTestStatsDivLargeScore.innerHTML = "?";
		} else {
			this.hTestStatsDivLargeScore.innerHTML = "&nbsp;";
		}
		
		// Progress
		if(this.hTestStatsDivProgressBar == null && this.learningEngine.bRunning) {
			this.hTestStatsDivProgressBar = new UI.PlanningProgressDiv(this.hTestStatsDivRight, 1);
		}
		if(this.learningEngine.bRunning) {
			this.hTestStatsDivProgressBar.SetProgress(this.CalcTestProgress());
		}
	}
	
	this.ClearQuestionLogTable = function Editor$ClearQuestionLogTable() {
		
		while(this.hTestHistroyTable.rows.length > 0) {
			this.hTestHistroyTable.deleteRow(0);
		}
	}
	
	this.PopNextTestQuestion = function Editor$PopNextTestQuestion() {
	
		// Declare variables
		
		if(this.learningEngine.TestIsFinished()) {
			this.FinalizeTest();
			return;
		}
		
		if(!this.learningEngine.NextQuestion()) {
		
			alert(TEXT['Editor.NextQuestionError']);
			return;
		}
		
		switch(this.learningEngine.testStyle) {
			case TestStyleEnum.OPEN_QUESTION:
				this.TestInputShowOpenQuestion();
				break;
			case TestStyleEnum.MULTIPLE_CHOICE_2:
			case TestStyleEnum.MULTIPLE_CHOICE_3:
			case TestStyleEnum.MULTIPLE_CHOICE_4:
			case TestStyleEnum.MULTIPLE_CHOICE_5:
			case TestStyleEnum.MULTIPLE_CHOICE_6:
				this.TestInputShowMultipleChoiceQuestion();
				break;
			case TestStyleEnum.THOUGHT_EXERCICE:
				this.TextInputShowThoughtExercice();
				break;
			case TestStyleEnum.WRITING_EXERCICE:
				
				break;
			
		}
	}
	
	this.FinalizeTest = function Editor$FinalizeTest() {
	
		// Declare variables
		var newDiv, newP;
		var currentDate, elapsedTime;
		var strTime, strScore, strScoreDetails;
		var iScore, iCorrectAnswers
		
		// Freeze test timer
		clearInterval(this.timer);
		
		// Stop the learning engine
		this.learningEngine.StopTest();
		
		// Reset the test div
		this.hTestAnswerInput = null;
		this.InitializeTestDiv();
		
		// Show the test result div
		this.UpdateTestResultDiv();
		this.ShowDiv("testresult");
		
		// Submit planning results to server
		this.NotifyServerPlanningProgress();
		
		// Invalidate the test div in order to update the control buttons
		this.InvalidateTestDiv();
		
		// Destroy the test progressbar
		try {
			this.hTestStatsDivProgressBar.Dispose();
			this.hTestStatsDivProgressBar = null;
		} catch(ex) {};
		
		// Simulate a timer tick in order to be sure the satistics panel is fully up to data
		this.OnTimerTick();
	}
	
	this.TestInputShowOpenQuestion = function Editor$TestInputShowOpenQuestion() {
	
		// Declare variables
		var newP, newInput, newButton;
		var strPriLanguage, strSecLanguage;
		var oVoice;
		
		// Clear hTestInputDiv
		while(this.hTestInputDiv.childNodes.length > 0) {
			this.hTestInputDiv.removeChild(this.hTestInputDiv.childNodes[0]);
		}
		
		// Get language strings
		if(this.learningEngine.currentQuestionDirection == QuestionDirectionEnum.PRIMARY_SECONDARY) {
			strPriLanguage = this.wordList.priLanguage;
			strSecLanguage = this.wordList.secLanguage;
			oVoice = this.oPrimaryVoice;
		} else if(this.learningEngine.currentQuestionDirection == QuestionDirectionEnum.SECONDARY_PRIMARY) {
			strSecLanguage = this.wordList.priLanguage;
			strPriLanguage = this.wordList.secLanguage;
			oVoice = this.oSecondaryVoice;
		}
		
		// Question label language
		newP = document.createElement("P");
		newP.className = "questionLabelLanguage";
		if(this.learningEngine.strCurrentRemark.trim() != "") {
			newP.appendChild(document.createTextNode(strPriLanguage + " - " + this.learningEngine.strCurrentRemark.trim()));
		} else {
			newP.appendChild(document.createTextNode(strPriLanguage));
		}
		this.hTestInputDiv.appendChild(newP);
		
		// Question label
		newP = document.createElement("P");
		newP.className = "questionLabel";
		newP.appendChild(document.createTextNode(this.learningEngine.strCurrentQuestion));
		this.hTestInputDiv.appendChild(newP);
		
		// Answer language
		newP = document.createElement("P");
		newP.className = "questionLabelLanguage";
		newP.appendChild(document.createTextNode(strSecLanguage));
		this.hTestInputDiv.appendChild(newP);
		
		// Answer input
		newP = document.createElement("P");
		this.hTestAnswerInput = document.createElement("INPUT");
		this.hTestAnswerInput.className = "questionInput";
		this.hTestAnswerInput.owningClass = this;
		this.hTestAnswerInput.onfocus = this.OnInputFocus;
		this.hTestAnswerInput.onblur = this.OnInputBlur;
		this.hTestAnswerInput.onmouseup = this.OnInputClick;
		this.hTestAnswerInput.onkeyup = this.OnAnswerInputKeyUp;
		this.hTestAnswerInput.id = "OpenAnsweInput";
		newP.appendChild(this.hTestAnswerInput);
		this.hTestInputDiv.appendChild(newP);
		
		// Submit answer button
		newButton = document.createElement("INPUT");
		newButton.className = "answerSubmitButton";
		newButton.type = "button";
		newButton.value = TEXT['Editor.AnswerButton'];
		newButton.onclick = this.OnAnswerSubmitButtonClick;
		newButton.owningClass = this;
		newP.appendChild(newButton);
		
		this.hTestAnswerInput.focus();
		this.hTestAnswerInput.focus();
		
		// Speak text
		if(this.learningEngine.bEnableSpeech && this.speech.bSpeechOutput && this.oVoice !== null) {
			this.speech.SetVoice(oVoice);
			this.speech.Speak(this.learningEngine.strCurrentQuestion);
		}
	}
	
	this.TestInputShowMultipleChoiceQuestion = function Editor$TestInputShowMultipleChoiceQuestion() {
	
		// Declare variables
		var newP, newInput, newButton, newAnswerDiv, newImg;
		var strPriLanguage, strSecLanguage, strChoice;
		var questionContainer, answerContainer;
		
		// Clear hTestInputDiv
		while(this.hTestInputDiv.childNodes.length > 0) {
			this.hTestInputDiv.removeChild(this.hTestInputDiv.childNodes[0]);
		}
		
		// Get language strings
		if(this.learningEngine.currentQuestionDirection == QuestionDirectionEnum.PRIMARY_SECONDARY) {
			strPriLanguage = this.wordList.priLanguage;
			strSecLanguage = this.wordList.secLanguage;
		} else if(this.learningEngine.currentQuestionDirection == QuestionDirectionEnum.SECONDARY_PRIMARY) {
			strSecLanguage = this.wordList.priLanguage;
			strPriLanguage = this.wordList.secLanguage;
		}
		
		// Create the question container
			questionContainer = document.createElement("DIV");
			questionContainer.className = "multipleChoiceQuestionContainer";
			this.hTestInputDiv.appendChild(questionContainer);
			
			// Question label language
			newP = document.createElement("P");
			newP.className = "questionLabelLanguage";
			if(this.learningEngine.strCurrentRemark.trim() != "") {
				newP.appendChild(document.createTextNode(strPriLanguage + " - " + this.learningEngine.strCurrentRemark.trim()));
			} else {
				newP.appendChild(document.createTextNode(strPriLanguage));
			}
			questionContainer.appendChild(newP);
			
			// Question label
			newP = document.createElement("P");
			newP.className = "questionLabel";
			newP.appendChild(document.createTextNode(this.learningEngine.strCurrentQuestion));
			questionContainer.appendChild(newP);
		
		// Create answer container
			answerContainer = document.createElement("DIV");
			answerContainer.className = "multipleChoiceAnswerContainer";
			this.hTestInputDiv.appendChild(answerContainer);
			
			// Answer language
			newP = document.createElement("P");
			newP.className = "questionLabelLanguage";
			newP.appendChild(document.createTextNode(strSecLanguage));
			answerContainer.appendChild(newP);
			
			// Create answers
			this.arrMultipleChoiceAnswers = new Array();
			for(i = 0; i < this.learningEngine.strCurrentChoices.length ; i++) {
			
				strChoice = this.learningEngine.strCurrentChoices[i];
				
				newAnswerDiv = document.createElement("DIV");
				newAnswerDiv.className = "multipleChoiceAnswerDiv";
				newAnswerDiv.owningClass = this;
				newAnswerDiv.onmouseover = this.OnMultipleChoiceAnswerMouseOver;
				newAnswerDiv.onmouseout = this.OnMultipleChoiceAnswerMouseOut;
				newAnswerDiv.onclick = this.OnMultipleChoiceAnswerClick;
				newAnswerDiv.strAnswer = strChoice;
				answerContainer.appendChild(newAnswerDiv);
				this.arrMultipleChoiceAnswers.push(newAnswerDiv);
				
				newImg = document.createElement("IMG");
				newImg.src = "images/icon-gofoward.png";
				newAnswerDiv.appendChild(newImg);
				
				newP = document.createElement("P");
				newP.appendChild(document.createTextNode(strChoice));
				newAnswerDiv.appendChild(newP);
			}
	}
	
	this.OnMultipleChoiceAnswerMouseOver = function Editor$OnMultipleChoiceAnswerMouseOver(e) {
		this.className = "multipleChoiceAnswerDivHover";
	}
	
	this.OnMultipleChoiceAnswerMouseOut = function Editor$OnMultipleChoiceAnswerMouseOut(e) {
		this.className = "multipleChoiceAnswerDiv";
	}
	
	this.OnAnswerInputKeyUp = function Editor$OnAnswerInputKeyUp(e) {
	
		// Declare variables
		var srcClass, oEvent;
		
		srcClass = this.owningClass;
		
		if(window.event) {
		
			// Windows IE and DOM level 2
			// Bug: using window.event seems to slowdown event handling in IE. Perhaps IE takes a lot of time setting the window.event object.
			oEvent = window.event;
		} else {
		
			// Firefox
			oEvent = e;
		}
		
		if(oEvent.keyCode == 13 || (srcClass.bErrorMode && oEvent.keyCode == 32)) {
			switch(srcClass.learningEngine.testStyle) {
				case TestStyleEnum.OPEN_QUESTION:
					srcClass.CheckOpenAnswer();
					break;
			}
		}
	}
	
	this.OnAnswerSubmitButtonClick = function Editor$OnAnswerInputKeyUp(e) {
	
		// Declare variables
		var srcClass, oEvent;
		
		srcClass = this.owningClass;
		
		if(window.event) {
		
			// Windows IE and DOM level 2
			// Bug: using window.event seems to slowdown event handling in IE. Perhaps IE takes a lot of time setting the window.event object.
			oEvent = window.event;
		} else {
		
			// Firefox
			oEvent = e;
		}
		
		switch(srcClass.learningEngine.testStyle) {
			case TestStyleEnum.OPEN_QUESTION:
				srcClass.CheckOpenAnswer();
				break;
		}
	}
	
	this.CheckOpenAnswer = function Editor$CheckOpenAnswer() {
	
		// Declare variables
		var hInput;
		var currentDate, elapsedTime;
		var strTime, strScore;
		var iScore, iCorrectAnswers;
		var bCorrect;
		
		// Check if system is in 'error mode'
		if(this.bErrorMode) {
			this.bErrorMode = false;
			this.PopNextTestQuestion();
			return;
		}
		
		// Get handles
		hInput = document.getElementById("OpenAnsweInput");
		
		// Check the answer
		bCorrect = this.learningEngine.CheckAnswer(hInput.value);
		
		// Calculate elapsed time
		currentDate = new Date();
		elapsedTime = new Date();
		elapsedTime.setTime(currentDate.getTime() - this.testStartTime.getTime())
		
		// Format elapsed time
		strTime = elapsedTime.getMinutes() + ":";
		if(elapsedTime.getSeconds() < 10) {
			strTime += "0" + elapsedTime.getSeconds();
		} else {
			strTime += elapsedTime.getSeconds();
		}
		
		// Format score
		iCorrectAnswers = this.learningEngine.iQuestionCount - this.learningEngine.iErrorCount;
		iScore = iCorrectAnswers / this.learningEngine.iQuestionCount;
		strScore = Math.round(iScore * 10) + " (" + Math.round(iScore * 100) + "% " + TEXT['Editor.Correct'] + ")";
	
		if(bCorrect) {
			this.AppendHistoryRow(strTime, this.learningEngine.strCurrentQuestion, hInput.value, this.learningEngine.strCurrentKey, strScore, true);
			this.PopNextTestQuestion();
		} else {
			this.AppendHistoryRow(strTime, this.learningEngine.strCurrentQuestion, hInput.value, this.learningEngine.strCurrentKey, strScore, false);
			this.DisplayAnswerError(hInput.value);
		}
		
		
	}
	
	this.DisplayAnswerError = function Editor$DisplayAnswerError(strAnswer) {
	
		// Declare variables
		var newP;
		
		// Switch into 'error mode'
		this.bErrorMode = true;
		
		newP = document.createElement("P");
		newP.className = "answerErrorLabel";
		newP.appendChild(document.createTextNode(TEXT['Editor.IncorrectAnswer']));
		this.hTestInputDiv.appendChild(newP);
		
		newP = document.createElement("P");
		newP.className = "answerError";
		newP.appendChild(document.createTextNode(this.learningEngine.strCurrentKey));
		this.hTestInputDiv.appendChild(newP);
		
		// Disable anwer input
		if(this.hTestAnswerInput != null && this.hTestAnswerInput) {
			this.hTestAnswerInput.readOnly = true;
		}
	}
	
	this.OnMultipleChoiceAnswerClick = function Editor$OnMultipleChoiceAnswerClick(e) {
	
		// Declare variables
		var srcClass, oEvent;
		
		srcClass = this.owningClass;
		
		if(window.event) {
		
			// Windows IE and DOM level 2
			// Bug: using window.event seems to slowdown event handling in IE. Perhaps IE takes a lot of time setting the window.event object.
			oEvent = window.event;
		} else {
		
			// Firefox
			oEvent = e;
		}
		
		// Check the answer
		srcClass.CheckMultipleChoiceAnswer(this.strAnswer, this);
	}
	
	this.CheckMultipleChoiceAnswer = function Editor$CheckMultipleChoiceAnswer(strAnswer, hAnswerDiv) {
		
		// Declare variables
		var currentDate, elapsedTime;
		var strTime, strScore;
		var iScore, iCorrectAnswers;
		var bCorrect;
		
		// Get handles
		hInput = document.getElementById("OpenAnsweInput");
		
		// Check the answer
		bCorrect = this.learningEngine.CheckAnswer(strAnswer);
		
		// Calculate elapsed time
		currentDate = new Date();
		elapsedTime = new Date();
		elapsedTime.setTime(currentDate.getTime() - this.testStartTime.getTime())
		
		// Format elapsed time
		strTime = elapsedTime.getMinutes() + ":";
		if(elapsedTime.getSeconds() < 10) {
			strTime += "0" + elapsedTime.getSeconds();
		} else {
			strTime += elapsedTime.getSeconds();
		}
		
		// Format score
		iCorrectAnswers = this.learningEngine.iQuestionCount - this.learningEngine.iErrorCount;
		iScore = iCorrectAnswers / this.learningEngine.iQuestionCount;
		strScore = Math.round(iScore * 10) + " (" + Math.round(iScore * 100) + "% " + TEXT['Editor.Correct'] + ")";
	
		if(bCorrect) {
			this.AppendHistoryRow(strTime, this.learningEngine.strCurrentQuestion, strAnswer, this.learningEngine.strCurrentKey, strScore, true);
			this.PopNextTestQuestion();
		} else {
			this.AppendHistoryRow(strTime, this.learningEngine.strCurrentQuestion, strAnswer, this.learningEngine.strCurrentKey, strScore, false);
			this.DisplayMultipleChoiceAnswerError(hAnswerDiv);
			this.hMultipleChoiceTestTimeout = setTimeout(this.OnMultipleChoiceAnswerErrorTimeout, 500);
		}
	}
	
	this.DisplayMultipleChoiceAnswerError = function Editor$DisplayMultipleChoiceAnswerError(hGivenAnswerDiv) {
	
		// Declare variables
		var hAnswerDiv;
		
		for(i = 0; i < this.arrMultipleChoiceAnswers.length; i++) {
		
			hAnswerDiv = this.arrMultipleChoiceAnswers[i];
			
			hAnswerDiv.onmouseover = function() {};
			hAnswerDiv.onmouseout = function() {};
			hAnswerDiv.onclick = function() {};
			
			if(hAnswerDiv.strAnswer == this.learningEngine.strCurrentKey) {
				hAnswerDiv.className = "multipleChoiceAnswerDivCorrect";
			} else {
				hAnswerDiv.className = "multipleChoiceAnswerDiv";
			}
		}
		
		// Highlight the given answer
		hGivenAnswerDiv.className = "multipleChoiceAnswerDivFault";
	}
	
	this.OnMultipleChoiceAnswerErrorTimeout = function Editor$OnMultipleChoiceAnswerErrorTimeout() {
		
		// Pop the next question
		// (this = window)
		this.editor.PopNextTestQuestion();
	}
	
	this.OnSaveTestResultsButtonClick = function Editor$OnSaveTestResultsButtonClick() {
	
		this.SaveTestResults();
	}
	
	this.SaveTestResults = function Editor$SaveTestResults() {
	
		// Declare variables
		var strData, strUrl;
		var currentDate;
		var iElapsedTime;
		
		this.saveTestResultsButton.disabled = true;
		this.saveTestResultsButton.value = TEXT['Editor.SaveScoreButtonSaving'];
		
		// Calculate elapsed time
		currentDate = new Date();
		
		// Format elapsed time
		iElapsedTime = (currentDate.getTime() - this.testStartTime.getTime()) / 1000;
		
		// Prepare data
		strData = "questionCount=" + this.learningEngine.iQuestionCount;
		strData += "&faults=" + this.learningEngine.iErrorCount;
		strData += "&questionStyle=" + this.learningEngine.testStyle;
		strData += "&repeatMethod=" + this.learningEngine.repeatMethod;
		strData += "&questionDirection=" + this.learningEngine.questionDirection;
		strData += "&questionSequence=" + this.learningEngine.questionSequence;
		strData += "&checkType=" + this.learningEngine.answerCheckType;
		strData += "&duration=" + Math.round(iElapsedTime);
		if(this.learningEngine.bShowRemarks) {
			strData += "&showRemarks=1";
		} else {
			strData += "&showRemarks=0";
		}
		
		// Prepare url
		strUrl = "xml.php?page=storetestresults&wordlist=" + this.wordList.wordlistId;
		
		// Send wordlist to server for storage
		var _this = this;
		this.resultsAjaxRequest = getXmlHttpRequest();
		this.resultsAjaxRequest.onreadystatechange = function() { _this.SaveTestResultsCallback() };
		this.resultsAjaxRequest.open("POST", strUrl, true);
		this.resultsAjaxRequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
		this.resultsAjaxRequest.send(strData);
	}
	
	this.SaveTestResultsCallback = function Editor$SaveTestResultsCallback() {
	
		if(this.resultsAjaxRequest.readyState == 4) {
			
			// Check results
			this.saveTestResultsButton.value = TEXT['Editor.SaveScoreButtonSaved'];
		}
	}
	
	this.NotifyServerWordlistTest = function Editor$NotifyServerWordlistTest() {
	
		// Declare variables
		var strUrl;
		
		// Only notify if editor is in wordlist mode
		if(this.operationMode != "normal" && this.wordList.wordlistId != "new" && this.wordList.wordlistId > 0)
			return;
		
		// Prepare url
		strUrl = "xml.php?page=notifytest&wordlist=" + this.wordList.wordlistId;
	
		// Notify the server the current wordlist is being tested
		this.notifyTestAjaxRequest = getXmlHttpRequest();
		this.notifyTestAjaxRequest.onreadystatechange = function() { return true; };
		this.notifyTestAjaxRequest.open("GET", strUrl, true);
		this.notifyTestAjaxRequest.send(null);
	}
	
	this.SetStatusBarDefaultMessage = function Editor$NotifyServerWordlistTest(strMessage) {
		
		this.strStatusBarDefaultMessage = strMessage;
		this.UpdateStatusBar();
	}
	
	this.UpdateStatusBar = function Editor$UpdateStatusBar() {
		
		// Clear the statusbar
		while(this.hStatusBar.childNodes.length > 0)
			this.hStatusBar.removeChild(this.hStatusBar.firstChild);
			
		if(this.hStatusBarTimer == null || !this.hStatusBarTimer || this.hStatusBarTimer == undefined) {
		
			// Set the default message
			this.hStatusBar.appendChild(document.createTextNode(this.strStatusBarDefaultMessage));
		} else {
		
			// Set the current message
			this.hStatusBar.appendChild(document.createTextNode(this.strStatusBarCurrentMessage));
		}
	}
	
	this.SetStatusBarMessage = function Editor$SetStatusBarMessage(strMessage, iMilliseconds) {
		
		// Clear the timer
		if(this.hStatusBarTimer != null)
			clearTimeout(this.hStatusBarTimer);
		
		if(iMilliseconds == -1 || iMilliseconds == undefined) {
		
			// Display the new message as the default message
			this.strStatusBarDefaultMessage = strMessage;
			
		} else {
		
			// Display the new message as a temporary message
			this.hStatusBarTimer = setTimeout(this.OnStatusBarTimerTimeout, iMilliseconds);
			this.strStatusBarCurrentMessage = strMessage;
		}
		
		this.UpdateStatusBar();
	}
	
	this.OnStatusBarTimerTimeout = function Editor$OnStatusBarTimerTimeout() {
	
		this.editor.hStatusBarTimer = null;
		this.editor.UpdateStatusBar();
	}
	
	this.OnHelpButtonClick = function Editor$OnHelpButtonClick() {
		
		window.open('help.php?id=23', '_blank', 'toolbar=no, location=yes, resizable=yes, scrollbars=yes, width=900, height=500');
	}
	
	this.targetMode = mode;
	this.Initialize();
}

Editor.prototype.InitializeTestResultDiv = function Editor$InitializeTestResultDiv() {
	
	this.hTestResultDiv = document.createElement("DIV");
	this.hTestResultDiv.className = "editorContentDiv";
	this.hTestResultDiv.style.visibility = "hidden";
	this.hEditorContentParent.appendChild(this.hTestResultDiv);
	
	// Create the test result content div
	this.hTestResultDivContent = document.createElement("DIV");
	this.hTestResultDiv.appendChild(this.hTestResultDivContent);
	
	// Create the test result table
}

Editor.prototype.SetMode = function Editor$SetMode(mode) {
	
	// Check if editmode should change
	if(this.mode == mode)
		return;
		
	this.hActiveInput = null;
	this.insertSymbolButton.Disable();

	switch(mode) {
		case "edit":
		
			// Switch to edit mode
			this.mode = mode;
			
			this.hEditButton.disabled = true;
			this.hTestButton.disabled = false;
			
			this.openButton.Enable();
			this.saveButton.Enable();
			this.lineInputButton.Enable();
			this.newWordButton.Enable();
			this.propertiesButton.Enable();
			this.deleteSelectionButton.Enable();
			
			this.ShowDiv(mode);
				
			break;
		case "test":
		
			// Switch to test mode
			this.mode = mode;
			
			this.hEditButton.disabled = false;
			this.hTestButton.disabled = true;
			
			this.openButton.Enable();
			this.saveButton.Enable();
			this.lineInputButton.Disable();
			this.newWordButton.Disable();
			this.propertiesButton.Disable();
			this.deleteSelectionButton.Disable();
			
			this.ShowDiv(mode);
			
			break;
		case "testresult":
			
			// Switch to test result mode
			this.mode = mode;
			
			this.hEditButton.disabled = false;
			this.hTestButton.disabled = false;
			
			this.openButton.Enable();
			this.saveButton.Enable();
			this.lineInputButton.Disable();
			this.newWordButton.Disable();
			this.propertiesButton.Disable();
			this.deleteSelectionButton.Disable();
			
			this.ShowDiv(mode);
			
			break;
		case "loading":
			
			// Switch to test result mode
			this.mode = mode;
			
			this.hEditButton.disabled = true;
			this.hTestButton.disabled = true;
			
			this.openButton.Disable();
			this.saveButton.Disable();
			this.lineInputButton.Disable();
			this.newWordButton.Disable();
			this.propertiesButton.Disable();
			this.deleteSelectionButton.Disable();
			
			this.ShowDiv(mode);
		
			break;
	}
	
	this.InvalidateEditButtons();
}

Editor.prototype.ShowDiv = function Editor$ShowDiv(div) {
	
	this.hTestDiv.style.visibility = "hidden";
	this.hTestDiv.style.display = "none";
	this.hTestResultDiv.style.visibility = "hidden";
	this.hTestResultDiv.style.display = "none";
	this.hInputDiv.style.visibility = "hidden";
	this.hInputDiv.style.display = "none";
	this.hLoadingDiv.style.visibility = "hidden";
	this.hLoadingDiv.style.display = "none";
	
	switch(div) {
		case "edit":
			this.hInputDiv.style.visibility = "visible";
			this.hInputDiv.style.display = "block";
			break;
		case "test":
			this.hTestDiv.style.visibility = "visible";
			this.hTestDiv.style.display = "block";
			break;
		case "loading":
			this.hLoadingDiv.style.visibility = "visible";
			this.hLoadingDiv.style.display = "block";
			break;
		case "testresult":
			this.hTestResultDiv.style.visibility = "visible";
			this.hTestResultDiv.style.display = "block";
			break;
	}
}

Editor.prototype.OnBeforePageUnload = function Editor$OnBeforePageUnload(e) {
	
	if(!e) var e = window.event;
	
	if(!this.wordList.bChangesSaved)
		e.returnValue = TEXT['Editor.ExitWordlistNoSaved'];
}

Editor.prototype.UpdateTestResultDiv = function Editor$UpdateTestResultDiv() {
	
	// Declare variables
	var newP, newToolbox, newH2, newInput;
	
	// Clear the testresult div
	while(this.hTestResultDivContent.childNodes.length > 0)
		this.hTestResultDivContent.removeChild(this.hTestResultDivContent.firstChild);
	
	// Calculate elapsed time
	currentDate = new Date();
	elapsedTime = new Date();
	elapsedTime.setTime(currentDate.getTime() - this.testStartTime.getTime())
	
	// Format score
	iCorrectAnswers = this.learningEngine.iQuestionCount - this.learningEngine.iErrorCount;
	iScore = iCorrectAnswers / this.learningEngine.iQuestionCount;
	strScore = Math.round(iScore * 10);
	strScoreDetails = iCorrectAnswers + "/" + this.learningEngine.iQuestionCount + " " + TEXT['Editor.Correct'] + " (" + Math.round(iScore * 100) + "%)";
	
	// Format elapsed time
	//if(elapsedTime.getHours() > 0)
	//	strTime = elapsedTime.getHours() + ":";
	strTime = elapsedTime.getMinutes() + ":";
	if(elapsedTime.getSeconds() < 10) {
		strTime += "0" + elapsedTime.getSeconds();
	} else {
		strTime += elapsedTime.getSeconds();
	}
	
	// Create the caption
	newP = document.createElement("P");
	newP.className = "testFinished";
	if(this.bTestCancelled) {
		newP.appendChild(document.createTextNode(TEXT['Editor.TestCancelled']));
	} else {
		newP.appendChild(document.createTextNode(TEXT['Editor.TestFinished']));
	}
	this.hTestResultDivContent.appendChild(newP);
	
	// Create the mark caption
	newP = document.createElement("P");
	newP.className = "finalResult";
	newP.appendChild(document.createTextNode(strScore));
	this.hTestResultDivContent.appendChild(newP);
	
	// Create the score details
	newP = document.createElement("P");
	newP.className = "center";
	newP.appendChild(document.createTextNode(strScoreDetails));
	newP.appendChild(document.createElement("BR"));
	newP.appendChild(document.createElement("BR"));
	this.hTestResultDivContent.appendChild(newP);
	
	// Create result div
	if(this.operationMode == "planninglearnnew" || this.operationMode == "planningprogressiontest") {
		this.hTestResultStatusDiv = document.createElement("DIV");
		this.hTestResultStatusDiv.className = "testResultsDiv";
		this.hTestResultDivContent.appendChild(this.hTestResultStatusDiv);
		
		// Set default text
		newH2 = document.createElement("H2");
		newH2.className = "center";
		newH2.appendChild(document.createTextNode(TEXT['Editor.SavePlanningProgressTitle']));
		this.hTestResultStatusDiv.appendChild(newH2);
		
		newP = document.createElement("P");
		newP.className = "center";
		newP.appendChild(document.createElement("BR"));
		newP.appendChild(document.createTextNode(TEXT['Editor.SavePlanningProgressBusy']));
		this.hTestResultStatusDiv.appendChild(newP);
		
	} else if(this.operationMode == "normal" && this.wordList.wordlistId > 0 && this.bLoggedIn) {
		
		// Ask if user wants to save al the wrong answered words to a new wordlist.
		// Only ask if the test was not a progressive interval test
		if(this.learningEngine.repeatMethod != RepeatMethodEnum.PIT) {
			
			// Create result div
			newToolbox = document.createElement("DIV");
			newToolbox.className = "testResultsDiv";
			this.hTestResultDivContent.appendChild(newToolbox);
			
			newH2 = document.createElement("H2");
			newH2.className = "center";
			newH2.appendChild(document.createTextNode(TEXT['Editor.SaveResultsTitle']));
			newToolbox.appendChild(newH2);
			
			newP = document.createElement("P");
			newP.className = "center";
			newP.appendChild(document.createElement("BR"));
			
			this.saveTestResultsButton = document.createElement("INPUT");
			this.saveTestResultsButton.type = "button";
			this.saveTestResultsButton.className = "mediumButton";
			this.saveTestResultsButton.value = TEXT['Editor.SaveScoreButton'];
			this.saveTestResultsButton.onclick = this.SaveTestResults.Bind(this);
			newP.appendChild(this.saveTestResultsButton);
			newToolbox.appendChild(newP);
		}
	}
	
	if(this.operationMode != "planningprogressiontest") {
		
		// Create actions div
		newToolbox = document.createElement("DIV");
		newToolbox.className = "testResultsDiv";
		this.hTestResultDivContent.appendChild(newToolbox);
		
		newP = document.createElement("P");
		newP.className = "center";
		newP.appendChild(document.createElement("BR"));
		newInput = document.createElement("INPUT");
		newInput.type = "button";
		newInput.className = "mediumButton";
		newInput.value = TEXT['Editor.StartNewTestButton'];
		newInput.onclick = this.OnNewTestButtonClick.Bind(this);
		newP.appendChild(newInput);
		newP.appendChild(document.createElement("BR"));
		newP.appendChild(document.createElement("BR"));
		
		newInput = document.createElement("INPUT");
		newInput.type = "button";
		newInput.className = "mediumButton";
		newInput.value = TEXT['Editor.RestartTestButton'];
		newInput.onclick = this.OnRestartFinishedTestButtonClick.Bind(this);
		newP.appendChild(newInput);
		newToolbox.appendChild(newP);
	}
}

Editor.prototype.OnSaveFaultsAsListButtonClick = function Editor$OnSaveFaultsAsListButtonClick() {
	
	core.ShowDialog('dialog.php?page=pickwordlistcategory', [], 460, 530);
}

Editor.prototype.SaveFaultedWordsAsWordlist = function Editor$SaveFaultedWordsAsWordlist() {
	
}

Editor.prototype.LoadList = function Editor$LoadList(url) {
	
	// Disable button's
	this.testProgressButton.disabled = true;
	
	this.bLoadingWordlist = true;
	this.targetMode = this.mode;
	this.SetMode("loading");
	
	this.wordList.LoadFromXml(url);
}

Editor.prototype.LoadExampleWordlist = function Editor$LoadExampleWordlist() {
	
	this.wordList.Clear();
	this.wordList.SuspendLogging();
	this.wordList.priLanguage = "Nederlands";
	this.wordList.secLanguage = "Engels";
	wordIndex = this.wordList.AppendNewWord();
	this.wordList.ResumeLogging();
	this.wordList.SetValue(wordIndex, 1, "lopen");
	this.wordList.SetValue(wordIndex, 3, "Ik loop op straat");
	this.wordList.SetValue(wordIndex, 2, "to walk");
	this.wordList.SetValue(wordIndex, 4, "I am walking in the street.");
	this.wordList.AppendNewWord();
	
	this.CreateWordTableFromWordlist();
	this.FinalizeInitialization();
}

Editor.prototype.NotifyServerPlanningProgress = function Editor$NotifyServerPlanningProgress() {
	
	// Delcare variables
	var strLearnedWords, strFaultedWords, strData, strUrl;
	var iWordIndex;
	
	strLearnedWords = "";
	strFaultedWords = "";
	
	switch(this.operationMode) {
		case "normal":
			return false;
			break;
		case "planninglearnnew":
		
			strUrl = "xml.php?page=planninglearnprogress&planning=" + this.iCurrentPlanning + "&planningdateid=" + this.iCurrentPlanningDateId;
			
			// Serialize all words in the quinary pool ( = learned words)
			for(var x = 0; x < this.learningEngine.quinaryPool.length; x++) {
				
				if(x > 0)
					strLearnedWords += ",";
				
				// Get the server word id
				iWordIndex = this.learningEngine.quinaryPool[x].wordIndex;
				strLearnedWords += this.wordList.GetValue(iWordIndex, 0); 
			}
			
			// Make the request
			strData = "learnedwords=" + strLearnedWords;
			this.planningProgressRequest = new Net.Request(strUrl, "POST", strData, true);
			this.planningProgressRequest.OnComplete.Suscribe(this.OnNotifyServerPlanningProgress, this);
			this.planningProgressRequest.MakeRequest();
	
			break;
		case "planningprogressiontest":
		
			strUrl = "xml.php?page=planningprogressiontestresults&planning=" + this.iCurrentPlanning + "&planningdateid=" + this.iCurrentPlanningDateId;
		
			// Serialize all the word id's in the learningEngine.arrFaultedQuestions array ( = faulted words)
			for(var x = 0; x < this.learningEngine.arrFaultedQuestions.length; x++) {
				
				if(x > 0)
					strFaultedWords += ",";
				
				// Get the server word id
				iWordIndex = this.learningEngine.arrFaultedQuestions[x];
				strFaultedWords += this.wordList.GetValue(iWordIndex, 0); 
			}
			
			// Make the request
			strData = "faultedwords=" + strFaultedWords;
			this.planningProgressRequest = new Net.Request(strUrl, "POST", strData, true);
			this.planningProgressRequest.OnComplete.Suscribe(this.OnNotifyServerPlanningProgress, this);
			this.planningProgressRequest.MakeRequest();
			
			break;
	}
	
	return true;
}

Editor.prototype.OnNotifyServerPlanningProgress = function Editor$OnNotifyServerPlanningProgress() {
	
	// Declare variables
	var strMessage;
	var newP, newInput;
	
	// Update status text
	if(this.operationMode == "planninglearnnew" || this.operationMode == "planningprogressiontest") {
		
		if(this.hTestResultStatusDiv && this.hTestResultStatusDiv.lastChild)
			this.hTestResultStatusDiv.removeChild(this.hTestResultStatusDiv.lastChild);
		
		newP = document.createElement("P");
		newP.className = "center";
		newP.appendChild(document.createElement("BR"));
		if(this.planningProgressRequest.ExtendedResult) {
			newP.appendChild(document.createTextNode(TEXT['Editor.SavePlanningProgressSaved']));
		} else {
			newP.appendChild(document.createTextNode(TEXT['Editor.SavePlanningProgressError']));
		}
		this.hTestResultStatusDiv.appendChild(newP);
		
		// Add buttons
		if(this.operationMode == "planninglearnnew") {
			newP.appendChild(document.createElement("BR"));
			newP.appendChild(document.createElement("BR"));
			newInput = document.createElement("INPUT");
			newInput.className = "largeButton";
			newInput.type = "button";
			newInput.value = TEXT['Editor.LearnMoreNewWordsForPlanning'];
			newInput.onclick = this.PlanningLearnMoreNewWords.Bind(this);
			newP.appendChild(newInput);
		}
		
		// Add goto my planning button
		newP.appendChild(document.createElement("BR"));
		newP.appendChild(document.createElement("BR"));
		newInput = document.createElement("INPUT");
		newInput.className = "largeButton";
		newInput.type = "button";
		newInput.value = TEXT['Editor.GoToMyPlanningButton'];
		newInput.onclick = function() { window.open("index.php?page=planner", target='_self'); };
		newP.appendChild(newInput);
	}
}

Editor.prototype.PlanningLearnMoreNewWords = function Editor$PlanningLearnMoreNewWords() {
	
	// Declare variables
	var strUrl;
	
	if(this.operationMode == "planninglearnnew" && this.iCurrentPlanning !== null && this.iCurrentPlanningDateId !== null) {
		
		strUrl = "xml.php?page=planninglist&planning=" + this.iCurrentPlanning + "&planningdateid=" + this.iCurrentPlanningDateId;
		this.LoadList(strUrl);
	} else {
		throw new Error("Cannot learn more new words. Action is not supported under the current operation mode.")
	}
}

Editor.prototype.OnSpeechLoaded = function Editor$OnSpeechLoaded() {
	
	try {
		this.speechSettingsButton.Enable();
		
		// Apply settings
		editor.speech.bShowBalloon = Sys.Settings.Speech.ShowBalloon;
		editor.speech.SetVoice(Speech.Voices.British, Sys.Settings.Speech.VoiceGender, Sys.Settings.Speech.VoiceSpeed);
	}
	catch(ex) {};
}

/**
 * Calculates the progress of the current test and returns the value (1 - 100)
 */
Editor.prototype.CalcTestProgress = function Editor$CalcTestProgress() {
	
	// Declare variables
	var iProgress;
	var iTotalWords, iWordsInSourcePool, iFinishedWords;
			
	// Get word counts
	iTotalWords = this.learningEngine.sourcePool.length + this.learningEngine.primaryPool.length + this.learningEngine.secondaryPool.length + this.learningEngine.tertiaryPool.length + this.learningEngine.quaternaryPool.length + this.learningEngine.quinaryPool.length;
	iWordsInSourcePool = this.learningEngine.sourcePool.length;
	iFinishedWords = this.learningEngine.quinaryPool.length;
	
	switch(this.learningEngine.repeatMethod) {
		case RepeatMethodEnum.PIT:
		
			// Calculate progress
			iProgress = Math.round(((iFinishedWords / iTotalWords * 50) + (iTotalWords - iWordsInSourcePool) / iTotalWords * 50)) ;
			
			break;
		case RepeatMethodEnum.UNTIL_KNOWN:
		case RepeatMethodEnum.NONE:
		
			// Calc progress form finished words
			iProgress = Math.round((iFinishedWords / iTotalWords * 100));
			
			break;
		default:
			break;
	}
	
	return iProgress || 1;
}

Editor.prototype.TextInputShowThoughtExercice = function Editor$TextInputShowThoughtExercice() {
	
	// Delcare variables
	var containerDiv;
	var newDiv, newP, newInput;
	
	// Clear hTestInputDiv
	while(this.hTestInputDiv.childNodes.length > 0) {
		this.hTestInputDiv.removeChild(this.hTestInputDiv.childNodes[0]);
	}
	
	// Create question container
	containerDiv = document.createElement("div");
	containerDiv.className = "thoughtExerciceQuestionDiv";
	this.hTestInputDiv.appendChild(containerDiv);
	
	// Get language strings
	if(this.learningEngine.currentQuestionDirection == QuestionDirectionEnum.PRIMARY_SECONDARY) {
		strPriLanguage = this.wordList.priLanguage;
		strSecLanguage = this.wordList.secLanguage;
		oVoice = this.oPrimaryVoice;
	} else if(this.learningEngine.currentQuestionDirection == QuestionDirectionEnum.SECONDARY_PRIMARY) {
		strSecLanguage = this.wordList.priLanguage;
		strPriLanguage = this.wordList.secLanguage;
		oVoice = this.oSecondaryVoice;
	}
	
	// Question label language
	newP = document.createElement("P");
	newP.className = "questionLabelLanguage";
	if(this.learningEngine.strCurrentRemark.trim() != "") {
		newP.appendChild(document.createTextNode(strPriLanguage + " - " + this.learningEngine.strCurrentRemark.trim()));
	} else {
		newP.appendChild(document.createTextNode(strPriLanguage));
	}
	containerDiv.appendChild(newP);
	
	// Question label
	newP = document.createElement("P");
	newP.className = "questionLabel";
	newP.appendChild(document.createTextNode(this.learningEngine.strCurrentQuestion));
	containerDiv.appendChild(newP);
	
	// Create timer progressbar if a time limit is set
	if(this.learningEngine.iAnswerTime >= 0) {
		
		newDiv = document.createElement("div");
		newDiv.className = "thoughtExerciceProgessBarContainer";
		containerDiv.appendChild(newDiv);
		
		this.hAnswerTimeProgressBar = new UI.ProgressBar(newDiv, 0, this.learningEngine.iAnswerTime, 560, 10);
	}
	
	// Speak text
	if(this.learningEngine.bEnableSpeech && this.speech.bSpeechOutput && this.oVoice !== null) {
		this.speech.SetVoice(oVoice);
		this.speech.Speak(this.learningEngine.strCurrentQuestion);
	}
	
	// Create continue button
	newP = document.createElement("P");
	newP.className = "center";
	newInput = document.createElement("input");
	newInput.type = "button";
	newInput.className = "mediumButton";
	newInput.value = TEXT['Editor.ContinueButton'];
	newInput.onclick = this.TextInputShowThoughtExerciceStage2.Bind(this);
	newP.appendChild(newInput);
	containerDiv.appendChild(newP);
	
	newInput.focus();
	newInput.focus();
	
	// Set timer
	if(this.learningEngine.iAnswerTime >= 0) {
		this.learningEngine.iAnswerTimeRemaining = this.learningEngine.iAnswerTime;
		if(this.answerTimer != null)
			clearInterval(this.answerTimer);
		this.answerTimer = setInterval(this.OnThoughtExerciceTimerTick.Bind(this), 1000);
	}
}

Editor.prototype.OnThoughtExerciceTimerTick = function Editor$OnThoughtExerciceTimerTick() {
	
	// Declare variables
	
	// Check if test is still running
	if(!this.learningEngine.bRunning) {
		clearInterval(this.answerTimer);
		this.answerTimer = null;
		return;
	}
	
	// Decrement remaining time
	this.learningEngine.iAnswerTimeRemaining--;
	this.hAnswerTimeProgressBar.SetProgress(this.learningEngine.iAnswerTime - this.learningEngine.iAnswerTimeRemaining);
	
	// Check if time out
	if(this.learningEngine.iAnswerTimeRemaining < 0) {
		clearInterval(this.answerTimer);
		this.TextInputShowThoughtExerciceStage2();
	}
}

Editor.prototype.TextInputShowThoughtExerciceStage2 = function Editor$TextInputShowThoughtExerciceStage2() {
	
	// Delcare variables
	var containerDiv;
	var newDiv;
	
	// Stop interval timer
	if(this.answerTimer  != null) {
		clearInterval(this.answerTimer);
		this.answerTimer = null;
	}
	
	// Clear hTestInputDiv
	while(this.hTestInputDiv.childNodes.length > 0) {
		this.hTestInputDiv.removeChild(this.hTestInputDiv.childNodes[0]);
	}
	
	// Create question container
	containerDiv = document.createElement("div");
	containerDiv.className = "thoughtExerciceQuestionDiv";
	this.hTestInputDiv.appendChild(containerDiv);
	
	// Get language strings
	if(this.learningEngine.currentQuestionDirection == QuestionDirectionEnum.PRIMARY_SECONDARY) {
		strPriLanguage = this.wordList.priLanguage;
		strSecLanguage = this.wordList.secLanguage;
		oVoice = this.oPrimaryVoice;
	} else if(this.learningEngine.currentQuestionDirection == QuestionDirectionEnum.SECONDARY_PRIMARY) {
		strSecLanguage = this.wordList.priLanguage;
		strPriLanguage = this.wordList.secLanguage;
		oVoice = this.oSecondaryVoice;
	}
	
	// Question label language
	newP = document.createElement("P");
	newP.className = "questionLabelLanguage";
	newP.appendChild(document.createTextNode(TEXT['Editor.CorrectAnswerIs']));
	containerDiv.appendChild(newP);
	
	// Question label
	newP = document.createElement("P");
	newP.className = "questionLabel";
	newP.appendChild(document.createTextNode(this.learningEngine.strCurrentKey));
	containerDiv.appendChild(newP);
	
	// Question label language
	newP = document.createElement("P");
	newP.className = "questionLabelLanguage";
	newP.appendChild(document.createTextNode(TEXT['Editor.DoesAnswerMatchThought']));
	containerDiv.appendChild(newP);
	
	// Create continue button
	newP = document.createElement("P");
	newP.className = "center";
	newInput = document.createElement("input");
	newInput.type = "button";
	newInput.className = "testControlDivButton";
	newInput.value = TEXT['Editor.No'];
	newInput.onclick = this.CheckThoughtExercice.Bind(this, false);
	newP.appendChild(newInput);
	newInput = document.createElement("input");
	newInput.type = "button";
	newInput.className = "testControlDivButton";
	newInput.value = TEXT['Editor.Yes'];
	newInput.onclick = this.CheckThoughtExercice.Bind(this, true);
	newP.appendChild(newInput);
	containerDiv.appendChild(newP);
	
	newInput.focus();
	newInput.focus();
}

Editor.prototype.CheckThoughtExercice = function Editor$CheckThoughtExercice(bCorrect) {
	
		// Declare variables
		var currentDate, elapsedTime;
		var strTime, strScore;
		var iScore, iCorrectAnswers;
		
		// Handle the answer
		if(bCorrect) {
			this.learningEngine.HandleCorrectAnswer();
		} else {
			this.learningEngine.HandleIncorrectAnswer();
		}
		
		// Calculate elapsed time
		currentDate = new Date();
		elapsedTime = new Date();
		elapsedTime.setTime(currentDate.getTime() - this.testStartTime.getTime())
		
		// Format elapsed time
		strTime = elapsedTime.getMinutes() + ":";
		if(elapsedTime.getSeconds() < 10) {
			strTime += "0" + elapsedTime.getSeconds();
		} else {
			strTime += elapsedTime.getSeconds();
		}
		
		// Format score
		iCorrectAnswers = this.learningEngine.iQuestionCount - this.learningEngine.iErrorCount;
		iScore = iCorrectAnswers / this.learningEngine.iQuestionCount;
		strScore = Math.round(iScore * 10) + " (" + Math.round(iScore * 100) + "% " + TEXT['Editor.Correct'] + ")";
	
		if(bCorrect) {
			this.AppendHistoryRow(strTime, this.learningEngine.strCurrentQuestion, TEXT['Editor.Yes'], this.learningEngine.strCurrentKey, strScore, true);
		} else {
			this.AppendHistoryRow(strTime, this.learningEngine.strCurrentQuestion, TEXT['Editor.No'], this.learningEngine.strCurrentKey, strScore, false);
		}
		
		// Get next question
		this.PopNextTestQuestion();
	}

