// --------------------------------------------------------------------------------------
// Javascript SCORM Library v1.0 --------------------------------------------------------
// David Storey - 16th May 2008 ---------------------------------------------------------
// Compatible with both SCORM 1.2 and 2004 ----------------------------------------------
// Uses code originally by Mike Rustici (http://www.scorm.com) --------------------------
// Uses code originally by Phil Hutchison (http://pipwerks.com) -------------------------
// --------------------------------------------------------------------------------------

// --------------------------------------------------------------------------------------
// Core SCORM Functions
// --------------------
// SCORM_init()
// SCORM_terminate()
// SCORM_commit()
// SCORM_getValue(variable)
// SCORM_setValue(variable, value)
// SCORM_getError()
//
// Handy SCORM Functions
// ---------------------
// startScorm() - bundles startTimer(), getApi() and SCORM_init()
// endScorm() - bundles endTimer(), SCORM_commit() and SCORM_terminate()
//
// SCORM_getLocation()
// SCORM_getStudentId()
// SCORM_getStudentName()
// SCORM_getStatus()
// SCORM_getSuccessStatus()
// SCORM_getScore()
// SCORM_getMinScore()
// SCORM_getMaxScore()
// SCORM_getSessionTime()
// SCORM_getTotalTime()
//
// SCORM_setLocation(value)
// SCORM_setComplete()
// SCORM_setIncomplete()
// SCORM_setSuccessStatus(value)
// SCORM_setScore(value)
// SCORM_setMinScore(value)
// SCORM_setMaxScore(value)
// SCORM_setSessionTime(value)
// --------------------------------------------------------------------------------------


var AUTOSCORM  = 0;
var SCORM_1_2  = 1;
var SCORM_2004 = 2;

var SCORM_version = AUTOSCORM;

var SCORM_API       = null;
var SCORM_available = false;
var SCORM_active    = false;




// --------------------------------------------------------------------------------------
// SCORM API FINDER FUNCTIONS -----------------------------------------------------------
// --------------------------------------------------------------------------------------

var MAX_PARENTS_TO_SEARCH = 500;

//scanParentsForApi -Searches all the parents of a given window until it finds an object named "API_1484_11". If an object of that name is found, a reference to it is returned. Otherwise, this function returns null.
function scanParentsForApi(win) {
	//Establish an outrageously high maximum number of parent windows that we are will to search as a safe guard against an infinite loop. This is probably not strictly necessary, but different browsers can do funny things with undefined objects.

	var nParentsSearched = 0;

	// Search each parent window until we either: -find the API, -encounter a window with no parent (parent is null or the same as the current window) -or, have reached our maximum nesting threshold
	try {
		while ((win.API == null && win.API_1484_11 == null) && (win.parent != null) && (win.parent != win) && (nParentsSearched <= MAX_PARENTS_TO_SEARCH)) {
			nParentsSearched++;
			win = win.parent;
		}
	} catch (error) { return null; }

	// If the API doesn't exist in the window we stopped looping on, then this will return null.
	switch(SCORM_version) {
		case AUTOSCORM:
			if (win.API) {
				SCORM_version = SCORM_1_2;
				return win.API;
			} else if (win.API_1484_11) {
				SCORM_version = SCORM_2004;
				return win.API_1484_11;
			} else {
				return null;
			}
		break;

		case SCORM_1_2:
			return win.API;
			break;

		case SCORM_2004:
			return win.API_1484_11;
			break;

		default:
			return null;
			break;
	}
}


// getAPI -Searches all parent and opener windows relative to the current window for the SCORM 2004 API Adapter. Returns a reference to the API Adapter if found or null otherwise.
function getApi() {
	var API = null;

	//Search all the parents of the current window if there are any
	if ((window.parent != null) && (window.parent != window)) {
		API = scanParentsForApi(window.parent);
	}

	// If we didn't find the API in this window's chain of parents, then search all the parents of the opener window if there is one
	if ((API == null) && (window.top.opener != null)) {
		API = scanParentsForApi(window.top.opener);
	}

	return API;
}




// --------------------------------------------------------------------------------------
// CORE SCORM FUNCTIONS -----------------------------------------------------------------
// --------------------------------------------------------------------------------------

function SCORM_init() {
	if (SCORM_available && !SCORM_active) {
		switch (SCORM_version) {
			case SCORM_1_2:
				SCORM_API.LMSInitialize("");
				SCORM_active = true;
				break;
			
			case SCORM_2004:
				SCORM_API.Initialize("");
				SCORM_active = true;
				break;
		}
	}
}


function SCORM_terminate() {
	if (SCORM_active) {
		switch (SCORM_version) {
			case SCORM_1_2:
				SCORM_API.LMSFinish("");
				SCORM_active = false;
				break;
			
			case SCORM_2004:
				SCORM_API.Terminate("");
				SCORM_active = false;
				break;
		}
	}
}


function SCORM_commit() {
	if (SCORM_active) {
		switch (SCORM_version) {
			case SCORM_1_2:
				SCORM_API.LMSCommit("");
				break;
			
			case SCORM_2004:
				SCORM_API.Commit("");
				break;
		}
	}
}


function SCORM_getValue(variable) {
	var value = "";

	if (SCORM_active) {
		switch (SCORM_version) {
			case SCORM_1_2:
				value = SCORM_API.LMSGetValue(variable);
				break;
			
			case SCORM_2004:
				value = SCORM_API.GetValue(variable);
				break;
		}
	}

	if (value == "" || value == 0 || value == "0" || value == null) value = "";

	return value;
}


function SCORM_setValue(variable, value) {
	if (SCORM_active) {
		switch (SCORM_version) {
			case SCORM_1_2:
				SCORM_API.LMSSetValue(variable, value);
				break;
			
			case SCORM_2004:
				SCORM_API.SetValue(variable, value);
				break;
		}
	}
}


function SCORM_getError() {
	var scormVerson = "";
	var errorCode   = "";
	var errorString = "";
	var errorDetail = "";
	
	if (SCORM_active) {
		switch (SCORM_version) {
			case SCORM_1_2:
				errorCode   = SCORM_API.LMSGetLastError();
				errorString = SCORM_API.LMSGetErrorString(errorCode);
				errorDetail = SCORM_API.LMSGetDiagnostic(errorCode);
				break;
			
			case SCORM_2004:
				errorCode   = SCORM_API.GetLastError();
				errorString = SCORM_API.GetErrorString(errorCode);
				errorDetail = SCORM_API.GetDiagnostic(errorCode);
				break;
		}
		
		var displayString = "SCORM " + scormVersion + " ERROR: \n";
		displayString += errorCode + ": " + errorString + " \n";
		displayString += errorDetail + " \n";
		
		logError(displayString);
		showErrorLog();
	}
}




// --------------------------------------------------------------------------------------
// HANDY SCORM FUNCTIONS ----------------------------------------------------------------
// --------------------------------------------------------------------------------------

function startScorm() {
	if (!SCORM_active) {
		startTimer();
		
		SCORM_API = getApi();
		
		if (SCORM_API == null) SCORM_available = false;
		else SCORM_available = true;
		
		SCORM_init();
	}
}


function endScorm() {
	if (SCORM_active) {
		SCORM_setSessionTime(endTimer());
		SCORM_commit();
		SCORM_terminate();
		SCORM_API = null;
	}
}

// --------------------------------------------------------------------------------------


function SCORM_getLocation() {
	var value = "";
	
	switch (SCORM_version) {
		case SCORM_1_2:
			value = SCORM_getValue("cmi.core.lesson_location");
			break;
		
		case SCORM_2004:
			value = SCORM_getValue("cmi.location");
			break;
	}
	
	if (value == "") value = "0";
	return value;
}


function SCORM_getStudentId() {
	var value = "";
	
	switch (SCORM_version) {
		case SCORM_1_2:
			value = SCORM_getValue("cmi.core.student_id");
			break;
		
		case SCORM_2004:
			value = SCORM_getValue("cmi.learner_id");
			break;
	}
	
	return value;
}


function SCORM_getStudentName() {
	var value = "";
	
	switch (SCORM_version) {
		case SCORM_1_2:
			value = SCORM_getValue("cmi.core.student_name");
			break;
		
		case SCORM_2004:
			value = SCORM_getValue("cmi.learner_name");
			break;
	}
	
	return value;
}


function SCORM_getStatus() {
	var value = "";
	
	switch (SCORM_version) {
		case SCORM_1_2:
			value = SCORM_getValue("cmi.core.lesson_status");
			break;
		
		case SCORM_2004:
			value = SCORM_getValue("cmi.completion_status");
			break;
	}

	if (value == "") value = "incomplete";
	return value;
}


function SCORM_getSuccessStatus() {
	var value = "";
	
	switch (SCORM_version) {
		case SCORM_1_2:
			break;
		
		case SCORM_2004:
			value = SCORM_getValue("cmi.success_status");
			break;
	}

	if (value == "") value = "unknown";
	return value;
}


function SCORM_getScore() {
	var value = "";
	
	switch (SCORM_version) {
		case SCORM_1_2:
			value = SCORM_getValue("cmi.core.score.raw");
			break;
		
		case SCORM_2004:
			value = SCORM_getValue("cmi.score.raw");
			break;
	}
	
	if (value == "") value = "0";
	return value;
}


function SCORM_getMinScore() {
	var value = "";
	
	switch (SCORM_version) {
		case SCORM_1_2:
			value = SCORM_getValue("cmi.core.score.min");
			break;
		
		case SCORM_2004:
			value = SCORM_getValue("cmi.score.min");
			break;
	}
	
	if (value == "") value = "0";
	return value;
}


function SCORM_getMaxScore() {
	var value = "";
	
	switch (SCORM_version) {
		case SCORM_1_2:
			value = SCORM_getValue("cmi.core.score.max");
			break;
		
		case SCORM_2004:
			value = SCORM_getValue("cmi.score.max");
			break;
	}
	
	if (value == "") value = "100";
	return value;
}


function SCORM_getSessionTime() {
	var value = "";
	
	switch (SCORM_version) {
		case SCORM_1_2:
			value = SCORM_getValue("cmi.core.session_time");
			break;
		
		case SCORM_2004:
			value = SCORM_getValue("cmi.session_time");
			break;
	}
	
	if (value == "") value = "00:00:00";
	return value;
}


function SCORM_getTotalTime() {
	var value = "";
	
	switch (SCORM_version) {
		case SCORM_1_2:
			value = SCORM_getValue("cmi.core.total_time");
			break;
		
		case SCORM_2004:
			value = SCORM_getValue("cmi.total_time");
			break;
	}
	
	if (value == "") value = "00:00:00";
	return value;
}


// --------------------------------------------------------------------------------------


function SCORM_setLocation(value) {
	switch (SCORM_version) {
		case SCORM_1_2:
			SCORM_setValue("cmi.core.lesson_location", value);
			break;
		
		case SCORM_2004:
			SCORM_setValue("cmi.location", value);
			break;
	}
}


function SCORM_setComplete() {
	switch (SCORM_version) {
		case SCORM_1_2:
			SCORM_setValue("cmi.core.lesson_status", "completed");
			break;
		
		case SCORM_2004:
			SCORM_setValue("cmi.completion_status", "completed");
			break;
	}
}


function SCORM_setIncomplete() {
	if (SCORM_getStatus().substring(0,1).toLowerCase() != "c") {
		switch (SCORM_version) {
			case SCORM_1_2:
				SCORM_setValue("cmi.core.lesson_status", "incomplete");
				break;
			
			case SCORM_2004:
				SCORM_setValue("cmi.completion_status", "incomplete");
				break;
		}
	}
}


function SCORM_setSuccessStatus(value) {
	switch (SCORM_version) {
		case SCORM_1_2:
			break;
		
		case SCORM_2004:
			SCORM_setValue("cmi.success_status", value);
			break;
	}
}


function SCORM_setScore(value) {
	switch (SCORM_version) {
		case SCORM_1_2:
			SCORM_setValue("cmi.core.score.raw", value);
			break;
		
		case SCORM_2004:
			SCORM_setValue("cmi.score.raw", value);
			break;
	}
}


function SCORM_setMinScore(value) {
	switch (SCORM_version) {
		case SCORM_1_2:
			SCORM_setValue("cmi.core.score.min", value);
			break;
		
		case SCORM_2004:
			SCORM_setValue("cmi.score.min", value);
			break;
	}
}


function SCORM_setMaxScore(value) {
	switch (SCORM_version) {
		case SCORM_1_2:
			SCORM_setValue("cmi.core.score.max", value);
			break;
		
		case SCORM_2004:
			SCORM_setValue("cmi.score.max", value);
			break;
	}
}


function SCORM_setSessionTime(value) {
	switch (SCORM_version) {
		case SCORM_1_2:
			SCORM_setValue("cmi.core.session_time", value);
			break;
		
		case SCORM_2004:
			SCORM_setValue("cmi.session_time", value);
			break;
	}
}




// --------------------------------------------------------------------------------------
// COMMON FUNCTIONS ---------------------------------------------------------------------
// --------------------------------------------------------------------------------------

var startTime;

function startTimer() {
	var theDate = new Date();
	startTime = theDate.getTime();
}


function endTimer() {
	var theDate = new Date();
	endTime = theDate.getTime();
	var seconds = Math.round(Math.ceil(endTime - startTime) / 1000);
	var minutes = 0;
	var hours = 0;
	while (seconds > 59) {
		seconds = seconds - 60;
		minutes = minutes + 1;
		if (minutes > 59) {
			minutes = 0;
			hours = hours + 1;
		}
	}
	var h = "" + hours;
	var m = "" + minutes;
	var s = "" + seconds;
	if ( hours < 10 ) h = "0" + hours;
	if ( minutes < 10 ) m = "0" + minutes;
	if ( seconds < 10 ) s = "0" + seconds;
	var timeTaken = h + ":" + m + ":" + s;

	return timeTaken;
}
