﻿
/************************************************************************************************************************************************************************
** 
** Filename: scorm.js
**
** File Description: This file contains the core functions require for communication between the LMS and SCO via the SCORM API.
**
** Author: Technical Team (James Jackson)
** Company Name: Saffron Interactive
**
** Design Issues:
** Implementation Issues:
** Known Problems:
** Side Effects:
**
** References: Saffron JavaScript Container v2.0
**
/************************************************************************************************************************************************************************


	/*************************************************************************************************************************************
	** scorm constuctor
	*************************************************************************************************************************************/


		function scorm(){


				/*************************************************************************************************************
				/** scorm methods 
				*************************************************************************************************************/
					
					//try {
						this.getAPIHandle=scorm_getAPIHandle;
						this.findAPI=scorm_findAPI;
						this.getAPI=scorm_getAPI;
						this.doLMSInitialize=scorm_doLMSInitialize;
						this.doLMSFinish=scorm_doLMSFinish;
						this.doLMSGetValue=scorm_doLMSGetValue;
						this.doLMSSetValue=scorm_doLMSSetValue;
						this.doLMSCommit=scorm_doLMSCommit;
						this.doLMSGetLastError=scorm_doLMSGetLastError;
						this.doLMSGetErrorString=scorm_doLMSGetErrorString;
						this.doLMSGetDiagnostic=scorm_doLMSGetDiagnostic;
						this.LMSIsInitialized=scorm_LMSIsInitialized;
						this.ErrorHandler=scorm_ErrorHandler;
					//}catch(e){errorReporter(e, errorLocation, "<b>file:</b> scorm.js - <b>function:</b> methods]");}
				
				
				/*************************************************************************************************************
				/** scorm properties 
				*************************************************************************************************************/
					
					//try {	
						this.apiHandle = null;
						this.api = this.getAPIHandle();
						this.findAPITries = 0;
						this.maxAPITries = 500;
					//}catch(e){errorReporter(e, errorLocation, "<b>file:</b> scorm.js - <b>function:</b> properties]");}
					
					
				/*************************************************************************************************************
				/** SCORM Exception/Error Codes 
				*************************************************************************************************************/
					//try {	
							this.NoError = 0;
							this.GeneralException = 101;
							this.ServerBusy = 102;
							this.InvalidArgumentError = 201;
							this.ElementCannotHaveChildren = 202;
							this.ElementIsNotAnArray = 203;
							this.NotInitialized = 301;
							this.NotImplementedError = 401;
							this.InvalidSetValue = 402;
							this.ElementIsReadOnly = 403;
							this.ElementIsWriteOnly = 404;
							this.IncorrectDataType = 405;
					//}catch(e){errorReporter(e, errorLocation, "<b>file:</b> scorm.js - <b>function:</b> exception/error codes]");}
		}


	/*************************************************************************************************************************************
	** Core API Methods
	*************************************************************************************************************************************/
	

			/*************************************************************************************************************
			**
			** 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 scorm_getAPIHandle(){
						try {
							
							if (this.apiHandle == null){
      								this.apiHandle = this.getAPI();
   							}
   							return this.apiHandle;
							
						}catch(e){errorReporter(e, errorLocation, "<b>file:</b> scorm.js - <b>function:</b> getAPIHandle()");}
					}	
			

			/*************************************************************************************************************
			**
			** Function findAPI(win)
			** Inputs:  _win - a Window Object, _nestedWindowDepth - the number of nested windows to search
			** 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 and looks down to a 
			** specified nested depth.
			**
			*************************************************************************************************************/

					function scorm_findAPI(_win){
						try {
							
						   //resets the number of tries
								this.findAPITries = 0;
							
							//checks to see if the API already exists and that there is a parent window to go to and also the parenet window is not the current window/
								while ((_win.API == null) && (_win.parent != null) && (_win.parent != _win)){
								
									//Set the current window to the it's parent window
										_win = _win.parent;
									
									//increments the number of tries to find the api
										this.findAPITries++;
									
									//checks to see if the loop has reached the maximum number of tries 
										if(this.findAPITries < this.maxAPITries){return null;}
										
								}
						   
						   //returns the win.API object
							return _win.API;
						   
						}catch(e){errorReporter(e, errorLocation, "<b>file:</b> scorm.js - <b>function:</b> findAPI()");}
						   
					}
			

			/*******************************************************************************
			**
			** 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 scorm_getAPI(){
						try {
							
							//Sets the api to null start the search
								var theAPI = null;
														
							//Search all the parents of the current window if exists and not the current window
								 if ((theAPI == null) && (window.parent != null) && (window.parent != window)){
									var theAPI = this.findAPI(window);
							
								}
							
							//Search all the opener's of the current window if exists and not the current window
								 if ((theAPI == null) && (window.opener != null) && (window.opener != window)){
									var theAPI = this.findAPI(window.opener);
								}
						
							//Search all the top most of the current window if exists and not the current window
								 if ((theAPI == null) && (window.top.opener != null) && (window.top.opener != window)){
									var theAPI = this.findAPI(window.top.opener);
								}
						
							//If the API is is null then report that it was unable to find the api adapter
								if (theAPI == null)
								{
									scormReporter(scormLocation, "error", "Unable to find an API adapter");
								}
								
						   return theAPI;
						   
						}catch(e){errorReporter(e, errorLocation, "<b>file:</b> scorm.js - <b>function:</b> getAPI()");}
					}


						
			
	/*******************************************************************************
	** Core SCORM Communication Methods
	*******************************************************************************/			
			
			
			/*******************************************************************************
			**
			** Function: doLMSInitialize()
			** Inputs:  None
			** Return:  CMIBoolean true 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 scorm_doLMSInitialize(){
						try{
						   var api = this.getAPIHandle();
						   if (api == null){
							  
							  scormReporter(scormLocation, "warning", "Unable to locate the LMS's API Implementation. LMSInitialize was not successful."); 
							  
							  return "false";
						   }
						   
						   var result = api.LMSInitialize("");
						   if (result.toString() != "true") {
							  var err = this.ErrorHandler();
						   }
						   return result.toString();
						   
					  }catch(e){errorReporter(e, errorLocation, "<b>file:</b> scorm.js - <b>function:</b> doLMSInitialize()");}
					}
			
			
			

			/*******************************************************************************
			**
			** 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 scorm_doLMSFinish(){
						try{
							
							var api = this.getAPIHandle();
							if (api == null)
							{
								scormReporter(scormLocation, "warning", "Unable to locate the LMS's API Implementation. LMSFinish was not successful.");
								
								//commented by madhan alert("Unable to locate the LMS's API Implementation. LMSFinish was not successful : Code 003")
								
								return "false";
							
							}else{ // call the LMSFinish function that should be implemented by the API
							
								var result = api.LMSFinish("");
								if (result.toString() != "true"){
									var err = this.ErrorHandler();
								 }
							}
							return result.toString();
							
						}catch(e){errorReporter(e, errorLocation, "<b>file:</b> scorm.js - <b>function:</b> doLMSFinish()");}
					}
			
			
			/*******************************************************************************
			**
			** 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 scorm_doLMSGetValue(name){
						try {
							
						   	var api = this.getAPIHandle();
							if (api == null){
							  scormReporter(scormLocation, "warning", "Unable to locate the LMS's API Implementation. LMSGetValue was not successful.");
							  return "undefined";
						   
						   }else{
							  var value = api.LMSGetValue(name).toString();
							  var errCode = api.LMSGetLastError().toString();
							  
							  //an error was encountered so display the error description
								if (errCode != this.NoError){
									var errDescription = api.LMSGetErrorString(errCode);
									scormReporter(scormLocation, "warning", "LMSGetValue("+name+")was not successful.\n"+ errDescription);
									return "undefined";
								}else{
									// // alert("LMSGetValue ( " + name + " , " + value.toString() + " ) ");	
									return value.toString();
								}
						   }
						   
						 }catch(e){errorReporter(e, errorLocation, "<b>file:</b> scorm.js - <b>function:</b> doLMSGetValue()");} 
					}

			/*******************************************************************************
			**
			** 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 scorm_doLMSSetValue(name, value){
						try{
							
							// // alert("scorm_doLMSSetValue() : " + name + " ::: " + value.toString())
							
						   var api = this.getAPIHandle();
						   if (api == null){
							  scormReporter(scormLocation, "warning", "Unable to locate the LMS's API Implementation. LMSSetValue was not successful.");
							  
							  return "false";
						   
						   }else{
							  var result = api.LMSSetValue(name.toString(), value.toString());
							  //// alert("LMSSetValue ( " + name + " ,  " + value.toString() + " , " + result + " ) ");	
						   }
						   
						   return result.toString();
						   
						}catch(e){errorReporter(e, errorLocation, "<b>file:</b> scorm.js - <b>function:</b> doLMSSetValue()");} 						   
					}

			/*******************************************************************************
			**
			** Function doLMSCommit()
			** Inputs:  None
			** Return:  None
			**
			** Description:
			** Call the LMSCommit function 
			**
			*******************************************************************************/

					function scorm_doLMSCommit(){
						try{
						
						   var api = this.getAPIHandle();
						   if (api == null){
							   
								//commented by madhan alert("Unable to locate the LMS's API Implementation. LMSCommit was not successful : Code 002")
								
							   	scormReporter(scormLocation, "warning", "Unable to locate the LMS's API Implementation. LMSCommit was not successful.");
							  	return "false";
						  
						  }else{
							  
							  var result = api.LMSCommit("");
							  if (result != "true"){
								 var err = this.ErrorHandler();
							  }
						   }
						
						   return result.toString();
						   
					    }catch(e){errorReporter(e, errorLocation, "<b>file:</b> scorm.js - <b>function:</b> doLMSCommit()");} 
					}

			/*******************************************************************************
			**
			** Function doLMSGetLastError()
			** Inputs:  None
			** Return:  The error code that was set by the last LMS function call
			**
			** Description:
			** Call the LMSGetLastError function 
			**
			*******************************************************************************/

					function scorm_doLMSGetLastError(){
						try{
						
						   var api = this.getAPIHandle();
						   if (api == null){
							  scormReporter(scormLocation, "warning", "Unable to locate the LMS's API Implementation. LMSGetLastError was not successful."); 
							  //since we can't get the error code from the LMS, return a general error
							  return this.GeneralException;
						   }
						
						   return api.LMSGetLastError().toString();
						   
						}catch(e){errorReporter(e, errorLocation, "<b>file:</b> scorm.js - <b>function:</b> doLMSGetLastError()");} 
					}

			/*******************************************************************************
			**
			** Function doLMSGetErrorString(errorCode)
			** Inputs:  errorCode - Error Code
			** Return:  The textual description that corresponds to the input error code
			**
			** Description:
			** Call the LMSGetErrorString function 
			**
			********************************************************************************/

					function scorm_doLMSGetErrorString(errorCode){
						try{
						
						   var api = this.getAPIHandle();
						   if (api == null){
							  scormReporter(scormLocation, "warning", "Unable to locate the LMS's API Implementation. LMSGetErrorString was not successful."); 
							  return;
						   }
						
						   return api.LMSGetErrorString(errorCode).toString();
						   
					   }catch(e){errorReporter(e, errorLocation, "<b>file:</b> scorm.js - <b>function:</b> doLMSGetErrorString()");} 
					}

			/*******************************************************************************
			**
			** 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 scorm_doLMSGetDiagnostic(errorCode){
						try{
							
						   var api = this.getAPIHandle();
						   if (api == null){
							  scormReporter(scormLocation, "warning", "Unable to locate the LMS's API Implementation. LMSGetDiagnostic was not successful.");
						   }
						
						   return api.LMSGetDiagnostic(errorCode).toString();
					   
						}catch(e){errorReporter(e, errorLocation, "<b>file:</b> scorm.js - <b>function:</b> doLMSGetDiagnostic()");}
					}

			/*******************************************************************************
			**
			** Function LMSIsInitialized()
			** Inputs:  none
			** Return:  true if the LMS API is currently initialized, otherwise false
			**
			** Description:
			** Determines if the LMS API is currently initialized or not.
			**
			*******************************************************************************/

					function scorm_LMSIsInitialized(){
						
						try{
					   
						   // there is no direct method for determining if the LMS API is initialized
						   // for example an LMSIsInitialized function defined on the API so we'll try
						   // a simple LMSGetValue and trap for the LMS Not Initialized Error
						
						   var api = this.getAPIHandle();
						   if (api == null)
						   {
							  scormReporter(scormLocation, "warning", "Unable to locate the LMS's API Implementation. LMSIsInitialized() failed.");
							  return false;
						   }
						   else
						   {
							  var value = api.LMSGetValue("cmi.core.student_name");
							  var errCode = api.LMSGetLastError().toString();
							  if (errCode == this.NotInitialized)
							  {
								// alert("scorm_LMSIsInitialized : Unable to locate the LMS's API Implementation : Code 002")
								
								return false;
								
							  }
							  else
							  {
								 return true;
							  }
						   }
					   
					  }catch(e){errorReporter(e, errorLocation, "<b>file:</b> scorm.js - <b>function:</b> LMSIsInitialized()");}
					}
			
			

			/*******************************************************************************
			**
			** 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 scorm_ErrorHandler(){
						try{
					   		
						   var api = this.getAPIHandle();
						   if (api == null){
							  scormReporter(scormLocation, "warning", "Unable to locate the LMS's API Implementation. Cannot determine LMS error code.");
							  return;
						   }
						
						   // check for errors caused by or from the LMS
						   var errCode = api.LMSGetLastError().toString();
						   if (errCode != this.NoError)
						   {
							  // an error was encountered so display the error description
							  var errDescription = api.LMSGetErrorString(errCode);
						
							  if (this.Debug == true)
							  {
								 errDescription += "\n";
								 errDescription += api.LMSGetDiagnostic(null);
								 // by passing null to LMSGetDiagnostic, we get any available diagnostics
								 // on the previous error.
							  }
						
							  scormReporter(scormLocation, "debug", errDescription);
						   }
						
						   return errCode;
					   
					   }catch(e){errorReporter(e, errorLocation, "<b>file:</b> scorm.js - <b>function:</b> ErrorHandler()");}
					}
						

