//these four variables, along with the two functions ScanForAPI and
//GetAPI are given in then SCORM documentation as the recommended 
//way of locating the API in either an opener or parent window

var nFindAPITries = 0; 
var API = null; 
var maxTries = 500; 
var APIVersion = "";

var STR_SETTING 	= "setting ";
var STR_SCORERAW 	= "cmi.core.score.raw";
var STR_SCOREMAX	= "cmi.core.score.max";
var STR_LESSONSTATUS= "cmi.core.lesson_status";
var STR_EXIT		= "cmi.core.exit";
var STR_WITHVALUE	= " with value ";

function ScanForAPI(win) {
	while ((win.API == null) 
	&& (win.parent != null) 
	&& (win.parent != win)) {
		nFindAPITries++;
		if (nFindAPITries > maxTries) {
			alert("Error in finding API instance -- too deeply nested."); 
			return null;
		} 
		win = win.parent;
	} return win.API;
}

function GetAPI() {
	if ((window.parent != null) && (window.parent != window)) { 
		API = ScanForAPI(window.parent); 
	} 
	if ((API == null) && (window.opener != null)) { 
		API = ScanForAPI(window.opener); 
	} 
}

//Here are two utilities: one to handle error-checking and one to 
//find whether the LMS supports a particular data field. This
//function should be called after every call to the API

function scormCheckError(context) {
	var errorCode = API.LMSGetLastError();
	if (errorCode != 0) {
		alert("Error " + context + ": " + API.LMSGetErrorString(errorCode));
	}
}

//scormFindChild is a utility which checks to see whether the value
//child exists within the comma-separated list of children. Some data
//fields do not have to be supported by an LMS. This is the way of 
//checking whether a feature is supported before using it. 
//See scormClose() for the use of this function.
function scormFindChild(childElement, child) {
	var isFound = false;
	var children = API.LMSGetValue(childElement);
	var childArray = new Array();
	childArray = children.split(",");
	scormCheckError("getting children for " + children);
	for (var i=0; (i<childArray.length); i++) {
		if (childArray[i] == child) {
			isFound = true;
			break;
		}
	}
	return isFound;
}


//here is code to support our assessment model. If an API object is
//found, LMSInitialize must be called first and LMSFinish last. You
//will normally call LMSCommit before LMSFinish to ensure that all
//values are persisted. In between these, we may call LMSSetValue,
//to pass data back to the LMS, LMSGetValue to read data from the
//LMSGetLastError and LMSGetErrorString if things go wrong. We will
//use three functions: ScormInitialize to get things going, ScormCommand to
//deal with the fscommand events occurring in the Flash animation, and
//ScormClose to tidy up at the end.

//ScormClose might be called in one of two ways: (a) when the Flash 
//movie finishes and issues an fscommand("finish", ""); or if the student
//closes the browser window before finishing. To avoid calling ScormClose //twice, we need to track whether our scorm session is active. 

var scormActive = false;

//these variables will keep track of the student's progress through the SCO
var marksTotal;	//will be set in the SCO's html
var marksDone = 0;
var marksScored = 0;
var scormStatus = "not attempted";
var marksReturned = false;

//scormStart() will get called whenever our html page loads
function scormStart() {
	GetAPI();
	if (API != null) {
		API.LMSInitialize("");
		scormCheckError("initializing API");
		scormActive = true;
		//we might load bookmarking information here, but we'll leave that for
		//next time
	}
}

//scormClose will get called at the end, either when the movie finishes or
//when the student closes the window without finishing the movie. We will
//return some minimum information: score, status, exit and marksDone. These //fields are all mandatory fields for the LMS, except for core.score.max, 
//Before returning core.score.max we need to find whether this is supported //by the LMS
function scormClose() {
	if (scormActive) {
		//prevent closing twice
		scormActive = false;
		//return normalized score
		if (marksTotal > 0) {
			//under SCORM 1.2, raw score is always returned as a 
			//normalized percentage
			alert("Setting scoreRaw: marksScored = " + marksScored + "; marksTotal = " + marksTotal);
			var scoreRaw = (marksScored / marksTotal) * 100;
			alert("ScoreRaw = " + scoreRaw);
			API.LMSSetValue(STR_SCORERAW, scoreRaw);
			scormCheckError(STR_SETTING + STR_SCORERAW + STR_WITHVALUE + scoreRaw);
		}
		//return max score (what the student could have scored if he got all
		//questions presented right
		if ((marksTotal > 0) && (scormFindChild("cmi.core.score._children", "max"))) {
			var maxScore = (marksScored / marksTotal) * 100;
			alert("maxScore = " + maxScore);
			API.LMSSetValue(STR_SCOREMAX, maxScore);
			scormCheckError(STR_SETTING + STR_SCOREMAX + STR_WITHVALUE + maxScore);
		}
		//set lesson_status
		if (marksReturned) {
			if (marksDone = marksTotal) {
				scormStatus = "completed";
			} else {
				scormStatus = "incomplete";
			}
		} else {
			scormStatus = "browsed";
		}
		API.LMSSetValue(STR_LESSONSTATUS, scormStatus);
		scormCheckError(STR_SETTING + STR_LESSONSTATUS + STR_WITHVALUE + scormStatus);
		//set normal exit
		API.LMSSetValue("cmi.core.exit", "");
		scormCheckError(STR_SETTING + STR_EXIT + STR_WITHVALUE);
		API.LMSCommit("");
		scormCheckError("committing to API");
		API.LMSFinish("");
		scormCheckError("finishing SCORM session");
	}
}

//scormCommand will deal with the fscommand messages from the movie
//we will not pass this data to the LMS, but just keep tote of the score
//in local JavaScript variables until the time comes to finish the unit
function scormCommand(command, params) {
	if (command == "mark") {	
		marksReturned = true;
		var paramArray = new Array();
		paramArray = params.split(",");
		if (paramArray.length != 3) {	
			alert("Error: mark command must have three parameters");
		} else {
			if (paramArray[1] > paramArray[2]) {
				alert("Error: cannot score more than total marks available");
			} else {
				//we will ignore question numbers for the time being
				var newMarksDone = marksDone + eval(paramArray[2]);
				if (newMarksDone > marksTotal) {
					alert("Error: marks done cannot be more than total marks");
				} else {
					marksDone = newMarksDone;
					alert("Incrementing marksScored. Marks scored = " + marksScored + "; increment = " + paramArray[1]);
					marksScored += eval(paramArray[1]);
				}
			}
		}
	} else if (command == "finish") {
		scormClose();
	}
}


