// © Edu-Performance Canada Inc., 1997-2005 (All rights reserved.)
// Warning : This computer program is protected by copyright law and 
// international treaties. Unauthorized reproduction or distribution 
// of this program, or any portion of it, may result in severe civil  
// and criminal penalties, and will be prosecuted to the maximum 
// extent possible under the law.

// © Edu-Performance Canada inc., 1997-2005 (Tous droits réservés.)
// Avertissement : ce logiciel est protégé par la loi du copyright et
// par les conventions internationales. Toute reproduction ou distribution
// partielle ou totale du logiciel, par quelque moyen que ce soit, est 
// strictement interdite. Toute personne ne respectant pas ces dispositions
// se rendra coupable du délit de contrefaçon et sera passible des sanctions
// pénales prévues par la loi.

var is_ie4up = false;
var is_nav4up = false;
var is_nav5up = false;
var is_ie4 = false;

var isSCOLaunchedOuterWindow = true;
var isFinishLMSSessionAlreadyCalled = false;

var runTimeEnvNone = 0; // None
var runTimeEnvAICC = 1; // AICC
var runTimeEnvSCORM12 = 2; // SCORM 1.2
var runTimeEnvSCORM13 = 3; // SCORM 1.3

var LMS_API_MODE = 0;
var TACTIC_JAVA_API_MODE = 1;
var TACTIC_XML_HTTP_API_MODE = 2;
var trackingAPIMode = LMS_API_MODE;

// Versions de fureteurs
var IE_NONE = "0"; // Aucun
var IE_5_0 = "5.0"; // IE 5.0
var IE_5_5 = "5.5"; // IE 5.5
var IE_6_0 = "6.0"; // IE 6.0

function checkForCorrectBrowser(stringToDisplay, stringToDisplayForIE)
{
  // convert all characters to lowercase to simplify testing 
  var agt=navigator.userAgent.toLowerCase(); 
  var is_major = parseInt(navigator.appVersion); 
  var is_minor = parseFloat(navigator.appVersion); 

  // Note: Opera and WebTV spoof Navigator.  We do strict client detection. 
  // If you want to allow spoofing, take out the tests for opera and webtv. 
  var is_nav  = ((agt.indexOf('mozilla')!=-1) && (agt.indexOf('spoofer')==-1) 
              && (agt.indexOf('compatible') == -1) && (agt.indexOf('opera')==-1) 
              && (agt.indexOf('webtv')==-1)); 
  is_nav4up = (is_nav && ((is_minor >= 4.04))); 
  is_nav5up = (is_nav && (is_major >= 5)); 

  var is_ie   = (agt.indexOf("msie") != -1); 
  is_ie4up  = (is_ie  && (is_major >= 4)); 
  is_ie4 = (is_ie && (is_major == 4));
  
  if ( !is_ie4up && !is_nav4up)
  {
    document.write('<CENTER><H1>'+stringToDisplay+'</H1></CENTER>');
  }
  else if (is_ie && parseFloat(pubIEVersion) > getIEVersion())
  {
    document.write('<CENTER><H1>'+stringToDisplayForIE.replace(/@@@/i, pubIEVersion)+'</H1></CENTER>');
  }
}

function getIEVersion()
{
	// convert all characters to lowercase to simplify testing 
	var agt=navigator.userAgent.toLowerCase(); 
	var is_ie   = (agt.indexOf("msie") != -1);
	var IEVersion = 0;
	if (is_ie)
		IEVersion = parseFloat(navigator.appVersion.substr(navigator.appVersion.indexOf("MSIE")+5,3));
	
	return   IEVersion;
}

function ResizeWin(){
	if(!window.saveInnerWidth ){ 
		window.onresize = resize;
		window.saveInnerWidth = window.innerWidth;
		window.saveInnerHeight = window.innerHeight;
	}
}

function resize(){ 
	if (saveInnerWidth < window.innerWidth || 
	    saveInnerWidth > window.innerWidth || 
	    saveInnerHeight > window.innerHeight || 
	    saveInnerHeight < window.innerHeight ){ 
			window.location.reload(); 
	}
}

function CloseSession(win)
{
	if(!isSCOLaunchedOuterWindow && (win.parent != null) && (win.parent.TOC != null))
		win.parent.TOC.FinishLMSSession();
	else
		win.top.close(); 
}

///////////////////////////////////////////////////////////////////
// Communication AICC/SCORM via xml-http
///////////////////////////////////////////////////////////////////

function extractFromAICCDataStr(aiccTable, param)
{
	var i;
	for(i=0; i<aiccTable.length; i++)
	{
		var aiccLineUpperCase = aiccTable[i].toUpperCase();
		var paramUpperCase = param.toUpperCase();
		if(aiccLineUpperCase.indexOf(paramUpperCase) != -1)
		{
			if((param == "[CORE_LESSON]") || (param == "[SUSPEND_DATA]"))
			{
				if(aiccTable[i+1].length == 1)
					return "";
				return aiccTable[i+1];
			}
			else
			{
				var dataStartIndex = aiccTable[i].indexOf("=")+1;
				var dataEndIndex = aiccTable[i].length;
				return aiccTable[i].substring(dataStartIndex, dataEndIndex);
			}
		}
	}
	
	return "";
}

function xmlHttpLMSInitialize()
{
	var commandValue = "getparam";
	var aiccData = "";
	var strXMLCmd = this.postUrl +"?command="+ commandValue +"&session_id="+ this.sessionId +"&version="+ this.versionValue +"&aiccdata="+ aiccData
	this.oXMLHTTP.open("GET", strXMLCmd, false)
	this.oXMLHTTP.send()
	var aiccData = new String(this.oXMLHTTP.responseText);
//alert(aiccData);
	aiccData.replace(aiccData, "\r\n", "\n");
	var aiccTable = aiccData.split("\n");
	this.lesson_status = this.extractAICCData(aiccTable, "Lesson_Status");
	this.lesson_location = this.extractAICCData(aiccTable, "Lesson_Location");
	this.score = this.extractAICCData(aiccTable, "Score");
	this.time = this.extractAICCData(aiccTable, "Time");
	this.suspend_data = this.extractAICCData(aiccTable, "[SUSPEND_DATA]");
	if(this.suspend_data == "")
		this.suspend_data = this.extractAICCData(aiccTable, "[CORE_LESSON]");								
}

function xmlHttpLMSFinish()
{
	var commandValue = "exitau";
	var strXMLCmd = this.postUrl +"?command="+ commandValue +"&session_id="+ this.sessionId +"&version="+ this.versionValue +"&aiccdata="
	this.oXMLHTTP.open("POST", strXMLCmd, false)
	this.oXMLHTTP.send()
}

function xmlHttpLMSSetValue(param, value)
{
	if(param == "cmi.core.lesson_status")
		this.lesson_status = value;
	else if(param == "cmi.core.lesson_location")
		this.lesson_location = value;
	else if(param == "cmi.core.score.raw")
		this.score = value;	
	else if(param == "cmi.core.time")
		this.time = value;		
	else if(param == "cmi.suspend_data")
		this.suspend_data = value;
	else if(param.indexOf("cmi.interactions")>-1)	
	{
// Interactions non-supportées
/*
		var splitInteraction = param.split(".");
		var interactionNo = splitInteraction[2];
		if(this.interactions.length == interactionNo)
			this.interactions[interactionNo] = new interaction;
		if(splitInteraction[3] == "type")
			this.interactions[interactionNo].type = value;
		if(splitInteraction[3] == "id")
			this.interactions[interactionNo].id = value;
		if(splitInteraction[3] == "correct_responses.0.pattern")
			this.interactions[interactionNo].correct_responses_0_pattern = value;
		if(splitInteraction[3] == "student_response")
			this.interactions[interactionNo].student_response = value;
		if(splitInteraction[3] == "result")
			this.interactions[interactionNo].result = value;
*/
	}
}

function xmlHttpLMSCommit()
{
	var commandValue = "putparam";
// suspend_data vs core_lesson
//	var aiccData = escape("[core]\r\nlesson_status="+this.lesson_status+"\r\nlesson_location="+this.lesson_location+"\r\nscore="+this.score+"\r\ntime="+this.time+"\r\n[suspend_data]\r\n"+this.suspend_data+"\r\n");
	var aiccData = escape("[core]\r\nlesson_status="+this.lesson_status+"\r\nlesson_location="+this.lesson_location+"\r\nscore="+this.score+"\r\ntime="+this.time+"\r\n[core_lesson]\r\n"+this.suspend_data+"\r\n");
	var strXMLCmd = this.postUrl +"?command="+ commandValue +"&session_id="+ this.sessionId +"&version="+ this.versionValue +"&AICC_Data="+ aiccData
//alert(unescape(strXMLCmd));
	this.oXMLHTTP.open("POST", strXMLCmd, false)
	this.oXMLHTTP.send()
}

function xmlHttpLMSGetValue(param)
{
	if(param == "cmi.core.lesson_status")
		return this.lesson_status;
	else if(param == "cmi.core.lesson_location")
		return this.lesson_location;
	else if(param == "cmi.core.score.raw")
		return this.score;	
	else if(param == "cmi.core.time")
		return this.time;		
	else if(param == "cmi.suspend_data")
		return this.suspend_data;			
	else
		return "";
}

/*
function interaction()
{
	this.type = "";
	this.id = "";
	this.correct_responses_0_pattern = "";
	this.student_response = "";
	this.result = "";
}
*/

function xmlHttpAPI(lmsCatcherUrl, lmsSessionId)
{
	this.oXMLHTTP = new ActiveXObject("Microsoft.XMLHTTP");
	this.sessionId = lmsSessionId;
	this.postUrl = lmsCatcherUrl;
	this.versionValue = "AICC+3.0.1";
	
	this.LMSInitialize = xmlHttpLMSInitialize;
	this.LMSFinish = xmlHttpLMSFinish;
	this.LMSSetValue = xmlHttpLMSSetValue;
	this.LMSGetValue = xmlHttpLMSGetValue;							
	this.LMSCommit = xmlHttpLMSCommit;
	
	this.extractAICCData = extractFromAICCDataStr;

	this.lesson_status = "";
	this.lesson_location = "";
	this.score = "";
	this.time = "";
	this.suspend_data = "";

//	this.interactions = new Array();
}

///////////////////////////////////////////////////////////////////


/******************************************************************************************
** Function isCMIContext(win)
** Inputs:	win
** Output:	boolean indicationg if it is a CMI context (the aicc_sid and the AICC_URL existe in URL)
** Description: This function determin if it is a CMI context or not, by parsing the 
**				window url. if it is CMI context, this function create un applet that contain 
**				an interface to comunicate with LMS.
**				supported window hierarchy, in the following order
**					1. The current window
**					2. All the parent of the current window
******************************************************************************************/
function isCMIContext(win) { 
	var URLQuery="", upperCaseURLQuery, aiccURL="", sessionID="", api=null, url=win.document.location+"";  
	pos=url.indexOf("#")
	if (pos==-1) pos=url.indexOf("?")
	if (pos>-1) URLQuery=url.substring(pos+1,url.length)
	URLQuery = unescape(URLQuery);
	upperCaseURLQuery=URLQuery.toUpperCase()
	if (upperCaseURLQuery.indexOf("AICC-SID")>-1) {
		alert("Lesson Server version incompatible.  Your administrator must upgrade to the latest version.");
		return false;
	}
	if ((pos=upperCaseURLQuery.indexOf("AICC_SID"))>-1) {
		sessionID=URLQuery.substring(pos+9,URLQuery.length)
		if (sessionID.indexOf("&")>0)
		sessionID=sessionID.substring(0,sessionID.indexOf("&"))
	}
	if ((pos=upperCaseURLQuery.indexOf("AICC_URL"))>-1) {
		aiccURL=URLQuery.substring(pos+9,URLQuery.length)
		if (aiccURL.indexOf("&")>0)
			aiccURL=aiccURL.substring(0,aiccURL.indexOf("&"))
		if ((aiccURL.indexOf("http://") == -1) && (aiccURL.indexOf("file://") == -1))
			aiccURL = "http://" + aiccURL; // on tente par http
	}
	if (aiccURL=="" || sessionID=="")
	{
		if (win == window.top) 
			return false;
		return isCMIContext(win.parent)
	}
	else 
	{
		if(trackingAPIMode == TACTIC_JAVA_API_MODE)
			document.write("<APPLET code=brwlms_api.class HEIGHT=0 ID=API NAME=API WIDTH=0 MAYSCRIPT='true'><PARAM NAME='url' VALUE='" + aiccURL + "'><PARAM NAME='sid' VALUE='" + sessionID + "'><PARAM NAME='version' VALUE='2.0'></APPLET>");
		else if(trackingAPIMode == TACTIC_XML_HTTP_API_MODE)
			document.API = new xmlHttpAPI(aiccURL, sessionID);
		else
			return false;			
		return true;
	}
} 

/******************************************************************************************
**
** Function findAPI(win)
** Inputs:	win - a Window Object
** Return:	If an API object is found, it is returned, otherwise null is returned.
**
** Description:
** This function looks for an object named API in the supported window hierarchy, 
** 
******************************************************************************************/
var _Debug = false;
function findAPI(win) 
{
   // Search the window hierarchy for an object named "API"  
   // Look in the current window (win) and recursively look in any child frames

   if (_Debug)
   {
      alert("win is: "+win.location.href);
   }

   if(runTimeEnvType >= runTimeEnvSCORM13)
   {
      if (win.API_1484_11 != null)
      {
         if (_Debug)
         {
            alert("found api in this window");
         }
         return win.API_1484_11;
      }
      // pour NS4
      else if (win.document.API_1484_11 != null)
      {
         if (_Debug)
         {
            alert("found api in this window");
         }
         return win.document.API_1484_11;
      }
   }

   if(runTimeEnvType <= runTimeEnvSCORM12)
   {
      if (win.API != null)
      {
         if (_Debug)
         {
            alert("found api in this window");
         }
         return win.API;
      }
      // pour NS4
      else if (win.document.API != null)
      {
         if (_Debug)
         {
            alert("found api in this window");
         }
         return win.document.API;
      }
   }

   if (win.length > 0)  // does the window have frames?
   {
      if (_Debug)
      {
         alert("looking for api in windows frames");
      }

      for (var i=0;i<win.length;i++)
      {
         if (_Debug)
         {
            alert("looking for api in frames["+i+"]");
         }
         var theAPI = findAPI(win.frames[i]);
         if (theAPI != null)
         {
            return theAPI;
         }
      }
   }

   if (_Debug)
   {
      alert("didn't find api in this window (or its children)");
   }
   return null;
}

/******************************************************************************************
**
** Function getAPI()
** Inputs:	none
** Return:	If an API object is found, it is returned, otherwise null is returned.
**
** Description:
** This function looks for an object named API, first in the current window's hierarchy, 
**  and then, if necessary, in the current window's opener window hierarchy (if there is
**  an opener window).
******************************************************************************************/
function getAPI()
{
//alert('getAPI called!');
   // start at the topmost window - findAPI will recurse down through
   // all of the child frames
   var theAPI = findAPI(this.top);

   if (theAPI == null)
   {
      // the API wasn't found in the current window's hierarchy.  If the
      // current window has an opener (was launched by another window),
      // check the opener's window hierarchy. 
      if (_Debug)
      {
         alert("checking to see if this window has an opener");
         alert("window.opener typeof is> "+typeof(window.opener));
      }

      if (typeof(this.opener) != "undefined")
      {
         if (_Debug)
         {
            alert("checking this windows opener");
         }
         if (this.opener != null)
         {
            if (_Debug)
            {
               alert("this windows opener is NOT null - looking there");
            }
            theAPI = findAPI(this.opener);
         }
         else
         {
            if (_Debug)
            {
               alert("this windows opener is null");
            }
         }
      }
   }

   return theAPI;
}


/******************************************************************************************
** Function StringToArray(pathstr)
** Inputs:	String that represente the path of the document (e.g, [1,0,3])
** Output:	the convertion of the string to an initilized array object.
** Description: parses the string and create an array object initialized with the values
**				contained in the string (e.g, Array("1","0","3")).
******************************************************************************************/
function StringToArray(pathstr){
	arrpath = new Array();
	var i=0, pos, pos2, nb;
	pathstr=pathstr+"";
	pos = pathstr.indexOf("[");
	pathstr = pathstr.substring(parseInt(pos+1),pathstr.length);
	do{
		pos=pathstr.indexOf(",");
		if (pos == parseInt("-1")){	
			pathstr = pathstr.substring(0, pathstr.indexOf("]"));
			nb = pathstr;
		}else{
			nb = pathstr.substring(0,pos);
			pathstr = pathstr.substring(pos+1, pathstr.length);
		}

		// Netscape met des guillemets parfois, il faut les enlever
	        pos2 = nb.indexOf("\"");
	        if(pos2 != -1)
                   nb = nb.substring(parseInt(pos2)+1,nb.length-1);

		arrpath[i] = parseInt(nb);
		i++;
	}while( parseInt(pos) != parseInt("-1"));
	return arrpath;
}

/******************************************************************************************
** Function ConvertTimeToSecond()
** Inputs:
** Output: time in seconds elapsed since 01/01/1970 from now.
** Description: 
******************************************************************************************/
function ConvertTimeToSecond(){	
	var ss = new Date();

	return Math.round(ss/1000);
}

/******************************************************************************************
** Function getTimeDiff(startTime,endTime)
** Inputs: startTime and endTime in seconds since 01/01/1970.
** Output: time string as "HH:MM:SS"/ For SCORM1.3 PT..H..M..S
** Description: 
******************************************************************************************/
function getTimeDiff(s1,s2){
	var strTime = "",
		d = s2 - s1,
		hh = Math.floor(d/3600),
		mm = Math.floor(d/60) - hh*60,
		ss = d % 60;
	if((parent != null) && (parent.runTimeEnvType != null) &&  (parent.runTimeEnvType >= runTimeEnvSCORM13))
	{	
		strTime= "PT"
		if(hh>0)
			strTime+= hh + "H";
		if(mm>0)	
			strTime+= mm+ "M";
		if(ss>0)
			strTime+=  Math.round(ss*100)/100 + "S";
	}
	else
	{
		if(hh<10)
			strTime+= "0"; 
		strTime+= (hh +":");
		if(mm<10)
			strTime+= "0"; 
		strTime+= mm + ":";
		if(ss<10)
			strTime+= "0"; 
		strTime+= ss;
	}
	return strTime;
}


///////////////////////////////////////////////////////////////////////

function rollover(obj, newImg)
{
  if(obj)
    obj.src = newImg;
}


///////////////////////////////////////////////////////////////////////
// Banners


var TOP_BANNER = 0;
var BOTTOM_BANNER = 1;
var BANNER_PREV_DOC = 0;
var BANNER_NEXT_DOC = 1;
var BANNER_TACTIC_DOC = 2;
var ID_STANDARD_IMG = 0;
var ID_DISABLED_IMG = 1;
var ID_HOVER_IMG = 2;
var ID_SELECTED_IMG = 3;
var ID_ENABLED_CLASS = 0;
var ID_DISABLED_CLASS = 1;


// informations sur un bouton
function bannerButton(buttonId, buttonType, arrImg, arrClass)
{
	this.id = buttonId; // id du div
	this.buttonType = buttonType; // type du bouton prev/next
	this.arrImg = arrImg; // tableau des images (standard, disabled, hover, selected)
	this.arrClass = arrClass; // tableau des styles (actif, inactif)
}

function banner()
{
	this.arrButtons = null;
}

function bannerMgr()
{
	this.arrBanners = null;
	this.init = bannerInit;
	this.addButton = addBannerButton;
	this.updateButtons = updateBannerButtons;
	this.enableButton = enableBannerButton;
	this.disableButton = disableBannerButton;
}

function bannerInit()
{
	arrBanners = new Array();
	arrBanners[arrBanners.length] = new banner(); // top banner
	arrBanners[arrBanners.length] = new banner(); // bottom banner
	arrBanners[TOP_BANNER].arrButtons = new Array();
	arrBanners[BOTTOM_BANNER].arrButtons = new Array();	
}

// Ajouter un bouton au tableau
function addBannerButton(bannerId, buttonId, buttonType, arrImg, arrClass)
{	
	arrBanners[bannerId].arrButtons[arrBanners[bannerId].arrButtons.length] = new bannerButton(buttonId, buttonType, arrImg, arrClass);
}

// Processus d'activation/désactivation des boutons de la bannière
function updateBannerButtons(bannerFrame)
{	
return;
	if((parent.TOC == null) || (parent.TacticDocument == null))
		return;
	
	var arrButtons = arrBanners[bannerFrame.bannerId].arrButtons;
	// parcourir le tableau des boutons
	for (var i=0; i< arrButtons.length; i++)
	{	// objet link
		var objLink = bannerFrame.document.getElementById(arrButtons[i].id).children(0);
		var isButtonToUpdate = false;
		var bDisableButton = false;
		// traiter les boutons prev/next
		switch (arrButtons[i].buttonType)
		{	
			case 0 : // BANNER_PREV_DOC : activer le bouton si un document précédent existe
				if (!parent.TacticDocument.canGoPrevDoc()) // pas de document précédent
					bDisableButton = true;
				isButtonToUpdate = true;
				break;
			case 1 : // BANNER_NEXT_DOC : activer le bouton si un document suivant existe
				if (!parent.TacticDocument.canGoNextDoc()) // pas de document suivant
					bDisableButton = true;
				isButtonToUpdate = true;
				break;
//			case 2 : // BANNER_TACTIC_DOC : activer le bouton si il y a une destination
//				if (objLink.href == "" || objLink.href == "#" || objLink.href == "javascript:void(0);") // pas de destination
//					bDisableButton = true;
//				isButtonToUpdate = true;
//				break;
		}

		// Selon le diagnostic ci-haut, activer/désactiver le bouton		
		if (isButtonToUpdate && bDisableButton)
			disableBannerButton(objLink, arrButtons[i].arrImg[ID_DISABLED_IMG], arrButtons[i].arrClass[ID_DISABLED_CLASS]);
		else
			enableBannerButton(objLink, arrButtons[i].arrImg, arrButtons[i].arrClass[ID_ENABLED_CLASS]);

	}
}

//désactiver un bouton : changer image(standard, hover,..), style
function disableBannerButton(objLink, strDisableImg, strDisableStyle)
{
	var objImg = objLink.children(0);
	objImg.src = strDisableImg;
	objLink.onmouseover = function(){rollover(objImg, strDisableImg);};
	objLink.onmouseout  = function(){rollover(objImg, strDisableImg);};
	objLink.onmousedown = function(){rollover(objImg, strDisableImg);};
	objLink.onmouseup =   function(){rollover(objImg, strDisableImg);};
	objLink.className = strDisableStyle;
}

//activer  un bouton 
function enableBannerButton(objLink, arrImg, strEnableStyle)
{
	var objImg = objLink.children(0);
	objImg.src = arrImg[ID_STANDARD_IMG];
	objLink.onmouseover = function(){rollover(objImg, arrImg[ID_HOVER_IMG]);};
	objLink.onmouseout  = function(){rollover(objImg, arrImg[ID_STANDARD_IMG]);};
	objLink.onmousedown = function(){rollover(objImg, arrImg[ID_SELECTED_IMG]);};
	objLink.onmouseup =   function(){rollover(objImg, arrImg[ID_HOVER_IMG]);};
	objLink.className = strEnableStyle;
}

 