/*
 * Copyright (c) 2005 Absolutely Training Limited
 *  
 * Created on 07-Feb-2005
 *
 * @author roberto, fritzd
 */

/**
 * Initialization
 */
new api_imp();
var USER_NOT_FOUND = "No user found. Please log in.";
var COMMIT_ATTEMPT = "COMMIT";
var GET_ATTEMPT = "GET_ATTEMPT";
var TERMINATE = "TERMINATE";
var SEQUENCE = "SEQUENCE";
var LAUNCH_SCO_FROM_SCO = "LAUNCH_SCO_FROM_SCO";
var SCORM_CONTROLLER_URL = misc_findHost() + "scormController.scorm";
var VALUE_PAIRS_SQUENCING_DIVIDER = "EndNameValuePairsStartSequencing";
var VALUE_PAIR_STRING_DELIMITER = "DIVIDER";

var code = "";
/**
	0, no messages shown
	1, meaningfull messases for user showm
	2, all message shown, including debuging ones. 
*/
var debug = 0;

/**
 * Class definition of api_imp class
 */
 function api_imp(containingFrame, contentFrame, host){
    this.containingFrame = containingFrame;
	this.contentFrame = contentFrame;
	this.host = host;
    this.attempt;
    this.variableInfo = new VariableInfo("0", "", "");
    this.state = "Not Initialized";	
    this.requestPage = null;
    this.parameters = null;
    this.deliveryScoId = "not specified";
	this.newDeliveryScoId = "not specified";
    this.valuePairs ="1";
	this.courseId;
	this.bookingId;
	this.version="1.0";
 }
 
api_imp.prototype.constructor = api_imp;

/**
 * Scorm api methods
 */
api_imp.prototype.Initialize = function(params){

	if (this.newDeliveryScoId != "not specified")
	{
		this.deliveryScoId = this.newDeliveryScoId;
		this.newDeliveryScoId = "not specified"
	}
	if (params!=""){
		this.variableInfo= VariableInfo.ERROR_201;     	
	} else if (this.state == "Terminated"){	
		this.variableInfo= VariableInfo.ERROR_104;
	} else if (this.state == "Running") {
		this.variableInfo = VariableInfo.ERROR_103;
	} else {		
		this.state = "Running";		
		this.attempt = new Attempt();				
		var params = "action=" + GET_ATTEMPT + "&deliveryScoId=" + this.deliveryScoId + "&courseId=" + this.courseId;
		
		if (this.bookingId){
			params = params+"&bookingId="+this.bookingId;
		}	

		var nameValuePairs = this.loadXMLDoc(SCORM_CONTROLLER_URL, params);

		if (nameValuePairs.indexOf("cmi.")>-1){
				this.recover(nameValuePairs);

		}else{
			this.dealWithError(nameValuePairs);
		}		
		
	}

	return this.variableInfo.value;
			
};

api_imp.prototype.LMSInitialize = api_imp.prototype.Initialize;

api_imp.prototype.SetValue = function(key, value){
	if (this.state == "Not Initialized"){
		this.variableInfo = VariableInfo.ERROR_132;
	} else if (this.state == "Terminated"){
		this.variableInfo = VariableInfo.ERROR_133;
	} else if (key == ""){
		this.variableInfo = VariableInfo.ERROR_351;
	} else {
		this.variableInfo = this.attempt.set(key, value);
	}
	return this.variableInfo.value;
};

api_imp.prototype.LMSSetValue = api_imp.prototype.SetValue;

/**
 * Sets property directly, no matter whether they are readonly or not. Used for population of RTE on initialization
 */
api_imp.prototype.SetValueDirect = function(key, value){
/*	
	if (this.state == "Not Initialized"){
		this.variableInfo = VariableInfo.ERROR_132;
	} else if (key == ""){
		this.variableInfo = VariableInfo.ERROR_351;
	} else {*/
		this.variableInfo = this.attempt.setDirect(key, value);
//	}
	return this.variableInfo.value;
};

api_imp.prototype.GetValue = function(key){
	 if (this.state =="Not Initialized"){
		this.variableInfo = VariableInfo.ERROR_122;
	} else if (this.state =="Terminated"){
		this.variableInfo = VariableInfo.ERROR_123;
	} else if (key!=""){
		this.variableInfo=this.attempt.get(key);
	} 
	return this.variableInfo.value;
};

api_imp.prototype.LMSGetValue = api_imp.prototype.GetValue;

api_imp.prototype.Commit = function(params){
	
	if (params!=""){
		this.variableInfo= VariableInfo.ERROR_201;    
		
	} else if (this.state =="Not Initialized"){
		this.variableInfo = VariableInfo.ERROR_142;

	} else if (this.state =="Terminated"){
		this.variableInfo = VariableInfo.ERROR_143;

	} else{      
		this.valuePairs = this.attempt.printMe('cmi.');
		var params = "action=" + COMMIT_ATTEMPT + "&deliveryScoId=" + this.deliveryScoId + "&state=" + this.state + "&valuePairs=" + this.valuePairs + "&courseId=" + this.courseId ;
		if (this.bookingId){
			params = params+"&bookingId="+this.bookingId;
		}

		var nameValuePairs = this.loadXMLDoc(SCORM_CONTROLLER_URL, params);

		if (!nameValuePairs)
		{
			return this.variableInfo.value;
		}

		// set the error or recover the attempt
		var reg = new RegExp("error_code=(.*)\#message=(.*)$");
		if (nameValuePairs.match(reg)) {
			this.dealWithError(nameValuePairs);
		} else{
			this.recover(nameValuePairs);
			this.variableInfo = VariableInfo.NO_SET_ERROR;
		}

	}
   
	return this.variableInfo.value;
};

api_imp.prototype.LMSCommit = api_imp.prototype.Commit;

api_imp.prototype.Terminate = function(params){

	if (params!=""){	
		this.variableInfo= VariableInfo.ERROR_201;     	
	}else if (this.state == "Terminated"){	
		this.variableInfo= VariableInfo.ERROR_113;
	}else if (this.state == "Not Initialized"){
		this.variableInfo= VariableInfo.ERROR_112;
	}else {
		//According to the specification this should be set to "Terminated". However, if one uses that value a simple reload of a sco 
		//leads to error message popups.
		this.state = "Not Running";
		var request = this.attempt.get("adl.nav.request");
		this.valuePairs = this.attempt.printMe('cmi.');
		var params = "action=" + TERMINATE + "&deliveryScoId=" + this.deliveryScoId + "&state=" + this.state + "&valuePairs=" + this.valuePairs + "&courseId=" + this.courseId + "&navigationRequest=" + request;
		
		if (this.bookingId){
			params = params+"&bookingId="+this.bookingId;
		}
		
		var allResults = this.loadXMLDoc(SCORM_CONTROLLER_URL, params);

		if (!allResults)
		{
			return this.variableInfo.value;
		}
		//Recover name value pairs
		var nameValuePairs = allResults.substring(0, allResults.indexOf(VALUE_PAIRS_SQUENCING_DIVIDER));
		this.recover(nameValuePairs);
		//Load next page 
		var sequencingResults = allResults.substring( allResults.indexOf(VALUE_PAIRS_SQUENCING_DIVIDER) + VALUE_PAIRS_SQUENCING_DIVIDER.length, allResults.length);
		var reg = new RegExp("id=(.*)\#url=(.*)\#presentationMode=(.*)$");
		
		/*
			why happens if there is no navigation request????
		*/

		if (sequencingResults.match(reg)) {
			this.newDeliveryScoId = RegExp.$1;
			var presentationMode =RegExp.$3;
			this.code = "control_generateFrame(control_getContentFrame(), \"" + RegExp.$2 + "\" , \"FrontController.lms?slMethod=com.atl.lms.servicelayer.Service.getCourse&viewName="+control_getViewPage(presentationMode)+"&id=" + this.courseId + "\",\""+presentationMode+"\")";
			//loads page with delay, otherwise call gets overwritten
			this.variableInfo = VariableInfo.NO_SET_ERROR;
			
			// this either loads the page or not, depending is it has been loaded before from loadNewPage.html
			this.loadNewPage();

		}else {
			/*
				here we can redirect to course finish, sequencing violations, etc, depending on the error code for example:
				control_getContentFrame().location.href = misc_findHost() + "html/Course Finished.html";
			*/

			this.dealWithError(allResults);

		}

	}

	// reload the trainingplan if there is an opener
	
	if (opener && opener.top['content']){
		var courseWindow = opener.top['menu'];
		courseWindow.menu_currentCourseWindowAtTerminate();
		opener.top['content'].location = opener.top['content'].location;	
	}	
	return this.variableInfo.value;
};

api_imp.prototype.LMSFinish = api_imp.prototype.Terminate;

api_imp.prototype.GetLastError = function(){
	return this.variableInfo.errorCode;	
};

api_imp.prototype.LMSGetLastError = api_imp.prototype.GetLastError;

api_imp.prototype.GetErrorString = function(errorId){
	
	var info = eval("VariableInfo.ERROR_"+errorId);
	return this.variableInfo.errorCode;
};

api_imp.prototype.LMSGetErrorString = api_imp.prototype.GetErrorString;

api_imp.prototype.GetDiagnostic = function(param){
	return this.variableInfo.errorMessage;
};

api_imp.prototype.LMSGetDiagnostic = api_imp.prototype.GetDiagnostic;


/**
 * Gets called when request to server responds to browser.
 */
api_imp.prototype.recover = function(valuePairs){
	var arrValuePairs = valuePairs.split(VALUE_PAIR_STRING_DELIMITER);

	for (var i = 0; i < arrValuePairs.length; i++)
	{
		var key = arrValuePairs[i].substring(0, arrValuePairs[i].indexOf("="));
		var value = arrValuePairs[i].substring(arrValuePairs[i].indexOf("=") + 1, arrValuePairs[i].length);
		this.SetValueDirect(key, value);

		if (this.GetLastError().toString() != "0")
		{
			if(debug>1){
				alert("Error(" + this.GetLastError().toString() + ") on recovery:" + key +"/" + value);
			}
		}
	}
};


/**
 * Methods for api state handling.
 */

/**
 * Executes XML HTTP Request to Sequencing controller in order to identify next content object for delivery.
 */
api_imp.prototype.launchSco = function(navigationRequest, courseId, bookingId) {
	if (courseId) { this.courseId = courseId; }
	if (bookingId) { this.bookingId = bookingId; }
	var params = "action=" + SEQUENCE + "&navigationRequest=" + navigationRequest + "&courseId=" + this.courseId+"&bookingId="+this.bookingId;
	var results = this.loadXMLDoc(SCORM_CONTROLLER_URL, params);

	if (results.match(/^id=(.*)\#url=(.*)\#presentationMode=(.*)\#courseId=(.*)\#bookingId=(.*)$/)) {
		var presentationMode = RegExp.$3;
		this.newDeliveryScoId = RegExp.$1;		
//		alert("delivery sco: "+RegExp.$1+"\nthis.courseId: "+this.courseId+"\nurl: "+RegExp.$2);
		control_generateFrame(control_getContentFrame(), RegExp.$2, "FrontController.lms?slMethod=com.atl.lms.servicelayer.Service.getCourse&viewName="+control_getViewPage(presentationMode)+"&id=" + this.courseId, presentationMode);
	}
	else {
		if (results != "")
		{
			if(debug>0){
				alert("Sequencing Results: " + results);
			}
		}
		else if (request != "_none_")
		{
			var url = misc_findHost() + "html/nocontent.html";
			top.location.href = url;
		}
	}
}



/**
 * Methods for api state handling.
 */

/**
 * Executes XML HTTP Request to Sequencing controller in order to identify next content object for delivery.
 */
api_imp.prototype.launchScoForCOCourseId = function(navigationRequest, contentObjectCourseId) {
	
	
	var params = "action=" + LAUNCH_SCO_FROM_SCO + "&navigationRequest=" + navigationRequest + "&contentObjectCourseId=" + contentObjectCourseId;
	var results = this.loadXMLDoc(SCORM_CONTROLLER_URL, params);
	
	this.bookingId = null;
	
	if (results.match(/^id=(.*)\#url=(.*)\#presentationMode=(.*)\#courseId=(.*)\#bookingId=(.*)$/)) {
		this.newDeliveryScoId = RegExp.$1;	
		this.courseId=RegExp.$4;
		this.bookingId=RegExp.$5;
		var presentationMode = RegExp.$3;
		this.code = "control_generateFrame(control_getContentFrame(), \"" + RegExp.$2 + "\" , \"FrontController.lms?slMethod=com.atl.lms.servicelayer.Service.getCourse&viewName="+control_getViewPage(presentationMode)+"&id=" + this.courseId + "\",\""+presentationMode+"\")";
		this.loadNewPage();
//		control_generateFrameWithHost(control_getContentFrame(), RegExp.$2, "FrontController.lms?slMethod=com.atl.lms.servicelayer.Service.getCourse&viewName="+control_getViewPage(presentationMode)+"&id=" + this.courseId, presentationMode);
	}
}

/**
 * Methods for api state handling.
 */

/**
 * Executes XML HTTP Request to Sequencing controller in order to identify next content object for delivery.
 */
api_imp.prototype.launchScoForContentObjectLink = function(navigationRequest, contentObjectCourseId) {
	
	
	var params = "action=" + LAUNCH_SCO_FROM_SCO + "&navigationRequest=" + navigationRequest + "&contentObjectCourseId=" + contentObjectCourseId;
	var results = this.loadXMLDoc(SCORM_CONTROLLER_URL, params);
	
	this.bookingId = null;
	
	if (results.match(/^id=(.*)\#url=(.*)\#presentationMode=(.*)\#courseId=(.*)\#bookingId=(.*)$/)) {
		this.newDeliveryScoId = RegExp.$1;	
		this.courseId=RegExp.$4;
		this.bookingId=RegExp.$5;
		var presentationMode = RegExp.$3;
		control_generateFrame(control_getContentFrame(), RegExp.$2, "FrontController.lms?slMethod=com.atl.lms.servicelayer.Service.getCourse&viewName="+control_getViewPage(presentationMode)+"&id=" + this.courseId, presentationMode);
	}
}


/**
 * Launches new sco into new window
 */
api_imp.prototype.launchScoInNewWindow = function(scoIdentifier, url, courseId) {
	this.newDeliveryScoId = scoIdentifier;
	window.open(url,'content','width=800,height=600');
	this.courseId = courseId;
}


/**
 * XML HTTP Communication
 */

var XML_HTTP_REQUEST = null;

api_imp.prototype.loadXMLDoc = function (url, params) {
	//alert("sending request to:" + url + " with params:" + params);
	try
	{

		if (window.XMLHttpRequest) {
			XML_HTTP_REQUEST = new XMLHttpRequest();
		} else if (window.ActiveXObject) {
			XML_HTTP_REQUEST = new ActiveXObject("Microsoft.XMLHTTP");
		}


		if (XML_HTTP_REQUEST != null) {

			
			XML_HTTP_REQUEST.open("POST", url, false);
			XML_HTTP_REQUEST.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
			XML_HTTP_REQUEST.send(encodeURI(params));

			return XML_HTTP_REQUEST.responseText;	
			
		} else {
			return "error_code=ERROR_101#message=XML_HTTP_REQUEST initialisation failed";
		}


	} catch(e) {

		if (debug>0){
			alert(e);
		}
		
		// TODO return an error here
		this.variableInfo = VariableInfo.ERROR_101;
		alert("There was an error connecting to the server. The information you supplied has not been recorded. \nPlease check your internet connection and try again.");
		return null;
		
	}
};

api_imp.prototype.showErrorPage = function (errorPage){

	if (!errorPage)
	{
		errorPage = "html/error.html?test=piss";
	}
	
	var code = "control_getContentFrame().location.href = misc_findHost()+'"+ errorPage+"'";

	window.setTimeout(code, 200);	


};


/*
	Recorvers an error send from the ScormController
*/
api_imp.prototype.recoverError = function(param){

		var error_code;
		var message;

		var reg = new RegExp("error_code=(.*)\#message=(.*)$");
		if (param.match(reg)) {
			error_code = RegExp.$1;
			message =RegExp.$2;
		}

		return this.getErrorVariable(error_code,message);

};

api_imp.prototype.getErrorVariable = function(error_code, message){		
		
		var info;
		if (error_code)
		{
			info = eval("VariableInfo."+error_code);
			
			if (message){						
				info.errorMessage = message;
			}		
			
		}
	
		return info;
		
};


api_imp.prototype.dealWithError = function(allResults){

	this.variableInfo = this.recoverError(allResults);
	if (debug>0){
		this.variableInfo.printMe();
	}

	if (this.variableInfo.errorCode!="0"){
		this.showErrorPage();
	}

};
api_imp.prototype.loadNewPage = function(allResults){
	window.setTimeout(this.code, 1);
	this.code="";
}


api_imp.prototype.showTestInNewWindow = function(variable, companyCss, currentLanguage){

	var testWindow =window.open();
	var fileref = window.document.createElement("script");
	fileref.setAttribute("language", "javascript");
	fileref.setAttribute("src", "course/AttemptJS/localisation/text_"+currentLanguage+".js");
	window.document.getElementsByTagName("head").item(0).appendChild(fileref);


	variable =	unescape(variable);
	variable = misc_replaceAll(variable,"B_S15"," ");
	variable = misc_replaceAll(variable,"\n"," ");
	variable = misc_replaceAll(variable,"\r"," ");

	var testSummaryPage = eval(variable);
	

	var t = new TestHtmlTranslator();
	testWindow.document.write("<html><body dir=\""+(currentLanguage=="ar"? "rtl":"ltr")+"\"><head>");
	testWindow.document.write("<link rel=\"stylesheet\" type=\"text/css\" href=\""+companyCss+"\"></head>");
	
	testWindow.document.write("<div style=\"padding-left: 20px;\">");
	
	testWindow.document.write(t.recreateTest(testSummaryPage));
	testWindow.document.write("</div>");
	testWindow.document.write("</body></html>");
	testWindow.document.close();

};


