var soundFolder = "/hearingtest/";
var SoundManagerLoaded = false;

soundManager.url = soundFolder + 'soundmanager2.swf'; // override default SWF url
soundManager.debugMode = false;
soundManager.consoleOnly = false;
soundManager.onload = function() {
	soundManager.defaultOptions = {
		'autoLoad': true,//true       // enable automatic loading (otherwise .load() will be called on demand with .play()..)
		'stream': false, //true,       // allows playing before entire file has loaded (recommended)
		'autoPlay': false,             // enable playing of file as soon as possible (much faster if "stream" is true)
		'onid3': null,                 // callback function for "ID3 data is added/available"
		'onload': null,                // callback function for "load finished"
		'whileloading': null,          // callback function for "download progress update" (X of Y bytes received)
		'onplay': null,                // callback for "play" start
		'whileplaying': null,          // callback during play (position update)
		'onstop': null,                // callback for "user stop"
		'onfinish': null,              // callback function for "sound finished playing"
		'onbeforefinish': null,        // callback for "before sound finished playing (at [time])"
		'onbeforefinishtime': 5000,    // offset (milliseconds) before end of sound to trigger beforefinish..
		'onbeforefinishcomplete':null, // function to call when said sound finishes playing
		'onjustbeforefinish':null,     // callback for [n] msec before end of current sound
		'onjustbeforefinishtime':200,  // [n] - if not using, set to 0 (or null handler) and event will not fire.
		'multiShot': true,             // let sounds "restart" or layer on top of each other when played multiple times..
		'pan': 0,                      // "pan" settings, left-to-right, -100 to 100
		'volume': 0                  // self-explanatory. 0-100, the latter being the max.
	}
	soundManager.loadFromXML(soundFolder + "sound-files.xml");
	FinishedLoadingSoundManager();
}
function FinishedLoadingSoundManager(){
	if(!SoundManagerLoaded){
		view_Begin_Start();
		SoundManagerLoaded=true;
	}
}



// These are the offset values to convert normal DB to DB Hearing Loss
function dbOffset(freq){
	switch(freq){
		case  250: return 25.5;
		case  500: return 11.5;
		case 1000: return 7;
		case 2000: return 9;
		case 4000: return 9.5;
		case 8000: return 13;
		default: return 0;
	}
}



// This function plays the tone with the specified parameters
function playTone(waitPeriod,freq,dbIn,ears,function_onfinish){
	// dbIn should go from 0-lowest to 100-highest
	// db (in filename) should go from 0-highest to 100-lowest
	db = 100 - dbIn;
	// db should be adjusted for the dB Hearing Level
	db = db - dbOffset(freq);

	if(db<25) dbRef=0;
	else if(db<50) dbRef=25;
	else if(db<75) dbRef=50;
	else if(db<100) dbRef=75;
	else dbRef=100;
	vol = 100/Math.pow(10,(db-dbRef)/20);
	vol = Math.round(vol);
	var id = freq + "-" + dbRef;
	var balance = 0;
	if(ears.charAt(0) == "R") balance = 100;
	else if(ears.charAt(0) == "L") balance = -100;

	//alert("playing: " + id + " at volume:" + vol);
	if(!waitPeriod || waitPeriod<=0){
		if(function_onfinish+""!=""){
			soundManager.play(id, {volume:vol,pan:balance,onfinish:function_onfinish});
		}else{
			soundManager.play(id, {volume:vol,pan:balance});
		}
	}else{
		//soundManager.sounds[id].load(soundManager.defaultOptions); // not working is playing the same tone regardless of the id specified.
		setTimeout("playTone(0," + freq + "," + dbIn + ",'" + ears + "'," + function_onfinish + ")", waitPeriod);
	}
}



// This is the class for the TestStep Object - handles the logic of the scoring and processing the answers
function TestStep(frequency, ears){
	this.frequency = frequency;
	this.ears = ears;
	this.dbMin = -10;
	this.dbMax = 100;
	this.deltaLarge = 10; // if same as deltaSmall then no large steps
	this.deltaSmall = 5;
	this.dbCurrent = 50;
	this.hadNoAnswer = false;

	this.dbYes = this.dbMax + this.deltaSmall;
	this.dbNo  = this.dbMin - this.deltaSmall;
	this.dbYesSet = function() { return this.dbYes <= this.dbMax; }
	this.dbNoSet  = function() { return this.dbNo  >= this.dbMin; }

	this.started = function(){ return this.dbYesSet() || this.dbNoSet(); }
	this.completed = function(){
		if(this.dbYesSet() && this.dbYes - this.deltaSmall < this.dbMin) return true;
		if(this.dbNoSet()  && this.dbNo  + this.deltaSmall > this.dbMax) return true;
		if(this.dbYesSet() && this.dbNoSet() && (this.dbYes - this.dbNo <= this.deltaSmall)) return true;
		return false;
	}
	
	this.isRightEar = function(){ return (this.ears.charAt(0) == "R"); }
	this.isLeftEar =  function(){ return (this.ears.charAt(0) == "L"); }
	this.isBothEars = function(){ return (this.ears.charAt(0) == "B"); }

	this.bestDb = function(){
		if(this.dbYesSet()) return this.dbYes;
		if(this.dbNoSet())  return this.dbNo;
		return (this.dbMin + this.dbMax)/2;
	}

	this.createEstimate = function(testSteps){
		if(!this.started()){
			for(i = 0; i < testSteps.length; i++){
				var step = testSteps[i];
				if(step.started() && step.frequency <= this.frequency){
					this.dbCurrent = step.bestDb() + 10;
					if(this.dbCurrent > this.dbMax) this.dbCurrent = this.dbMax;
				}
			}
		}
	}

	this.redo = function(){
		this.dbYes = this.dbMax + this.deltaSmall;
		this.dbNo  = this.dbMin - this.deltaSmall;
	}

	this.provideAnswer = function(answer){ // will return if finished (true) or not (false)
		if(answer){ // true
			this.dbYes = this.dbCurrent;
			if(this.completed()){
				this.dbCurrent = this.bestDb();
				return true;
			}
			if(this.dbCurrent - this.deltaLarge > this.dbNo){
				this.dbCurrent = this.dbCurrent - this.deltaLarge;
			}else if(this.dbCurrent - this.deltaSmall > this.dbNo){
				this.dbCurrent = this.dbCurrent - this.deltaSmall;
			}
		}else{ //false
			this.hadNoAnswer = true;
			if(this.dbYesSet()){
				this.dbNo  = this.dbCurrent;
			}
			if(this.completed()){
				this.dbCurrent = this.bestDb();
				return true;
			}
			if(this.dbCurrent + this.deltaLarge < this.dbYes){
				this.dbCurrent = this.dbCurrent + this.deltaLarge;
			}else if(this.dbCurrent + this.deltaSmall < this.dbYes){
				this.dbCurrent = this.dbCurrent + this.deltaSmall;
			}
		}
		return this.completed();
	}
} // object TestStep




function ShowDiv(divName){
	var theDiv = GetElementById(divName);
	if(!theDiv) { return false; }
	SetDivVisibility(theDiv, true);

	var envelope = GetElementById("view_Envelope");
	if(!envelope) { return false; }
	for(var i = 0; i < envelope.childNodes.length; i++){
		var div = envelope.childNodes[i];
		if(div.id){
			if(div != theDiv){ SetDivVisibility(div, false); }
		}
	}
	return true;
}






////// Start of the Main Logic Flow of the Views

var TestSteps = new Array(6);
var CurrentStepNum = -1;
var CurrentStep = false;
var TestType = 1;// 1=Speakers 2=Headphones
var CalibrationMode = false;
var CalibrationLeft = 0;
var CalibrationRight = 0;
var calibrationZero = 10;
var testFrequency = 500;


function view_Begin_Start(){
	SetTitle("Online Hearing Test");
	SetSubtitle("Ready to Begin");
	ShowDiv("view_Begin");
	return true;
}
function view_Begin_Continue(){
	return true;
}


function view_ChooseType_Start(){
	SetTitle("Online Hearing Test");
	SetSubtitle("Select Test Type");
	ShowDiv("view_ChooseType");
	return true;
}
function view_ChooseType_Continue(theType){
	TestType = theType;
	return true;
}


function BeginCalibration(){
	var d = new Date();
	var cvalue = readCookie("TestCalibration");
	if(cvalue){
		var cvalues = cvalue.split("|");
		if(cvalues.length>=4){
			if(1*cvalues[0] == TestType){
				var cookieDate = new Date(cvalues[1]);
				if(d - cookieDate <= 1000*60*60*24*30){ // cookie good for 30 days
					CalibrationLeft = 1 * cvalues[2];
					CalibrationRight = 1 * cvalues[3];
					return view_CalibrationSkip_Start(cookieDate);
				}
			}
		}
	}
	return view_Settings_Start();
}

function view_CalibrationSkip_Start(lastDate){
	SetTitle("Online Hearing Test");
	SetSubtitle("Calibration Last Done on " + lastDate.getMonth() + "/" + lastDate.getDate());
	ShowDiv("view_CalibrationSkip");
	return true;
}
function view_CalibrationSkip_Answer(theAnswer){
	if(theAnswer){
		return view_EnterName_Start();
	}else{
		return view_Settings_Start();
	}
}


function view_Settings_Start(){
	SetTitle("Online Hearing Test");
	SetSubtitle("Adjust Computer Volume");
	ShowDiv("view_Settings");
	return true;
}
function view_Settings_Continue(){
	if(TonesPlaying){ PlayTestTones(); }
	return true;
}

// These functions are for the test tones (alternating tones left/right)
var TonesPlaying=false;
var TestLeft = true;
function PlayTestTones(){
	soundManager.stopAll();
	var buttonContinue = GetElementById("buttonTestToneContinue");
	var buttonTestTone = GetElementById("buttonTestTone");
	if(!TonesPlaying){
		TonesPlaying = true;
		TestLeft = true;
		if(buttonContinue){ buttonContinue.disabled = false; }
		if(buttonTestTone){ buttonTestTone.value = "Stop Tones"; }
		PlayTestToneNow(true);
	}else{
		TonesPlaying = false;
		if(buttonTestTone){ buttonTestTone.value = "Play Tones"; }
	}
}
function PlayTestToneNow(start){
	soundManager.stopAll();
	if(!start){
		setTimeout("PlayTestToneNow('true')",100);
		return;
	}
	if(TonesPlaying){
		if(TestLeft){
			playTone(0, testFrequency, 50, "Left Ear", PlayTestToneNow);
		}else{
			playTone(0, testFrequency, 50, "Right Ear", PlayTestToneNow);
		}
		TestLeft = !TestLeft;
	}
}





function view_Calibration_Start(){
	SetTitle("Online Hearing Test");
	SetSubtitle("Sound Calibration");
	ShowDiv("view_Calibration");
}
function view_Calibration_Continue(){
	if(TestType==1){
		TestSteps = new Array(1);
		TestSteps[0] = new TestStep(testFrequency, "Both Ears");
		TestSteps[0].dbCurrent = 50;
	}else{
		TestSteps = new Array(2);
		TestSteps[0] = new TestStep(testFrequency, "Left Ear");
		TestSteps[1] = new TestStep(testFrequency, "Right Ear");
		TestSteps[0].dbCurrent = 50;
		TestSteps[1].dbCurrent = 50;
	}
	CalibrationMode = true;
	BeginTest();
	return true;
}
function Calibration_Complete(){
	CalibrationMode = false;
	HideEars();
	eraseCookie("TestCalibration");
	createCookie("TestCalibration", TestType + "|" + (new Date().toUTCString()) + "|" + CalibrationLeft + "|" + CalibrationRight , 1, 0, 0);
	return view_EnterName_Start();
}


function view_EnterName_Start(){
	SetTitle("Online Hearing Test");
	SetSubtitle("Begin the Test");
	ShowDiv("view_EnterName");
	return true;
}
function view_EnterName_Continue(){
	var testFld;
	testFld = GetElementById("testNameEntered");
	if(!testFld || testFld.value.length==0){
		alert("The name is required (nickname or anything)");
		return false;
	}
	testFld = GetElementById("testAgeEntered");
	if(!testFld || testFld.value.length==0){
		alert("The age is required (used for statistical averaging)");
		return false;
	}
	if(!IsOnlyChars(testFld.value, "0123456789")){
		alert("Please enter a valid age (only digits)");
		return false;
	}
	testFld = GetElementById("testZipEntered");
	if(!testFld || testFld.value.length==0){
		alert("The zip code (or postal code) is required.");
		return false;
	}
	if(!IsOnlyChars(testFld.value, "0123456789-")){
		alert("Please enter a valid zip code");
		return false;
	}
	testFld = GetElementById("testWearingAids");
	if(!testFld || testFld.value.length==0){
		alert("Please answer if wearing hearing aids.");
		return false;
	}
	
	if(GetElementById("testNameEntered").value == "skiptest"){
		PrepareTestSteps();
		TestDone();
		return false;
	}
	
	return true;
}


function MainTest_Start(){
	PrepareTestSteps();
	BeginTest();
}
function PrepareTestSteps(){
	CalibrationMode = false;
	var fs = new Array(250,500,1000,2000,4000,8000);
	if(TestType==1){
		TestSteps = new Array(6);
		for(i=0; i<fs.length; i++){
			TestSteps[i] = new TestStep(fs[i], "Both Ears");
		}
	}else{
		TestSteps = new Array(12);
		for(i=0; i<fs.length; i++){
			TestSteps[i] = new TestStep(fs[i], "Left Ear");
		}
		for(i=0; i<fs.length; i++){
			TestSteps[6+i] = new TestStep(fs[i], "Right Ear");
		}
	}
}
function BeginTest(){
	CurrentStepNum = 0;
	StartCurrentStep();
}
function StartCurrentStep(){
	CurrentStep = TestSteps[CurrentStepNum];
	if(!CurrentStep) return;
	CurrentStep.createEstimate(TestSteps);
	if(CalibrationMode){
		SetTitle("Calibrating " + CurrentStep.ears + " at " + CurrentStep.frequency + " Hz");
		SetSubtitle("Calibration Step " + (CurrentStepNum+1) + " of " + TestSteps.length);
	}else{
		SetTitle("Testing " + CurrentStep.ears + " at " + CurrentStep.frequency + " Hz");
		SetSubtitle("Step " + (CurrentStepNum+1) + " of " + TestSteps.length);
	}
	if(CurrentStep.completed()){
		CompleteStep();
		return;
	}
	PlayToneForCurrentStep();
}
function SetTitle(text){
	SetDivIdContent("testTitle", text);
}
function SetSubtitle(text){
	SetDivIdContent("testSubtitle", text);
}
function HideEars(){
	SetDivIdVisibility("testLeftEar", false);
	SetDivIdVisibility("testRightEar",false);
}
function UpdateEars(){
	var message = CurrentStep.frequency + " Hz<br />" + CurrentStep.dbCurrent + " dB<br />";
	SetDivIdContent("testLeftEar",  message);
	SetDivIdContent("testRightEar", message);
	SetDivIdVisibility("testLeftEar", !CurrentStep.isRightEar());
	SetDivIdVisibility("testRightEar",!CurrentStep.isLeftEar());
}
function PlayToneForCurrentStep(){
	UpdateEars();
	ShowDiv("view1_Listen");
	var randomnumber= 500 + Math.floor(Math.random()*1001); // random number from 500 to 1500 (milliseconds for pause)
	if(!CurrentStep.started()) randomnumber+=1000;
	var deltaDb = 0;
	if(!CalibrationMode){
		if(CurrentStep.isRightEar()){
			deltaDb = CalibrationRight;
		}else{
			deltaDb = CalibrationLeft; // also works for "Both Ears"
		}
	}
	playTone(randomnumber, CurrentStep.frequency, CurrentStep.dbCurrent + deltaDb, CurrentStep.ears, AfterPlayTone);
}
function AfterPlayTone(){
	setTimeout("AskQuestionForCurrentStep()",500);
}
function AskQuestionForCurrentStep(){
	ShowDiv("view2_Answer");
}
function ToneReplay(){
	PlayToneForCurrentStep();
}
function ToneAnswer(answer){
	CurrentStep.provideAnswer(answer);
	if(CurrentStep.completed()){
		CompleteStep();
	}else{
		PlayToneForCurrentStep();
	}
}
function CompleteStep(){
	ShowDiv("view3_Complete");
	SetDivIdVisibility("testGotoPreviousStep", CurrentStepNum>0);
	UpdateEars();
}
function MoveStep(numToMove){
	SetDivIdVisibility("testGotoPreviousStep", false);
	if(CurrentStepNum + numToMove < 0){ // error case
		alert("There is a problem with the test, please refresh the page to restart.");
		return;
	}
	if(CurrentStepNum + numToMove >= TestSteps.length){ // end of test ************************************
		TestDone();
		return;
	}
	CurrentStepNum = CurrentStepNum + numToMove;
	if(numToMove==0){
		CurrentStep.redo();
	}
	StartCurrentStep();
}
function TestDone(){
	if(CalibrationMode){
		if(TestType==1){
			CalibrationLeft = TestSteps[0].bestDb() - calibrationZero; // assume person was not perfect hearing;
			CalibrationRight = CalibrationLeft;
		}else{
			CalibrationLeft = TestSteps[0].bestDb() - calibrationZero;
			CalibrationRight = TestSteps[1].bestDb() - calibrationZero;
		}
		Calibration_Complete();
	}else{
		var both = GetElementById("txtResultsBoth");
		var right = GetElementById("txtResultsRight");
		var left = GetElementById("txtResultsLeft");
		both.value = "";right.value = "";left.value = "";

		for(i=0; i<TestSteps.length; i++){
			var ear = TestSteps[i].ears.charAt(0);
			var fld;
			if(ear=="L") fld = left;
			else if(ear=="R") fld = right;
			else fld = both;
			if(fld.value.length>0) fld.value += ",";
			fld.value += TestSteps[i].bestDb();
		}
		ShowDiv("view4_SubmitResults");
	}
}


// This is to prevent someone pushing the "Enter" key from auto-submitting the form before the end of the test
var FormReadyToSubmit=false;
function SubmitTest(){
	FormReadyToSubmit = true;
	var theForm = GetElementById("thisTestForm");
	theForm.submit();
}
function CheckTestForm(){
	return FormReadyToSubmit;
}


