var gHostName = 'http://localhost:8080/music/';
var problemArray; // holds all the problems loaded from the xml file for this module
var instructionArray; // holds all the instructions for each set of problems, there may not be as many instructions as problems
var instructionsToUseArray; // holds indexes to the instructionArray on which instruction to use per problem
var problemToUseArray;// holds indexes to the problemArray on which problems to user per problem (since the totalOnTest may be larger than number of problems in the xml data)
var gTotalProblemsFromXML = 0; // total number of problems in the xml
var instructionIndexPerProblem; // holds index into instructionArray of which problem goes with which instruction (since there is are instructions for a set of problems, need to keep track which instruction goes with which problem)

var gDescription; // hold the description of the xml file, not to be read by user
var gRandom; // whther  this module show the problems in random order (true/false)
var gTimed; // whether this module is timed (true/false)
var gTotalOnTest; // the total items on the test (may not be the same as the number of problems in the xml)
var gTrainingType; // the type of training: "timed test". 
var gInitialInstructionsToStudent; // initial instructions before starting the module, shown only once in the beginning
var gFinalInstructionsToStudent;
var gDurationOfTest; // duration of test in seconds
var gCounter; // current countdown time of test
var gCountDownTimer; // countdown timer
var gTestTimer; // timer for test
var gTestStarted = "false";
var gFileName = '';


var gAjaxRequestProblems = null;
var gProblemsTakenSoFar = 0; // holds the number of problems that have been taken so far

var gInitXLocOfNote = 100; // initial Xloc of Notes put on the staff image


// load the data from the server into a hashtable with key being the id
function loadServerXMLDataIntoProblemArray(xmlData)
{
	problemArray = new Array();
	instructionArray = new Array();
	instructionIndexPerProblem = new Array();
	
	var module = xmlData.getElementsByTagName("module");
	gDescription = convertXMLCheckForNull(module[0].getElementsByTagName("description")[0].childNodes[0]); // internal description to describe what module is about when reading the xml file
	gRandom = convertXMLCheckForNull(module[0].getElementsByTagName("random")[0].childNodes[0]); // whether this test has the problems randomly chosen when performing the module (true/false)
	gTimed = convertXMLCheckForNull(module[0].getElementsByTagName("timed")[0].childNodes[0]); // whether this test is timed (true/false)
	gTotalOnTest = convertXMLCheckForNull(module[0].getElementsByTagName("totalOnTest")[0].childNodes[0]); // the total number of problems that should be shown to the student (may be more than the actual number of problems in the xml so the problems will be reused), this is a number field
	gTrainingType = convertXMLCheckForNull(module[0].getElementsByTagName("trainingtype")[0].childNodes[0]); // values include: "timed test" (must time the test and show a button when to start the timed test)
	gInitialInstructionsToStudent = convertXMLCheckForNull(module[0].getElementsByTagName("initialInstructionsToStudent")[0].childNodes[0]); // initial instructions for the student what this test is about, will be removed once module is started
	gFinalInstructionsToStudent = convertXMLCheckForNull(module[0].getElementsByTagName("finalInstructionsToStudent")[0].childNodes[0]); // final instructions for the student 
	
	gDurationOfTest = convertXMLCheckForNull(module[0].getElementsByTagName("durationOfTest")[0].childNodes[0]); // 
	
	var theSets = xmlData.getElementsByTagName("set"); // holds the sets for the module, a set is one that has different top instructions displayed on the GUI
	var tmpInstructions, tmpInitialNotes, tmpTextQuestion, tmpStaffAnswer, tmpTextAnswer;
	var someProblems;

	for(var ii=0; ii < theSets.length; ii++)
	{
		instructionArray[ii] = convertXMLCheckForNull(theSets[ii].getElementsByTagName("instructions")[0].childNodes[0]);
		someProblems = theSets[ii].getElementsByTagName("problem");
		
		for(var kk=0; kk < someProblems.length; kk++)
		{
			tmpInitialNotes = convertXMLCheckForNull(someProblems[kk].getElementsByTagName("InitialNotes")[0].childNodes[0]);
			tmpTextQuestion = convertXMLCheckForNull(someProblems[kk].getElementsByTagName("TextQuestion")[0].childNodes[0]);
			tmpStaffAnswer = convertXMLCheckForNull(someProblems[kk].getElementsByTagName("StaffAnswer")[0].childNodes[0]);
			tmpTextAnswer = convertXMLCheckForNull(someProblems[kk].getElementsByTagName("TextAnswer")[0].childNodes[0]);
			problemArray[gTotalProblemsFromXML] = {"InitialNotes" : tmpInitialNotes, "TextQuestion": tmpTextQuestion, "StaffAnswer": tmpStaffAnswer, "TextAnswer": tmpTextAnswer};
			
			instructionIndexPerProblem[gTotalProblemsFromXML] = ii;
			gTotalProblemsFromXML++;
		}	
	}
}

// create the problems set given the problemArray, totalOnTest, random
// will make the instructionsToUseArray which is an array as long as totalOnTest indexing into the instructionArray on which instruction to use for each problem
// will make the problemToUseArray which is an array as long as totalOnTest indexing into the problemArray on which problems to use for each problem
function makeProblemSet()
{
	instructionsToUseArray = new Array();
	problemToUseArray = new Array();
	
	if (gRandom == 'true') // case when test must be random and the problems should not repeat
	{
		// make an index array as long as number of problems on test
		var indexArray = new Array();
		for (var kk=0; kk<gTotalProblemsFromXML; kk++)
		{ indexArray[kk] = kk; }
		
		var tmpIndex;
		for (var ii=0; ii<gTotalOnTest; ii++)
		{
			tmpIndex = Math.floor((indexArray.length)*Math.random());
			
			problemToUseArray[ii] = indexArray[tmpIndex];
			instructionsToUseArray[ii] = instructionIndexPerProblem[ indexArray[tmpIndex] ];
			
			indexArray.splice(tmpIndex,1); // remove the Index used so no repeats happen
			
			if (indexArray.length == 0) // make another index array since all of them have been removed
			{
				for (var kk=0; kk<gTotalProblemsFromXML; kk++)
				{ indexArray[kk] = kk; }
			}
			
		}
	}
	else // case when the problems should be displayed in the same order as the xml file
	{
		var iRunningTotal = 0;
		
		for (var ii=0; ii<gTotalOnTest; ii++)
		{
			for (var kk=0; kk<gTotalProblemsFromXML; kk++)
			{
				problemToUseArray[iRunningTotal] = kk;
				instructionsToUseArray[iRunningTotal] = instructionIndexPerProblem[kk];
				iRunningTotal++;
				
				if (iRunningTotal >= gTotalOnTest)
					break;
			}
			
			if (iRunningTotal >= gTotalOnTest)
					break;
		}
	}
	
}


// load the XML file for the problem set named with gFileName
function ajaxProblemSet()
{
	gAjaxRequestProblems = createAJAXRequestUtils(gAjaxRequestProblems)
	if(gAjaxRequestProblems != null)
	{
		gAjaxRequestProblems.onreadystatechange = processLoadProblemSet;
		gAjaxRequestProblems.open("POST", gHostName + gFileName, true); 	
		gAjaxRequestProblems.send("");
	}
}


// receive XML from server and load first problem
function processLoadProblemSet()
{
	if(gAjaxRequestProblems.readyState == 4)
	{
		if(gAjaxRequestProblems.status == 200)
		{
			loadServerXMLDataIntoProblemArray(gAjaxRequestProblems.responseXML);
			makeProblemSet();
			
			gProblemsTakenSoFar = 0; // reset gProblemsTakenSoFar to 0 when new data is loaded
			showIntroInstructions();
		}
		else
		{
			alert("Error loading problem set");
		}
	}
}


function showIntroInstructions()
{
	if (gInitialInstructionsToStudent.length > 0) // show initial instructions
	{
		var theInstructions = document.getElementById('theInstructions');
		theInstructions.innerHTML = gInitialInstructionsToStudent;
	}
}


// start the test, initiated by pressing Start button
function startTest()
{
	
	// check if a timed test
	if (gTimed  == "true") // start the Timer for the test
	{
		gTestTimer = setTimeout("stopTest()", gDurationOfTest*1000);
		
		// set countdown time
		gCounter = gDurationOfTest;
		
		// show time remaining
		updateCountDown();
	
		// start countdown timer
		gCountDownTimer = setInterval("updateCountDown()",1000);
	}
	
	gTestStarted = "true"; // set flag that test has started
	
	var startButton = document.getElementById('startButton');
	startButton.style.display = "none";
	
	var submitButton = document.getElementById('submitButton');
	submitButton.style.display = "block";
	
	showNextProblem(); // show the first problem
		
}


// stop the test if timer expires
function stopTest()
{
	
	// set the flag to stop the test
	gTestStarted = "false";
	
	// hide the submit button
	var submitButton = document.getElementById('submitButton');
	submitButton.style.display = "none";
		
	// hide the input text field
	var theTextAnswer = document.getElementById('theTextAnswer');
	theTextAnswer.style.display = "none";
	
	// stop countdown timer
	window.clearInterval(gCountDownTimer);
	document.getElementById('timeremaining').innerHTML = "0:00";
	
	// show the final text in the instructions location
	var now = new Date();
	document.getElementById('theInstructions').innerHTML = gFinalInstructionsToStudent + "<br>" + "<a href='index.html' style='cursor:pointer;'><u><b>click here to try again</b></u></a><br>" + now.toLocaleString();
	
	// need to setLayout whenever instructions change
	setLocations();
}


//  add the initial notes onto the staff, instructions and question for the next problem 
function showNextProblem()
{
	
	if ((gProblemsTakenSoFar < gTotalOnTest) && (gTestStarted == "true"))
	{
		// check if shadow note should be visible ()
		var tmpStaffAnswer = problemArray[ problemToUseArray[gProblemsTakenSoFar] ].StaffAnswer;
		if (tmpStaffAnswer.length > 0)
		{
			var shadowLayer = document.getElementById('shadowLayer'); 
			shadowLayer.style.display = "block"; // show shadow layer if StaffAnswer is non-zero length
			gShadowNote.style.display = "block"; // show shadow note if StaffAnswer is non-zero length
		}
		// hide previous ledger lines
		hidleLedgerLines();
		
		// show initial notes
		var tmpInitNotes = problemArray[ problemToUseArray[gProblemsTakenSoFar] ].InitialNotes;
		addInitialNotesOnStaff(tmpInitNotes);
		
		// show the TextQuestion (if any)
		var theQuestion = document.getElementById('theQuestion');
		var tmpTextQuestion = problemArray[ problemToUseArray[gProblemsTakenSoFar] ].TextQuestion;
		theQuestion.innerHTML = tmpTextQuestion;
		
		// show the Instructions (if any)
		var theInstructions = document.getElementById('theInstructions');
		var tmpInstructions = instructionArray[ instructionsToUseArray[gProblemsTakenSoFar] ];
		theInstructions.innerHTML = tmpInstructions;
		
		// put focus onto text input field if answer is text type
		//if (problemArray[gProblemsTakenSoFar].TextAnswer.length > 0)
		if (problemArray[ problemToUseArray[gProblemsTakenSoFar] ].TextAnswer.length > 0)
			document.getElementById('theTextAnswer').focus();
		
		// need to setLayout whenever instructions change
		setLocations();
	}
}


// restart test if user wants to try again
function restartTest()
{
	makeProblemSet(); // make new problem set
	
	gProblemsTakenSoFar = 0; // reset gProblemsTakenSoFar to 0 when new data is loaded
	gTotalAnsweredCorrectly = 0; // reset total answer correctly
	gTotalAnsweredIncorrectly = 0; // reset total answer incorrectly
	showIntroInstructions(); // show intro instructions
	document.getElementById('timeremaining').innerHTML = ""; // clear countdown timer gui
	
	// clear textfield
	var theTextAnswer = document.getElementById('theTextAnswer'); // textfield on GUI
	theTextAnswer.value = "";
		
	// clear notes on staff	
	removeAllNotes();
		
	// clear notes added to NotesArray
	emptyArray();	
	
	if (gTimed == 'true')
	{
		var percentaccurate = document.getElementById('percentaccurate');
		percentaccurate.innerHTML = "" ;
		
		var percentcomplete = document.getElementById('percentcomplete');
		percentcomplete.innerHTML = "";
	}
	
	// show the start button
	var startButton = document.getElementById('startButton');
	startButton.style.display = "block";
	
	// hide the submit button
	var submitButton = document.getElementById('submitButton');
	submitButton.style.display = "none";
		
	// show the input text field
	var theTextAnswer = document.getElementById('theTextAnswer');
	theTextAnswer.style.display = "block";
}


// update the Countdown timer
function updateCountDown()
{
	var tmpMin = Math.floor(gCounter/60);
	var tmpSec = gCounter - (tmpMin*60);
	if (tmpSec < 10)
	tmpSec = "0" + tmpSec;
		document.getElementById('timeremaining').innerHTML = tmpMin + ":" + tmpSec;
		
	gCounter--;
	if (gCounter < 0)
		window.clearInterval(gCountDownTimer);
}


// input the string that holds the notes to plot, ie c3,e3,g3 or c#3 or c3
function addInitialNotesOnStaff(theNotes)
{
	
	var tmpNotes = theNotes.split(',');
	var tmpNoteOctaveAccidental, tmpYLoc;
	var tmpDeletable = 'false'; // allow initial notes not to be deleteable by user
	for (var ii=0; ii < tmpNotes.length; ii++)
	{
		tmpNoteOctaveAccidental = tmpNotes[ii];
		addToNoteArrayUsingNote(tmpNoteOctaveAccidental);
		
		tmpYLoc = hashNoteToLocation[tmpNoteOctaveAccidental];
		
		addNoteByPosition(gInitXLocOfNote, tmpYLoc, tmpDeletable);
		
		showLedgerLine(tmpYLoc);
	}
}

function determineURL()
{
	//determine Hostname, include port number if applicable
	gHostName = window.location.protocol + "//" + window.location.hostname;
	var tmpPort = window.location.port;
	if (tmpPort.length > 0)
		gHostName = gHostName + ":" + tmpPort
	
	var paths = window.location.pathname.split("/"); // gets the paths after the hostname and port
	sWebAppFolder = paths[1];	// webAppFolder
	gHostName = gHostName + "/" + sWebAppFolder + "/";
}

function getQueryStringParams()
{
	var sHREF = window.location.href;
	var iIndexModule = sHREF.indexOf("module=");
	var sModule = "";
	if (iIndexModule > -1)
	{
		sModule = sHREF.substring(iIndexModule+7,sHREF.length);
	}
	
	if (sModule == "nrtreble")
	{
		gFileName = "data/treble.xml";
	}
	else if (sModule == "nrbass")
	{
		gFileName = "data/bass.xml";
	}
	else if (sModule == "nrgrandstaffnoledger")
	{
		gFileName = "data/grandStaffWithoutLedger.xml";
	}
	else if (sModule == "nrgrandstaffledger")
	{
		gFileName = "data/grandStaffWithLedger.xml";
	}
	else if (sModule == "nrgrandstaffonlyledger")
	{
		gFileName = "data/OnlyLedger.xml";
	}
	else if (sModule == "nrtreblefast")
	{
		gFileName = "data/trebleFast.xml";
	}
	else if (sModule == "nrbassfast")
	{
		gFileName = "data/bassFast.xml";
	}
	else if (sModule == "nrgrandstaffnoledgerfast")
	{
		gFileName = "data/grandStaffWithoutLedgerFast.xml";
	}
	else if (sModule == "nrgrandstaffledgerfast")
	{
		gFileName = "data/grandStaffWithLedgerFast.xml";
	}
	else if (sModule == "nrgrandstaffonlyledgerfast")
	{
		gFileName = "data/OnlyLedgerFast.xml";
	}
}

