﻿/**************************************************************************************

	Description: 
		Contains a Javascript implementation that logs using the HACP protocol.
		The implementation requires an ASP file on the server called AICCProxy.asp
		that can redirect calls to the lms to avoid cross-domain scripting issues.

**************************************************************************************/

/*
	Create a new AICC LMS Object
*/
var AICCApi = new AICCLMS(location.search);

if(!AICCApi.LMSDetected())
{
	AICCApi = null;
}

/*
	Constructor for creating an AICC LMS
*/
function AICCLMS(aiccparams)
{
	// Values for AICC
	this.AICC_url = null;
	this.AICC_sid = null;	
	
	// Values for tracking time
	this.startTime = new Date();   
	this.endTime = new Date(); 		
	
	// Student data
	this.StudentId = null;
	this.StudentName = null;	
	this.LessonStatus = null;
	
	/*
		Initializes the AICCLMS object. This involves setting up the runtime environment
	*/
	this.initializeLms = function(aiccparams)
	{
		// Check for AICC/HACP usage. This is found by checking the querystring for
		// the parameters aicc_url and aicc_sid (session id)	
		aiccparams = new QueryString();
		
		this.AICC_url = aiccparams.getValue("aicc_url");
		this.AICC_sid = aiccparams.getValue("aicc_sid");
		
		// debug div
		document.write("<div id=\"debug\" style=\"height:320px;width:160px;");
		document.write("overflow:scroll;border:solid 1px #E0E0E0;");
		document.write("font-family:courier new;font-size:8px;display:none\">&nbsp;</div>");		
		
		this.debug("URL: " + this.AICC_url);
		this.debug("SID: " + this.AICC_sid);				
		
		// communication
		this.httpReq = this.createHttpRequestObject();	
		
		// read important settings
		this.getData();	
	}
		
	/*
		Logs an interaction		
	*/
	this.addInteraction = function(id, type, correct, response, result, latency)
	{
		this.debug(id + ", " + type + ", " + correct + ", " + response + ", " + 
			result + ", " + latency);
			
		this.putInteraction(id, type, correct, response, result, latency);
	}
	
	/*
		Initializes the course with the LMS
	*/
	this.initialize = function(timeOfInit)
	{
		this.startTime = timeOfInit;
		
		this.debug("initialize(" + timeOfInit.toString() + ")");
		
		this.setScoreAndCompletion(0, "incomplete");
	}
	
	/*
		Marks the course as completed
	*/
	this.courseCompleted = function()
	{
		this.debug("courseCompleted()");
		this.putParam("completed", null, this.trackTime());
	}
	
	/*
		Sets the completion status for the course
	*/
	this.setCompletion = function(completion)
	{
		this.debug("setCompletion(" + completion + ")");	
		this.putParam(completion, null, this.trackTime())		
	}
	
	/*
		Sets the score for the course
	*/
	this.setScore = function(score)
	{
		this.debug("setScore(" + score + ")");
		this.putParam(null, score, this.trackTime())
	}
	
	/*
		Sets the score and completion status for the course
	*/
	this.setScoreAndCompletion = function(score, completion)
	{
		this.debug("setScoreAndCompletion(" + score + ", " + completion + ")");		
		this.putParam(completion, score, this.trackTime()) 
	}
	
	/*
		Finish the session in the lms
	*/
	this.finish = function()
	{
		this.debug("finish()");
		
		// Call exit system
		this.exitSystem(this.trackTime());
	}
	
	/*
		Save suspend data in the lms	
	*/
	this.suspendCourse = function(location, data)
	{
		this.debug("suspendCourse(" + location + ", " + data + ")");		
	}
	
	/*
		Writes out a debug message
	*/
	this.debug = function(txt)
	{
		if(!this.debugDiv)		
			this.debugDiv = document.getElementById('debug');						
		
		if(this.debugDiv && this.debugDiv.style.display != 'none')		
		{	
			this.debugDiv.innerHTML = (this.debugDiv.innerHTML == "&nbsp;" ? "" :
				this.debugDiv.innerHTML) + txt + "<br>";
		}
	}
		
	/*
		Returns the AICC formated time when tracking. Formats the date and time 
		so it can be read by the LMS
	*/
	this.trackTime = function()
	{
		var Time, Minutes, sendInfo; 	
		
		// Get the time when they finish the topic 
		this.endTime = new Date(); 
		var Time = Math.floor((this.endTime.getTime() - this.startTime.getTime()) / 1000); 
		
		// Find the difference 
		var Minutes = Math.floor(Time / 60); 
		Time = this.padNumber(Math.floor(Minutes / 60)) + ":" + this.padNumber(Minutes % 60) + ":" +  

		this.padNumber(Time % 60); 
		
		return Time; 
		
	} 

	/*  
		Adds padding to numbers so that they always equals two characters 
	*/ 
	this.padNumber = function(num) 
	{ 
		if (num < 10) 
			return "0" + num; 
		else 
			return num; 
	} 


	/*
		Returns true if the content was called by an LMS running AICC
	*/
	this.LMSDetected = function()
	{
		var Detected = (this.AICC_sid && this.AICC_url) &&
			(this.AICC_sid.length > 0 && this.AICC_url.length > 0);
			
		return (Detected ? true : false);
	}

	/*
		Sends a putparam command to the LMS via AICC/HACP
	*/
	this.putParam = function(lessonStatus, score, time) 
	{ 
		// created aicc_data parameter 
		var aiccData= '[CORE]'; 
		
		if(lessonStatus && this.LessonStatus && this.LessonStatus.length > 0 &&
			this.LessonStatus.charAt(0) != 'c' && this.LessonStatus.charAt(0) != 'p')
			aiccData += '\nLESSON_STATUS=' + lessonStatus; 
			
		if(score)
			aiccData += '\nSCORE=' + score; 
					
		aiccData += '\nTIME=' + time; 

		this.sendData("putParam", aiccData);
	} 
	
	/*
		Sends a putinteraction command to the LMS via AICC/HACP
	*/
	this.putInteraction = function(id, type, correct, response, result, latency)
	{ 
		// created aicc_data parameter 
		var aiccData = "\"course_id\", \"student_id\", \"lesson_id\", \"date\", \"time\"," + 
			"\"interaction_id\",\"objective_id\", \"type_interaction\",\"correct_response\"," + 
			"\"student_response\", \"result\", \"weighting\", \"latency\"\r\n";

		aiccData += ", this.StudentId, , , , " + 
			id + ", \"\", \"" + type + "\", \"" + 
			correct + "\", \"" + response + "\", \"" + result + "\",, " + latency;

		// ex: A340ft-2","jqh085","APU1","2004/01/15","15:14:23",37,ft1016,C,A,C,W,, 00:00:3 

		this.sendData("putInteractions", aiccData);
	} 

	/*
		Sends the ExitAU command to the LMS
	*/
	this.exitSystem = function(time) 
	{ 
		// created aicc_data parameter 
		var aiccData= '[CORE]'; 
		aiccData += '\nTIME=' + time; 
		
		this.sendData("ExitAU", aiccData);   
	} 

	/*
		Sends data to the LMS via AICC/HACP
	*/
	this.sendData = function(command, aiccdata) 
	{ 
		if(this.LMSDetected())
		{
			// Send request
			this.parseResults(this.sendHttpRequest(command, aiccdata));
		}
	} 

	/*
		reads data from the AICC LMS
	*/
	this.getData = function () 
	{ 	
		
		if(this.LMSDetected())
		{
			this.parseResults(this.sendHttpRequest("getparam", ""));
		}
	} 
	
	/*
		Callback whenever we recieve result back from our proxy on the server
	*/
	this.parseResults = function(result)
	{
		if(!result)
			return;
		
		// Parse results
		result = this.unescapeex(result);	
		var ResultList = result.split('\r')	
		
		// Loop through all the lines and split them
		for(var i = 0; i< ResultList.length; i++)
		{
			var NameValue = ResultList[i].split('=');
			
			if(NameValue.length == 2)
			{
				var Name = this.trim(NameValue[0]).toLowerCase();
				var Val = this.trim(NameValue[1]).toLowerCase();
							
				if(Val)
				{
					switch(Name)
					{
						case "student_id":			
							this.StudentId = Val;
							break;
							
						case "student_name":
							this.StudentName = Val;
							break;
							
						case "lesson_status":
							this.LessonStatus = Val;
							break;
												
					}
				}
			}
		}	
		
		// Add to debug:
		this.debug("Student ID:   " + this.StudentId);
		this.debug("Student Name: " + this.StudentName);									
		this.debug("LessonStatus: " + this.LessonStatus);
	}

	/*
		Callback from the ASP proxy whenever a communication error occurs.
	*/
	this.AICCResultError = function (errno, description)
	{		
		debug('err: ' & description);
	}	

	/*
		Creates the HttpRequest Object
	*/
	this.createHttpRequestObject = function()
	{
		var A = null;
	
		try
		{
			A = new ActiveXObject("Msxml2.XMLHTTP")
		}
		catch(e)
		{
			try
			{
				A = new ActiveXObject("Microsoft.XMLHTTP")
			} 
			catch(ex)
			{
				A = null
			}
		}
		
		if(!A && typeof XMLHttpRequest != "undefined") 
		{
			A = new XMLHttpRequest()
		}
		
		return A;
	}	
	
	/*
		Sends a Http Request and returns the results
	*/
	this.sendHttpRequest = function(command, aicc_data)
	{		
		if(this.httpReq)
		{		
			// Create the URL:
			var aicc_url = escape(this.AICC_url) + (this.AICC_url.indexOf("?") > -1 ? "" : "?");
			var url = "./../../SCORM/AICCProxy.asp?aicc_url=" + aicc_url + "&";
			url += "session_id=" + escape(this.AICC_sid) + "&";
			url += "command=" + escape(command) + "&";
			url += "aicc_data=" + escape(aicc_data) + "&";
			url += "version=1.0";
			
			// Call the logger.asp file
			this.httpReq.open("GET", url, false);
						
			// Send!
			this.httpReq.send();					
			
			this.debug("Result:");
			this.debug(this.httpReq.responseText);
			
			// Return the result from the request
			return this.httpReq.responseText;
		}
	}

	/*
		trims a string
	*/
	this.trim = function(str) 
	{
		return str.replace(/^\s+|\s+$/g,"");
	}

	/*
		extended replace to handle + signs
	*/
	this.unescapeex = function(str) 
	{
		return unescape(str).replace(/\+/g, " ");
	}


		
	// Initialize
	this.initializeLms(aiccparams);	
	
}

/*
	Creates a parsed querystring object
*/
function QueryString() 
{
	q = location.search;
	
	if(q.length > 1) 
		this.q = q.substring(1, q.length);
	else 
		this.q = null;
	
	this.keyValuePairs = new Array();
	
	if(this.q) 
	{		
		for(var i=0; i < this.q.split("&").length; i++) 
		{
			this.keyValuePairs[i] = this.q.split("&")[i];			
		}
	}
	
	this.getKeyValuePairs = function() 
	{ 
		return this.keyValuePairs; 
	}
	
	this.getValue = function(s) 
	{		
		for(var j=0; j < this.keyValuePairs.length; j++) 
		{
			if(this.keyValuePairs[j].split("=")[0].toLowerCase() == s.toLowerCase())
			{
				var temp = this.keyValuePairs[j].split("=");				
				var res = "";
				
				for(var n = 1; n < temp.length; n++)
					res += (res == "" ? "" : "=") + temp[n];
					
				return res;
			}
		}
		return -1;
	}
	
	this.getParameters = function() 
	{
		var a = new Array(this.getLength());
		
		for(var j=0; j < this.keyValuePairs.length; j++) 
		{
			a[j] = this.keyValuePairs[j].split("=")[0];
		}
		return a;
	}
	
	this.getLength = function() { return this.keyValuePairs.length; }	
}
