var NB_MAX_SIZE_SUSPEND_DATA = 1000;
var DEBUG_MODE = false;

var FORBIDDEN_ELEMENTS = ["cmi.score.scaled"];
var FORBIDDEN_VALUES = ["not attempted"];

// Define exception/error codes
var ERROR_NO_ERROR = 0;
var ERROR_GENERAL_EXCEPTION = 101;
var ERROR_SERVER_BUSY = 102;
var ERROR_INVALID_ARGUMENT = 201;
var ERROR_CANNOT_HAVE_CHILDREN = 202;
var ERROR_NOT_IN_ARRAY = 203;
var ERROR_NOT_INITIALIZED = 301;
var ERROR_NOT_IMPLEMENTED_ERROR = 401;
var ERROR_INVALID_SETVALUE = 402;
var ERROR_READ_ONLY = 403;
var ERROR_WRITE_ONLY = 404;
var ERROR_INCORRECT_DATA_TYPE = 405;

// local variable definitions
var apiHandle = null;
var API = null;
var findAPITries = 0;


/*******************************************************************************
**
** Function initTracking()
** Inputs:  None
** Return:  None
**
** Description:
** Charge les données de tracking
**
*******************************************************************************/
function initTracking()
{

	//Récupère les données de l'objet core (seulement les données accesiibles en lecture)
	var sCoreChildren = doLMSGetValue("cmi.core._children", "");
	if (sCoreChildren.indexOf("student_id") > -1) tracking["cmi.core.student_id"] = doLMSGetValue("cmi.core.student_id", "");
	if (sCoreChildren.indexOf("student_name") > -1) tracking["cmi.core.student_name"] = doLMSGetValue("cmi.core.student_name", "");
	if (sCoreChildren.indexOf("lesson_location") > -1) tracking["cmi.core.lesson_location"] = doLMSGetValue("cmi.core.lesson_location", "");
	if (sCoreChildren.indexOf("credit") > -1) tracking["cmi.core.credit"] = doLMSGetValue("cmi.core.credit", "credit");
	if (sCoreChildren.indexOf("lesson_status") > -1) tracking["cmi.core.lesson_status"] = doLMSGetValue("cmi.core.lesson_status", "not attempted");
	if (sCoreChildren.indexOf("entry") > -1) tracking["cmi.core.entry"] = doLMSGetValue("cmi.core.entry", "");
	if (sCoreChildren.indexOf("lesson_mode") > -1) tracking["cmi.core.lesson_mode"] = doLMSGetValue("cmi.core.lesson_mode", "normal");

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

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

	//Récupère le cmi.comments
	tracking["cmi.comments"] = doLMSGetValue("cmi.comments", "");

	//Récupère le cmi.student_preference
	var sStudentPreferenceChildren = doLMSGetValue("cmi.student_preference._children", "");
	if (sStudentPreferenceChildren.indexOf("audio") > -1) tracking["cmi.student_preference.audio"] = doLMSGetValue("cmi.student_preference.audio", 0);
	if (sStudentPreferenceChildren.indexOf("language") > -1) tracking["cmi.student_preference.language"] = doLMSGetValue("cmi.student_preference.language", "");
	if (sStudentPreferenceChildren.indexOf("speed") > -1) tracking["cmi.student_preference.speed"] = doLMSGetValue("cmi.student_preference.speed", 0);
	if (sStudentPreferenceChildren.indexOf("text") > -1) tracking["cmi.student_preference.text"] = doLMSGetValue("cmi.student_preference.text", 0);
	
	//Initialise données en écriture seule
	tracking["cmi.core.session_time"] = "0000:00:00";
	tracking["cmi.core.exit"] = "";

	return "1.2";
}

/*******************************************************************************
**
** Function: doLMSInitialize()
** Inputs:  None
** Return:  CMIBoolean 1.2 if the initialization was successful, or
**          CMIBoolean false if the initialization failed.
**
** Description:
** Initialize communication with LMS by calling the LMSInitialize
** function which will be implemented by the LMS.
**
*******************************************************************************/
function doLMSInitialize()	
{
   var api = getAPIHandle();
   if (api == null)
   {
      //alert("Unable to locate the LMS's API Implementation.\nLMSInitialize was not successful.");
      return "false";
   }

   var result = api.LMSInitialize("");

   if (result.toString() != "true")
   {
      result = ErrorHandler();
   }
   else
   {
	  result = "1.2"; //renvoie la version de l'API
   }

   return result;
}

/*******************************************************************************
**
** Function doLMSFinish()
** Inputs:  None
** Return:  CMIBoolean true if successful
**          CMIBoolean false if failed.
**
** Description:
** Close communication with LMS by calling the LMSFinish
** function which will be implemented by the LMS
**
*******************************************************************************/
function doLMSFinish()
{
   var api = getAPIHandle();
   if (api == null)
   {
      //alert("Unable to locate the LMS's API Implementation.\nLMSFinish was not successful.");
      return "false";
   }
   else
   {
      // call the LMSFinish function that should be implemented by the API

      var result = api.LMSFinish("");
      if (result.toString() != "true")
      {
         var err = ErrorHandler();
      }

   }

   return result.toString();
}

/*******************************************************************************
**
** Function doLMSGetValue(name)
** Inputs:  name - string representing the cmi data model defined category or
**             element (e.g. cmi.core.student_id)
** Return:  The value presently assigned by the LMS to the cmi data model
**       element defined by the element or category identified by the name
**       input value.
**
** Description:
** Wraps the call to the LMS LMSGetValue method
**
*******************************************************************************/
function doLMSGetValue(name)
{
   var api = getAPIHandle();
   if (api == null)
   {
      //alert("Unable to locate the LMS's API Implementation.\nLMSGetValue was not successful.");
      return "";
   }
   else
   {
      var value = api.LMSGetValue(name);
      var errCode = api.LMSGetLastError().toString();
      if (errCode != ERROR_NO_ERROR)
      {
         // an error was encountered so display the error description
         var errDescription = api.LMSGetErrorString(errCode);
         //alert("LMSGetValue("+name+") failed. \n"+ errDescription);
         return "";
      }
      else
      {
         
         return value.toString();
      }
   }
}

/*******************************************************************************
**
** Function doLMSSetValue(name, value)
** Inputs:  name -string representing the data model defined category or element
**          value -the value that the named element or category will be assigned
** Return:  CMIBoolean true if successful
**          CMIBoolean false if failed.
**
** Description:
** Wraps the call to the LMS LMSSetValue function
**
*******************************************************************************/
function doLMSSetValue(name, value)
{
	var api = getAPIHandle();
	if (api == null)
	{
		//alert("Unable to locate the LMS's API Implementation.\nLMSSetValue was not successful.");
		return;
	}

	var result = "true";

	// Spilt the name value on '.'
	var arrayOfComponents = name.split(".");

	//Toutes les commandes (hors cas spécial des intéractions)
	//sont envoyées par le flash au format de tracking SCORM 1.2
	if (arrayOfComponents[1] != "interactions")
	{
		if (!isValueInArray(FORBIDDEN_ELEMENTS, name) && !isValueInArray(FORBIDDEN_VALUES, value))
		{
			result = api.LMSSetValue(name, value);
		}
	}
	else
	{
		//interaction : on vérifie que l'interaction est supportée par le LMS
		//exemple : cmi.interactions.1.correct_response_text
		var interaction_id = arrayOfComponents[2];
		var interaction_name = arrayOfComponents[3];
		var interactions_children = doLMSGetValue("cmi.interactions._children").split(",");
		if (isValueInArray(interactions_children, interaction_name))
		{
			result = api.LMSSetValue(name, value);
		}
	}

	if (result.toString() != "true")
	{
		result = ErrorHandler();
	}

   return;
}

/*******************************************************************************
**
** Function doLMSCommit()
** Inputs:  None
** Return:  None
**
** Description:
** Call the LMSCommit function 
**
*******************************************************************************/
function doLMSCommit()
{
   var api = getAPIHandle();
   if (api == null)
   {
      //alert("Unable to locate the LMS's API Implementation.\nLMSCommit was not successful.");
      return "false";
   }
   else
   {
      var result = api.LMSCommit("");
      if (result != "true")
      {
         var err = ErrorHandler();
      }
   }

   return result.toString();
}

/*******************************************************************************
**
** Function doLMSGetLastError()
** Inputs:  None
** Return:  The error code that was set by the last LMS function call
**
** Description:
** Call the LMSGetLastError function 
**
*******************************************************************************/
function doLMSGetLastError()
{
   var api = getAPIHandle();
   if (api == null)
   {
      //alert("Unable to locate the LMS's API Implementation.\nLMSGetLastError was not successful.");
      //since we can't get the error code from the LMS, return a general error
      return _GeneralError;
   }

   return api.LMSGetLastError().toString();
}

/*******************************************************************************
**
** Function doLMSGetErrorString(errorCode)
** Inputs:  errorCode - Error Code
** Return:  The textual description that corresponds to the input error code
**
** Description:
** Call the LMSGetErrorString function 
**
********************************************************************************/
function doLMSGetErrorString(errorCode)
{
   var api = getAPIHandle();
   if (api == null)
   {
      //alert("Unable to locate the LMS's API Implementation.\nLMSGetErrorString was not successful.");
   }

   return api.LMSGetErrorString(errorCode).toString();
}

/*******************************************************************************
**
** Function doLMSGetDiagnostic(errorCode)
** Inputs:  errorCode - Error Code(integer format), or null
** Return:  The vendor specific textual description that corresponds to the 
**          input error code
**
** Description:
** Call the LMSGetDiagnostic function
**
*******************************************************************************/
function doLMSGetDiagnostic(errorCode)
{
   var api = getAPIHandle();
   if (api == null)
   {
      //alert("Unable to locate the LMS's API Implementation.\nLMSGetDiagnostic was not successful.");
   }

   return api.LMSGetDiagnostic(errorCode).toString();
}

/*******************************************************************************
**
** Function ErrorHandler()
** Inputs:  None
** Return:  The current value of the LMS Error Code
**
** Description:
** Determines if an error was encountered by the previous API call
** and if so, displays a message to the user.  If the error code
** has associated text it is also displayed.
**
*******************************************************************************/
function ErrorHandler()
{
   var api = getAPIHandle();
   if (api == null)
   {
      //alert("Unable to locate the LMS's API Implementation.\nCannot determine LMS error code.");
      return;
   }

   // check for errors caused by or from the LMS
   var errCode = api.LMSGetLastError().toString();
   if (errCode != ERROR_NO_ERROR)
   {
      // an error was encountered so display the error description
      var errDescription = api.LMSGetErrorString(errCode);

      if (DEBUG_MODE == true)
      {
         errDescription += "\n";
         errDescription += api.LMSGetDiagnostic(null);
         // by passing null to LMSGetDiagnostic, we get any available diagnostics
         // on the previous error.
      }

      //alert(errDescription);
   }

   return errCode;
}

/******************************************************************************
**
** Function getAPIHandle()
** Inputs:  None
** Return:  value contained by APIHandle
**
** Description:
** Returns the handle to API object if it was previously set,
** otherwise it returns null
**
*******************************************************************************/
function getAPIHandle()
{
   if (apiHandle == null)
   {
      apiHandle = getAPI();
   }

   return apiHandle;
}


/*******************************************************************************
**
** Function findAPI(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 findAPI(win)
{
   while ((win.API == null) && (win.parent != null) && (win.parent != win))
   {
      findAPITries++;
      // Note: 7 is an arbitrary number, but should be more than sufficient
      if (findAPITries > 7) 
      {
         //alert("Error finding API -- too deeply nested.");
         return null;
      }
      
      win = win.parent;

   }
   return win.API;
}



/*******************************************************************************
**
** Function getAPI()
** 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 getAPI()
{
   theAPI = findAPI(window);
   
   // Avec frame
   if ((theAPI == null) && (window.parent.opener != null) && (typeof(window.parent.opener) != "undefined")) {
	   theAPI = findAPI(window.parent.opener);
	   if ((theAPI == null) && (window.parent.opener.opener != null) && (typeof(window.parent.opener.opener) != "undefined")) {
		   theAPI = findAPI(window.parent.opener.opener);
	   }
   }

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

   return theAPI;
}

