/*
**	Constants
*/
var g_SCO_SELF_NAVIGATED = 0;
var g_SCO_VLE_NAVIGATED = 1;

/*
**	Utilities
*/
function padInt(toPad)
{
	return toPad < 10 ? toPad + "0" : toPad;
}


/*
**	Main harness object. Implements all the functionality required for the harness
**	to emulate the VLE as well managing the SCOs in the course that is being deployed
**	through the harness.
*/
function Harness()
{
	// The SCOs in this course
	this.scos = new Array();
	// The currently running SCO
	this.currentScoCode = null;
	this.description = "Xtensis harness API";
	this.sessionStartTime = 0;
}

/*
**	Adds a new SCO to the harness.
**
**	@param code String identifier for the SCO
**	@param type Whether this SCO is self navigated or navigated by the harness
**				Can be one of g_SCO_SELF_NAVIGATED or g_SCO_VLE_NAVIGATED
**	@param url location of the SCO
*/
Harness.prototype.addSco = function(code, type, url)
{
	this.scos[code] = new Sco(type, url);
}

/*
**	Returns the SCO object with the provided code
**
**	@param code String identifier for the SCO to be fetched
*/
Harness.prototype.getSco = function(code)
{
	return this.scos[code];
}

/*
**	Launches a SCO. If the SCO is self navigated - it is launched in a new window.
**	If the SCO is VLE navigated it is launched in the contentFrame.
**
**	@param code String identifier for the SCO to be launched
**
*/
Harness.prototype.launchSco = function(code)
{
	var sco;
	if (sco = this.getSco(code))
	{
		switch(sco.type)
		{
			case g_SCO_VLE_NAVIGATED:
				window.contentFrame.document.location = sco.url;
				this.currentScoCode = code;
				break;

			case g_SCO_SELF_NAVIGATED:
				window.open(sco.url, 'sco', 'width=790,height=520');
				this.currentScoCode = code;
				break;
		}
	}
}

/*
**	Return the amount of time the current SCO has been running for in the format hh:mm:ss.
**	Helper method used by LMSGetValue
**
**	@param code String identifier for the SCO to be launched
**
*/
Harness.prototype.getSessionTime = function()
{
	var currentDate = new Date().getTime();
	var ts = ((currentDate - this.sessionStartTime) / 1000);
	 
	var sec = (ts % 60);

	ts -= sec;
	var tmp = (ts % 3600);  //# of seconds in the total # of minutes
	ts -= tmp;              //# of seconds in the total # of hours

	// convert seconds to conform to CMITimespan type (e.g. SS.00)
	sec = Math.round(sec * 100) / 100;

	var strSec = new String(sec);
	var strWholeSec = strSec;
	var strFractionSec = "";

	if (strSec.indexOf(".") != -1)
	{
		strWholeSec =  strSec.substring(0, strSec.indexOf("."));
		strFractionSec = strSec.substring(strSec.indexOf(".") + 1, strSec.length);
	}

	if (strWholeSec.length < 2)
	{
		strWholeSec = "0" + strWholeSec;
	}
	strSec = strWholeSec;

	if (strFractionSec.length)
	{
		strSec = strSec + "." + strFractionSec;
	}


	if ((ts % 3600) != 0)
	{
		var hour = 0;
	}
	else
	{
		var hour = (ts / 3600);
	}
	
	if ((tmp % 60) != 0)
	{
		var min = 0;
	}
	else
	{
		var min = (tmp / 60);
	}

	if ((new String(hour)).length < 2)
	{
		hour = "0" + hour;
	}
	if ((new String(min)).length < 2)
	{
		min = "0" + min;
	}

	return hour + ":" + min + ":" + strSec;
}

/*
**	LMS method. Resets the session time for the current SCO.
**
**	@param x reserved parameter
*/
Harness.prototype.LMSInitialize = function(x)
{
	var date = new Date();
	this.sessionStartTime = date.getTime();
	return "true";
}

/*
**	LMS method.
**
**	@param x reserved parameter
*/
Harness.prototype.LMSFinish = function(x)
{
	/*
	**	TODO
	**	Decide what happens when LMSFinish is called
	**	Is the window closed or is the next SCO launched?
	**	If this is the last SCO is the window closed or do the SCOs wrap?
	*/
	//closeHarness();
	return "true";
}

/*
**	LMS method. Sets the value for the specified path.
**
**	@param path String containing the path who's value should be set
**	@param value String value to set
*/
Harness.prototype.LMSSetValue = function(path, value)
{
	this.getSco(this.currentScoCode).setValue(path, value);
	return true;
}

/*
**	LMS method. Fetches the value of the specified path
**
**	@param path String containing the path who's value should be fethed
**
*/
Harness.prototype.LMSGetValue = function(path)
{
	if (path == "cmi.core.total_time" || path == "cmi.core.session_time")
	{
		return this.getSessionTime();
	}

	return this.getSco(this.currentScoCode).getValue(path)

}

/*
**	LMS method. Dummy method that in an LMS would store the current state of the run time data
**
**	@param parameter reserved parameter
*/
Harness.prototype.LMSCommit = function(parameter)
{
	return "true";
}

/*
**	LMS method. Dummy method. Always returns 0 - no error
*/
Harness.prototype.LMSGetLastError = function()
{
	return 0;
}

/*
**	LMS method. Dummy method. Always returns empty string
**
**	@param errornumber Error to look up
*/
Harness.prototype.LMSGetErrorString = function(errornumber)
{
	return "";
}

/*
**	LMS method. Dummy method. Returns empty string
**
**	@param parameter reserved parameter
*/
Harness.prototype.LMSGetDiagnostic = function(parameter)
{
	return "";
}



/*
**	SCO object. Handles the run time data for this SCO. Run time data is stored in an
**	associative array (hash) and persists throughout the harness session.
**
**	@param type identifies how this SCO is navigated - by the VLE or self navigated
**	@param url path to the SCO
*/
function Sco(type, url)
{
	this.type = type;
	this.url = url;
	this.runtimeData = new Array();
	this.reset();
}

/*
**	Sets the initial run time data for this SCO.
*/
Sco.prototype.reset = function()
{
	this.setValue("cmi.core._children", "student_id,student_name,lesson_location,credit,lesson_status,entry,score,total_time,exit,session_time");
	this.setValue("cmi.core.student_id", "1234");
	this.setValue("cmi.core.student_name", "Smith, John");
	this.setValue("cmi.core.lesson_location", "");
	this.setValue("cmi.core.credit", "no-credit");
	this.setValue("cmi.core.lesson_status", "not attempted");
	this.setValue("cmi.core.entry", "ab-initio");
	this.setValue("cmi.core.score._children", "raw,min,max");
	this.setValue("cmi.core.score.raw", "");
	this.setValue("cmi.core.score.min", "");
	this.setValue("cmi.core.score.max", "");
	this.setValue("cmi.core.exit", "");
	this.setValue("cmi.suspend_data", "");
	this.setValue("cmi.launch_data", "");
	this.setValue("nlncat._version", "1.2");
}

/*
**	Sets a run time data value at the specified path. Called by LMSSetValue
**
**	@param path string identifying the path who's value is to be set.
**	@param value string containing the value to set at the specified path.
*/
Sco.prototype.setValue = function(path, value)
{
	this.runtimeData[path] = value;
}

/*
**	Fetches the current value at the specified path. If there is no value at the specified path
**	an empty string is returned. Called by LMSGetValue
**
**	@param path string identifying the path who's value is to be fetched.
*/
Sco.prototype.getValue = function(path)
{
	if (typeof(this.runtimeData[path]) == "undefined")
	{
		return ""
	}
	else
	{
		return this.runtimeData[path];
	}
}

/*
**	Global harness initialisation routine. Called when the frameset has loaded.
**	Creates the Harness object and calls the registerScos function to set the Harness up.
*/
function initialise()
{
	API = new Harness();
	registerScos();
}

var API

