/*******************************************************************************
** initialisations
*******************************************************************************/
var keyList = new Array(25); //Conversion table
var valueList = new Array(25); //Conversion table
var objectivesStatusRequestArr = new Array();


/*******************************************************************************
**
** Function doLMSInitializeSCORM13()
** Inputs:  none
** Return:  "true" si initialisation OK. Sinon "false"
**
** Description:
** Initialise l'API de tracking et signale au LMS le début de la session, le tout en SCORM 1.2
**
*******************************************************************************/
function doLMSInitializeSCORM13() {
	var buffer = "false";

   fillKeyList();
   fillValueList();

	API = getAPI13(); // recherche de l'API
	if (API != null) {
		buffer = API.Initialize(""); //Peut renvoyer une chaine ou un booleen ou rien du tout
		if (buffer == null) buffer = false;
		buffer = buffer.toString();
		buffer = buffer.toLowerCase();
		_sTrackingMode = "SCORM 1.3";
	}

	//trace("APIBased_LMSInitialize bAPIBased = " + bAPIBased);
	return buffer;
}

/*******************************************************************************
**
** Function doLMSFinishSCORM13()
** Inputs:  none
** Return:  le dernier code d'erreur
**
** Description:
** Envoi une dernière fois les données de tracking au LMS
** et met fin à la session de tracking en SCORM 1.2
**
*******************************************************************************/
function doLMSFinishSCORM13() {
	//trace("APIBased_LMSFinish");
	var buffer = false;
	clearInterval(nCommitIntervalID);

	if (API == null) API = getAPI13();

	// envoie de toutes les données stockées
	if (tracking["cmi.core.score.raw"] != null) dmElementSetFunction("cmi.core.score.raw", tracking["cmi.core.score.raw"]);
	if (tracking["cmi.score.scaled"] != null) dmElementSetFunction("cmi.score.scaled", tracking["cmi.score.scaled"]);
	dmElementSetFunction("cmi.core.session_time", tracking["cmi.core.session_time"]);
	dmElementSetFunction("cmi.core.lesson_status", tracking["cmi.core.lesson_status"]);
	dmElementSetFunction("cmi.core.lesson_location", tracking["cmi.core.lesson_location"]);
	dmElementSetFunction("cmi.suspend_data", tracking["cmi.suspend_data"]);
	doLMSCommitSCORM13();

	buffer = API.Terminate(""); // termine la session
	if (buffer != "true") doLMSGetDiagnosticSCORM13(API.GetLastError(), "Terminate", "");
	
	return buffer;
}


/*******************************************************************************
**
** Function getLMSParametersSCORM13()
** Inputs:  none
** Return:  une chaine URL
**
** Description:
** Retourne des paramètres url_encoded avec des infos sur le tracking
**
*******************************************************************************/
function getLMSParametersSCORM13() {
	var buffer = "";	

	if (API == null) API = getAPI13();

	//Récupère les données de l'objet core (seulement les données accessibles en lecture)
	tracking["cmi.core.student_id"] = doLMSGetValueSCORM13("cmi.learner_id", "");
	tracking["cmi.core.student_name"] = doLMSGetValueSCORM13("cmi.learner_name", "");
	tracking["cmi.core.lesson_location"] = doLMSGetValueSCORM13("cmi.location", "");
	tracking["cmi.core.credit"] = doLMSGetValueSCORM13("cmi.credit", "credit");
	tracking["cmi.core.lesson_status"] = doLMSGetValueSCORM13("cmi.completion_status", "not attempted");
	tracking["cmi.core.entry"] = doLMSGetValueSCORM13("cmi.entry", "");
	tracking["cmi.core.lesson_mode"] = doLMSGetValueSCORM13("cmi.mode");

	//Récupère le cmi.suspend_data
	tracking["cmi.suspend_data"] = doLMSGetValueSCORM13("cmi.suspend_data");

	//Récupère le cmi.launch_data
	tracking["cmi.launch_data"] = doLMSGetValueSCORM13("cmi.launch_data");

	//Récupère les informations de navigation inter-sco
	tracking["adl.nav.request_valid.continue"] = doLMSGetValueSCORM13("adl.nav.request_valid.continue");
	tracking["adl.nav.request_valid.previous"] = doLMSGetValueSCORM13("adl.nav.request_valid.previous");

	//Récupère le cmi.student_preference
	var sStudentPreferenceChildren = doLMSGetValueSCORM13("cmi.learner_preference._children");
	if (sStudentPreferenceChildren.indexOf("audio_level") > -1) tracking["cmi.student_preference.audio"] = doLMSGetValueSCORM13("cmi.learner_preference.audio_level");
	if (sStudentPreferenceChildren.indexOf("language") > -1) tracking["cmi.student_preference.language"] = doLMSGetValueSCORM13("cmi.learner_preference.language");
	if (sStudentPreferenceChildren.indexOf("delivery_speed") > -1) tracking["cmi.student_preference.speed"] = doLMSGetValueSCORM13("cmi.learner_preference.delivery_speed");
	if (sStudentPreferenceChildren.indexOf("audio_captioning") > -1) tracking["cmi.student_preference.text"] = doLMSGetValueSCORM13("cmi.learner_preference.audio_captioning");
	
	//Initialise données en écriture seule
	tracking["cmi.core.session_time"] = "0000:00:00";
	tracking["cmi.core.exit"] = "";
	
	//Prépare la chaine URL contenant les paramètres à destination du Flash
	buffer  = buffer + "&bAPIBased=1";
	buffer  = buffer + "&scormversion=2004";
	if (tracking["cmi.core.student_id"]) buffer = buffer + "&sStudentId=" + tracking["cmi.core.student_id"];
	if (tracking["cmi.core.student_name"]) buffer = buffer + "&sStudentName=" + tracking["cmi.core.student_name"];
	if (tracking["cmi.core.lesson_location"]) buffer = buffer + "&sLessonLocation=" + tracking["cmi.core.lesson_location"];
	if (tracking["cmi.core.credit"]) buffer = buffer + "&sCredit=" + tracking["cmi.core.credit"];
	if (tracking["cmi.core.lesson_status"]) buffer = buffer + "&sLessonStatus=" + tracking["cmi.core.lesson_status"];
	if (tracking["cmi.core.entry"]) buffer = buffer + "&sEntry=" + tracking["cmi.core.entry"];
	if (tracking["cmi.core.lesson_mode"]) buffer = buffer + "&sLessonMode=" + tracking["cmi.core.lesson_mode"];
	if (tracking["cmi.student_preference.audio"]) buffer = buffer + "&sStudentPreferenceAudio=" + tracking["cmi.student_preference.audio"];
	if (tracking["cmi.student_preference.language"]) buffer = buffer + "&sStudentPreferenceLanguage=" + tracking["cmi.student_preference.language"];
	if (tracking["cmi.student_preference.speed"]) buffer = buffer + "&sStudentPreferenceSpeed=" + tracking["cmi.student_preference.speed"];
	if (tracking["cmi.student_preference.text"]) buffer = buffer + "&sStudentPreferenceText=" + tracking["cmi.student_preference.text"];

	// historique trop long pour être envoyé directement au swf en parametre (limitation IE)
	// le swf doit demander au javascript de lui envoyer en plusieurs fois
	buffer  = buffer + "&sSuspendData=big";

	//si le LMS supporte les interactions, la fonction doit retourner la liste des champs supportés (exple : "id,result,type,weighting")
	aTrackInteractionsList = doLMSGetValueSCORM13("cmi.interactions._children").split(",");
	bTrackInteractions = (aTrackInteractionsList.length > 0);
	buffer  = buffer + "&bTrackInteractions=" + bTrackInteractions; // flag "Track Interactions"

	if (tracking["adl.nav.request_valid.continue"]) buffer = buffer + "&sNavRequestValidContinue=" + tracking["adl.nav.request_valid.continue"];
	if (tracking["adl.nav.request_valid.previous"]) buffer = buffer + "&sNavRequestValidPrevious=" + tracking["adl.nav.request_valid.previous"];

	return buffer;
}


/*******************************************************************************
**
** Function doLMSSetValueSCORM13()
** Inputs:  name -string representing the data model defined category or element
**          value -the value that the named element or category will be assigned
**			bIsInteraction -boolean indicates when data is an interaction
** Return:  true if successful
**          false if failed.
**
** Description:
** Converts the element name to the Updated element name following the
** SCORM 2004 data model. Also converts the value to the appropriate format
** when neccessary.
**
*******************************************************************************/
function doLMSSetValueSCORM13(name, value, bIsInteraction) {
	if (API == null) API = getAPI13();

	if (!bIsInteraction) {
		dmElementSetFunction(name, value);
		
		//Prépare la validation de la transaction avec un délai d'une seconde
		clearInterval(nCommitIntervalID);
		nCommitIntervalID = setInterval(doLMSCommitSCORM13, 1000);

	} else { // interaction : on vérifie que l'interaction est supportée par le LMS
		// exple : cmi.interactions.1.correct_response_text
		if (isValueInArray(aTrackInteractionsList, getInteractionName(name))) {
			dmElementSetFunction(name, value); // on n'envoie l'interaction que si elle est supportée par le LMS
			
			//Prépare la validation de la transaction avec un délai d'une seconde
			clearInterval(nCommitIntervalID);
			nCommitIntervalID = setInterval(doLMSCommitSCORM13, 1000);
		}
	}
}

/*******************************************************************************
**
** Function doLMSGetValueSCORM13()
** Inputs:  name - string representing a data model element 
**
** Return:  The value presently stored by the LMS for the data model element
**
** Description:
** Requests the value for the data model element
**
*******************************************************************************/
function doLMSGetValueSCORM13(name, defaultValue) {
	if (API == null) API = getAPI13();
	var updatedName = getNewValue(name);

	var buffer = API.GetValue(updatedName);

	var errCode = API.GetLastError();
	if (errCode != "0") doLMSGetDiagnosticSCORM13(errCode, "GetValue", updatedName);

	if (buffer == undefined || buffer == null) buffer = defaultValue;

	return buffer;
}


/*******************************************************************************
**
** Function doLMSGetLastErrorSCORM13()
** Inputs:  none 
** Return:	Le dernier code d'erreur retourné par le LMS
**
** Description:
** Interroge le LMS pour obtenir le code d'erreur généré par la dernière commande
** envoyé au LMS
**
*******************************************************************************/
function doLMSGetLastErrorSCORM13() {
	if (API == null) API = getAPI13();
	return API.GetLastError();
}


/*******************************************************************************
**
** Function doLMSGetDiagnosticSCORM13()
** Inputs:  errCode -string
**          attr -string
**			value -string
** Return:	none
**
** Description:
** Affiche un message d'erreur si la dernière commande envoyée au LMS a généré
** une erreur. Le message contient le numéro et la description de l'erreur
**
*******************************************************************************/
function doLMSGetDiagnosticSCORM13(errCode, attr, val) {
	if (API == null) API = getAPI13();
	var msg = "ERROR : " + errCode + "\n" + API.GetDiagnostic(errCode);

	if (val != "") val = " / " + val;
	if (attr != "") msg += "\n\n" + attr + val;
	
	if (DEBUG_MODE) alert(msg);
}

/*******************************************************************************
**
** Function doLMSCommitSCORM13()
** Inputs:  none 
** Return:	none
**
** Description:
** Cloture la transaction en validant les commandes envoyées au LMS
**
*******************************************************************************/
function doLMSCommitSCORM13() {
	clearInterval(nCommitIntervalID);
	if (API == null) API = getAPI13();

	var buffer = API.Commit(""); //on commit pour être sûr que le LMS stocke la valeur (certains LMS ont besoin de ceci pour réellement stocker la valeur)
	if (buffer != "true") doLMSGetDiagnosticSCORM13(API.GetLastError(), "Commit", "");

	return buffer;
}


/*******************************************************************************
**
** Function findAPI13(win)
** Inputs:  win - a Window Object
** Return:  If an API object is found, it's returned, otherwise null is returned
**
** Description:
** This function looks for an object named API in parent and opener windows
**
*******************************************************************************/
function findAPI13(win) {
   while ((win.API_1484_11 == null) && (win.parent != null) && (win.parent != win))
   {
      nFindAPITries++;
      // Note: 500 is a number that comes from the new IEEE API standard.
      //       See rational in ticket number 3547
      if (nFindAPITries > 500) {
         if (DEBUG_MODE) alert("Error finding API -- too deeply nested.");
         return null;
      }
      win = win.parent;
   }
   return win.API_1484_11;
}
/*******************************************************************************
**
** Function getAPI13()
** Inputs:  none
** Return:  If an API object is found, it's returned, otherwise null is returned
**
** Description:
** This function looks for an object named API, first in the current window's
** frame hierarchy and then, if necessary, in the current window's opener window
** hierarchy (if there is an opener window).
**
*******************************************************************************/
function getAPI13() {
   theAPI = findAPI13(window);
   
   // Avec frame
   if ((theAPI == null) && (window.parent.opener != null) && (typeof(window.parent.opener) != "undefined")) {
	   theAPI = findAPI13(window.parent.opener);
	   if ((theAPI == null) && (window.parent.opener.opener != null) && (typeof(window.parent.opener.opener) != "undefined")) {
		   theAPI = findAPI13(window.parent.opener.opener);
	   }
   }

   if (theAPI == null)   {
      if (DEBUG_MODE) alert("Unable to find an API adapter");
   }

   return theAPI;
}



/******************************************************************************
**
** Function: fillKeyList()
** Inputs:  None
** Return:  None
**
** Description:
** fillKeyList is called upon initiation of the file and populates a list array
** used in the getNewValue function. The finished list contains the conformant
** SCORM 1.2 data model elements that may need converted to SCORM 2004.  
**
******************************************************************************/ 
function fillKeyList()
{
   // Fill the list of keys (old data model elements)
   keyList[0] = "cmi.core.student_id";
   keyList[1] = "cmi.core.student_name";
   keyList[2] = "cmi.core.lesson_location";
   keyList[3] = "cmi.core.credit";
   keyList[4] = "cmi.core.entry";
   keyList[5] = "cmi.core.score.raw";
   keyList[6] = "cmi.core.score.max";
   keyList[7] = "cmi.core.score.min";
   keyList[8] = "cmi.core.total_time";
   keyList[9] = "cmi.core.lesson_mode";
   keyList[10] = "cmi.core.exit";
   keyList[11] = "cmi.core.session_time";
   keyList[12] = "cmi.core.score._children";
   keyList[13] = "cmi.student_preference._children";
   keyList[14] = "cmi.student_preference.audio";
   keyList[15] = "cmi.student_preference.language";
   keyList[16] = "cmi.student_preference.speed";
   keyList[17] = "cmi.student_preference.text";
   keyList[18] = "cmi.student_data.mastery_score";
   keyList[19] = "cmi.student_data.max_time_allowed";
   keyList[20] = "cmi.student_data.time_limit_action";
   keyList[21] = "cmi.comments_from_lms";
   keyList[22] = "cmi.comments";
}

/******************************************************************************
**
** Function: fillValueList()
** Inputs:  None
** Return:  None 
**
** Description:
** fillValueList is called upon initiation of the file and populates a list array
** used in the getNewValue function. This finished list contains the appropriate
** updated SCORM 2004 data model elements.
**
******************************************************************************/   
function fillValueList()
{
   // Fill the list of values (new data model elements)
   valueList[0] = "cmi.learner_id";
   valueList[1] = "cmi.learner_name";
   valueList[2] = "cmi.location";
   valueList[3] = "cmi.credit";
   valueList[4] = "cmi.entry";
   valueList[5] = "cmi.score.raw";
   valueList[6] = "cmi.score.max";
   valueList[7] = "cmi.score.min";
   valueList[8] = "cmi.total_time";
   valueList[9] = "cmi.mode";
   valueList[10] = "cmi.exit";
   valueList[11] = "cmi.session_time";
   valueList[12] = "cmi.score._children";
   valueList[13] = "cmi.learner_preference._children";
   valueList[14] = "cmi.learner_preference.audio_level";
   valueList[15] = "cmi.learner_preference.language";
   valueList[16] = "cmi.learner_preference.delivery_speed";
   valueList[17] = "cmi.learner_preference.audio_captioning";
   valueList[18] = "cmi.scaled_passing_score";
   valueList[19] = "cmi.max_time_allowed";
   valueList[20] = "cmi.time_limit_action";
   valueList[21] = "cmi.comments_from_lms.0.comment";
   valueList[22] = "cmi.comments_from_learner.0.comment";
}

/******************************************************************************
**
** Function: getNewValue()
** Inputs: SCORM 1.2 data model element 
** Return: corresponding SCORM 2004 data model element
**
** Description:
** getNewValue take in the old SCORM 1.2 datamodel element and by using the 
** previously set list arrays returns the corresponding SCORM 2004 data model
** element.
**
******************************************************************************/   
function getNewValue( key ) {
	var keyResult = key;

	// Check to see if result is cmi.interactions
	var checkValue = keyResult.substring(0,16);

	if (checkValue == "cmi.interactions") {
		var arrayOfComponents = keyResult.split(".");

		switch (arrayOfComponents[3]) {
		case "time":
			keyResult = "cmi.interactions." + arrayOfComponents[2] + ".timestamp";
			break;
		case "student_response":
			keyResult = "cmi.interactions." + arrayOfComponents[2] + ".learner_response";
			break;
		}
	}

	for (var i=0; i<keyList.length; i++) {
		if (keyList[i] == key) {
			keyResult = valueList[i];
			break;
		}
	}   
	
	return keyResult;
}





/******************************************************************************
**
** Function: dmElementSetFunction()
** Inputs: data model element name to set and the value attempting to set
** Return: boolean value true or false if the value was correctly set
**
** Description:
** dmElementSetFunction takes in the name of the SCORM 1.2 datamodel 
** element and the desired value to set the element equal to. Prior to calling
** the SetValue call to the LMS the function converts the element to conformant
** SCORM 2004 syntax and in some cases formats the value data to meet SCORM 2004
** standards.  Upon calling the SetValue call the return value of true or false 
** is returned to the originating calling line.Three special cases exist for
** elements that require additional more complicated conversions, they are for
** core elements, objective and interactions. All other normal calls fall into
** the default case.
**
******************************************************************************/ 
function dmElementSetFunction(name, value) {
	var buffer = "";

	if (API == null) API = getAPI13();

	var sNewName = getNewValue(name); 
	var arrayOfComponents = name.split(".");

	switch ( arrayOfComponents[1] ) {
		case "core": 
			buffer = setConvertCore(name,value,arrayOfComponents);
			break;
		case "objectives":
			buffer = setConvertObjectives(name,value,arrayOfComponents);
			break; 
		case "interactions":
			buffer = setConvertInteractions(name,value,arrayOfComponents);
			break; 
		default:
			// Normal setValue() Call
			buffer = API.SetValue(sNewName, value);
	}

	if (buffer != "true") {
		doLMSGetDiagnosticSCORM13(API.GetLastError(), sNewName, value);
	}
	
	return buffer;
}


/******************************************************************************
**
** Function: setConvertCore()
** Inputs: core data model element 
** Return: boolean true or false depending on success or failure of the call
**
** Description: Special Case 1 of 3 for SetValue
** setConvertCore accepts a valid SCORM 1.2 element and value and converts the 
** call into conformant SCORM 2004 syntax. Upon making the conversion the 
** SetValue call is made to the LMS and returns a boolean value upon the the 
** sucess or failure of the call.
**
******************************************************************************/
function setConvertCore(name,value,arrayOfComponents) {
	var buffer = "";
	
	var coreUpdatedName = getNewValue(name);

	if ( name == "cmi.core.lesson_status" ) {
	  // Check name and determine which element to set
	  if ( (value == "completed") || (value == "incomplete") || 
		   (value == "not attempted") )
	  {
		 buffer = API.SetValue("cmi.completion_status", value);
		 return buffer;
	  }
	  else if ( (value == "passed") || (value == "failed") )
	  {
		 buffer = API.SetValue("cmi.success_status", value);
		 return buffer;
	  }
	  else if (value == "browsed")
	  {
		 buffer = true;
		 return buffer;
	  }

	} else if ( name == "cmi.core.session_time" ) {
	  timeArray = new Array(4);
	  timeArray = value.split(":");
	  
	  hours = timeArray[0];
	  minutes = timeArray[1];
	  seconds = timeArray[2];
	  
	  var newvalue = "PT" + hours + "H" + minutes + "M" + seconds + "S";
	  buffer = API.SetValue(coreUpdatedName, newvalue);
	  return buffer;      
	} else {
	  // Normal setValue() Call         
	  buffer = API.SetValue(coreUpdatedName, value);
	  return buffer;
	}

	return buffer;
}

/******************************************************************************
**
** Function: setConvertObjectives()
** Inputs: objectives data model element 
** Return: boolean true or false depending on success or failure of the call
**
** Description: Special Case 2 of 3 for SetValue
** setConvertObjectives accepts a valid SCORM 1.2 element and value and converts  
** the call into conformant SCORM 2004 syntax. Upon making the conversion the 
** SetValue call is made to the LMS and returns a boolean value upon the the 
** sucess or failure of the call.
**
******************************************************************************/
function setConvertObjectives(name,value,arrayOfComponents)
{
   var buffer = "";
   var objUpdatedName = getNewValue(name);
   
   if ( arrayOfComponents[3] == "status" )
   {
      if ( (value == "passed") || (value == "failed") )
      {
         // Reset Objectives Flag
         objectivesFlag = "";
         buffer = API.SetValue("cmi.objectives." + 
                               arrayOfComponents[2] + ".success_status", value);
         objectivesStatusRequestArr[arrayOfComponents[2]] = "cmi.objectives." + 
                                       arrayOfComponents[2] + ".success_status";
         return buffer;
      }
      else if ( (value == "completed") || (value == "incomplete") || 
                (value == "not attempted") )
      {
         // Reset Objectives Flag
         objectivesFlag = "";
         buffer = API.SetValue("cmi.objectives." + arrayOfComponents[2]+ 
                                       ".completion_status", value);
         objectivesStatusRequestArr[arrayOfComponents[2]] = "cmi.objectives." + 
                                    arrayOfComponents[2] + ".completion_status";
         return buffer;       
      }
      else if ( value == "browsed")
      {
        // Set objectives flag
        objectivesFlag = "browsed";
        buffer = true;
        return buffer;
      }
   }
   else
   { // Normal set objective call
      // Normal setValue() Call
      buffer = API.SetValue(objUpdatedName, value);
      return buffer;
   }
   
   return buffer;
}

/******************************************************************************
**
** Function: setConvertInteractions()
** Inputs: interactions data model element 
** Return: boolean true or false depending on success or failure of the call
**
** Description: Special Case 3 of 3 for SetValue
** setConvertInteractions accepts a valid SCORM 1.2 element and value and   
** converts the call into conformant SCORM 2004 syntax. Upon making the  
** conversion the SetValue call is made to the LMS and returns a boolean value  
** upon the the sucess or failure of the call.
**
******************************************************************************/
function setConvertInteractions(name,value,arrayOfComponents)
{
   var buffer = "";
   var interUpdatedName = getNewValue(name);

   if ( arrayOfComponents[3] == "latency" )
   {
      timeArray = new Array(4);
      timeArray = value.split(":");
      
      hours = timeArray[0];
      minutes = timeArray[1];
      seconds = timeArray[2];
      
      var newvalue = "PT" + hours + "H" + minutes + "M" + seconds + "S"; 
      buffer = API.SetValue(name, newvalue);
      return buffer;     
   }
   else if ( arrayOfComponents[3] == "time" )
   {
      // Convert the time format to correct format
      var now = new Date();
      var year = now.getYear();
      var month = now.getMonth();
      
      if ( month <= 9 )
      {
         month = "0" + month;
      }

      var day = now.getDay();
      
      if ( day <= 9 )
      {
         day = "0" + day;
      }

      var newValue = year + "-" + month + "-" + day + "T" + value;
      
      // Setting interactions.timestamp to updated 2004 time format
      var result1 = API.SetValue("cmi.interactions." + arrayOfComponents[2] + 
                                 ".timestamp", newValue);
      return result1;
   }
   else if ( arrayOfComponents[3] == "result" )
   {
      // Check Value sending in to set
      if ( value == "wrong" )
      {
         buffer = API.SetValue(interUpdatedName, "incorrect");
         return buffer;
      }
      else
      {
         buffer = API.SetValue(interUpdatedName, value);
         return buffer;
      }
   }
   else
   { // Normal core set value call
      // Normal setValue() Call         
      buffer = API.SetValue(interUpdatedName, value);
      return buffer;
   }
   
   return buffer;
}

