//
//  12/24/2001   B.Law      Added call to routeEvent(e) for each mouse even handler to allow all objects to have a shot at handling the event.
//  02/27/2002   B.Law/JB   Added new code for handling live event messages.
//  04/09/2002   B.Law      Added check for null to OnLiveMessage function.
//  04/26/2002   B.Law/JB   Added code to autoreconnect live applet if error occurs.
//  05/06/2002   B.Law      Added getQueryStringValue to be used in place of GetParamFromQueryString when appropriate.
//  06/17/2002   B.Law      Added getUrlPathParent(...) function.
//  06/24/2002   B.Law      Added getFormQuerystring(...) function.
//  7/15/2002    J.B.       Modified LiveClient code to work with v2.
//  09/04/2002   B.Law      Synched with v1.x --- a few functions were missing.
//  10/07/2002   B.Law      Modified LoadSyncData(...) to use the new "cache-file synchronization" method instead of an .JSP page.
//  10/08/2002   B.Law      Modified DoSync to accept an optional array of event timestamps.
//  10/08/2002   B.Law      Added timestamp as a parameter to LiveEventCmd. Timestamp is the time elapsed in milliseconds since the first event was triggered.
//  10/10/2002   B.Law      Modified ReplaceElementInnerHTML(...) function to use setTimeout on Netscape browsers --- timing issue with replacing inner text.
//  10/23/2002   B.Law      Added setSyncBaseTime(...) to allow synchronization of event files with a time source.
//  11/4/2002    B.Law      Fixed "collapsing" logic and event file logic.
//	11/4/2002	 J.B.		Modified OnLiveMessage to handle control messages "live" and synced
//  12/02/2002   B.Law      Modified ReplaceElementInnerHTML to keep a reference to the object for part 2 instead of trying by name --- the by name method fails in Netscape for QAResult on different domains.
//  12/18/2002   J.B.       Updated live applets to work with Netscape.
//  12/21/2002   B.Law      Modified GetElement to do more checking before the embeds element so we don't get an access violation in Netscape.
//  1/13/2003    J.B.       Added Precache Image code.
//  1/17/2003    J.B.       Added GetURLPath(w) to return the entire path including server
//  02/04/2003   B.Law      Modified SetStyle to check for existence of object to avoid errors.
//  02/13/2003   B.Law      Added window error handling code.
//  03/17/2003   B.Law      Modified to have a flag that determines whether to use injected times (akamai injected times).
//  03/20/2003   B.Law      Modified getQueryStringValue_helper(...) to unescape + signs back to spaces.
//	04.14/2003	 J.B.		Modified getQueryStringValue to allow for top level frame from other domains
//  05/14/2003   B.Law      Added mpDebug(s) that can be used for sending debug messages
//	05/16/2003	 J.B.		Added Netscape7 handlers to SetStyle
//	05/30/2003	 J.B.		Fixed a bug in TryReconnect where i should have been appletID
//  06/05/2003   B.Law      Added Timeout for synch process to retry synching if taking too long
//  06/09/2003   B.Law      Added deltaSync time
//  06/13/2003   B.Law      Added appendPassthroughParameters(...) method.
//  07/24/2003   B.Law      Added addPassthroughParameter(...) method so new passthrough parameters can be added at runtime.
//  07/24/2003   B.Law      Added some AICC parameters as default passthroughs so we are AICC compliant.
//  10/29/2003   J.B.       Added NotifyListeners and PrependZero functions
//	10/30/2003   J.B.		Moved VideoComponent2.js player states from there to here so Time Component could have access to them for StatusBar compinent
//	11/07/2003	 J.B.		updateScript trick didnt work with Netscape 7. First time update occurred then the SCRIPT tag was dead and setting the src did nothing
//								Fixed NS7 by doing a createElement('script') call every time. No significant resource hit was noticed
//  12/11/2003   B.Law      Modified getFormQuerystring to correctly handle radio and checkboxes and to skip non-input fields.
//	12/15/2003	 J.B.		Added the function SetStyleInDoc which works just like SetStyle but accepts a target document to operate on. Modified SetStyle to call SetStyleInDoc
//	12/16/2003	 J.B.		Modified Netscape Event Handling functions for simplification
//	01/14/2003	 J.B.		Added AddNoSyncCollapseFunction to allow functions to be defined that dont collapse for efficiency during sync. Useful for functions such as NextSlide
//	03/10/2004	 J.B.		Changed LoadSyncData to use a non caching querystring of 0-4 rather than a unique id every time with Date();
//	09/13/2004	 J.B.		Added code to allow Mozilla to participate in Live Events using http polling of Live Server
//   10/12/2004   B.Law     Modified getQueryStringValue to strip a trailing "#" off the string if one exists... this can result from a <A href='#'...> reference on a page
//	10/18/2004	 J.B.		Changed Live Client initialization. Any time there are no available clients fails over to http polling regardless of browser
//

var TIMEWARP_TOLERANCE = 750;	// milliseconds to determine when a "time warp" has taken place

////////////////// Global Functions /////////////////////
var PLAYER_STOPPED = 0;
var PLAYER_PAUSED = 1;
var PLAYER_PLAYING = 2;
var PLAYER_BUFFERING = 3;
var PLAYER_SEEKING = 4;
var PLAYER_CLOSED = 5;
var PLAYER_OPENING = 6;
var PLAYER_CONNECTING = 7;

var g_deltaSync = 10000;

var UD_HandleMouseOver = null;
var UD_HandleMouseOut = null;
var UD_HandleMouseUp = null;
var UD_HandleMouseDown = null;

var g_preventUnload = false;

function Component(name)
{
	this.name = name;
	for(var i=1;i< arguments.length;i++)
	{
		nv = arguments[i].split("=");
		this[nv[0]] = nv[1];
	}
}

function Element(name)
{	
	for(var i=0;i< elementArray.length;i++)
		if(elementArray[i].name ==name)
			return elementArray[i];
}

function NotifyListeners(notifier,eventName,paramArray,paramTypeArray)
{
	var l = listeners[notifier];
	if(l)
	{
		var tcList = l[eventName];
		if(tcList)
		{
			for(var i=0;i< tcList.length;i++)
			{
				if(typeof(eval(tcList[i])) == "function")
				{
					funcStr = tcList[i]+"(";
					for(var j=0;j< paramArray.length;j++)
					{
						var type = "STRING";
						if(paramTypeArray)
						{
							if(paramTypeArray[j])
								type = paramTypeArray[j];
						}
						if(j>0)
							funcStr += ",";
						if(type.toUpperCase()=="STRING")
							funcStr+="\""+paramArray[j]+"\"";	
						if(type.toUpperCase()=="NUMBER")
							funcStr+=paramArray[j];	
						if(type.toUpperCase()=="BOOLEAN")
						{
							funcStr+=paramArray[j];	
						}
					}
					funcStr += ")";
					eval(funcStr);
				}
			}
		}
	}
}

function PreventUnload()
{
	g_preventUnload = true;
}

function PrependZero(str)
{
	str = ""+str;
	if(str.length<2)
		return "0"+str;
	else
		return str;
}

////////////////////////////////////////////////////////////////////////////
////////////////////////////Live Events/////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
function LiveEventCmd(targetType,targetID,senderType,senderID,index,cmd,timestamp)
{
	this.targetType = targetType;
	this.targetID = targetID;
	this.senderType = senderType;
	this.senderID = senderID;
	this.index = index;
	this.cmd = cmd;
	this.timestamp = timestamp;
}

var eventQueue = new Array();
var msgHistory = new Array();

function LIVE_CLIENT_OnMessage(msg)
{
	for(var i=0;i<msgHistory.length;i++)
	{
		if(msgHistory[i] == msg)
			return;
	}
	msgHistory[i] = msg;

	OnLiveMessage(msg);
}

function LIVE_CLIENT_OnError(errCode,errMsg,appletID)
{
	if(errCode == "400" || errCode == "401" || errCode == "420")
	{
		window.setTimeout("TryReconnect("+appletID+")",5000);
	}
}

var initAppletList = new Array();
function LIVE_CLIENT_OnLoad(applet)
{
	var count = initAppletList.length;
	initAppletList[count] = applet;
	applet.SetAppletID(count);
	if(!applet.Connect(deploymentGUID)) 
		TryReconnect(count);
	else
	{
		HTTP_CheckEvents_Failover = false;
		HTTP_CheckEvents_Continue = false;
	}
}

function InitLiveClient()
{
	if(initAppletList.length==0)
	{
		HTTP_CheckEvents_Failover = true;
		HTTP_CheckEvents_Continue = true;
		window.setTimeout("HTTP_CheckEvents();",3000);
		return;
	}
}
function TryReconnect(appletID)
{
	HTTP_CheckEvents_Continue = true;
	if(!HTTP_CheckEvents_Failover)
	{
		window.setTimeout("HTTP_CheckEvents();",100);
		HTTP_CheckEvents_Failover = true;
	}

	var success = initAppletList[appletID].Connect(deploymentGUID);

	if(!success)
		window.setTimeout("TryReconnect("+appletID+")",5000);
	else
	{
		HTTP_CheckEvents_Failover = false;
		HTTP_CheckEvents_Continue = false;
	}
	
}
var HTTP_CheckEvents_Failover = false;
var HTTP_CheckEvents_Continue = true;
var HTTP_CheckEvents_Last = 0;
var HTTP_Current_Live_Client = 0;
function HTTP_CheckEvents()
{
window.status = "CheckEvents "+HTTP_CheckEvents_Last;
	var usc_elem = document.createElement('script');
	document.documentElement.appendChild(usc_elem);
	usc_elem.onerror = HTTP_CheckEvents_Error;
	usc_elem.src = liveClientList[HTTP_Current_Live_Client].server+"/geteventjs.htm?guid="+deploymentGUID+"&last="+HTTP_CheckEvents_Last
}

function HTTP_CheckEvents_Error(e)
{
	HTTP_Current_Live_Client++;
	if(HTTP_Current_Live_Client >= liveClientList.length)
		HTTP_Current_Live_Client = 0;
	window.setTimeout("HTTP_CheckEvents();",100);
}

function LEI(interval)
{
	if(HTTP_CheckEvents_Continue)
		window.setTimeout("HTTP_CheckEvents();",interval);
}

function LEC(lastTime,msg)
{
	HTTP_CheckEvents_Last = lastTime;
	LIVE_CLIENT_OnMessage(unescape(msg));
}


function OnLiveMessage(msg)
{

	if(synced)
		ParseMessage(msg);
	else
		QueueMessage(msg);
}

function ParseMessage(msg)
{
	var valid = false;
	var senderType = "m";
	if(msg.substring(0,1) == "#")
	{
		msg = msg.substring(1);
		var msgArray = msg.split(":");
		valid = IsMessageValid(msgArray[0],msgArray[1]);

		if(valid)
		{
			for(var i=0;i<2;i++)
			{
				var index = msg.indexOf(":");
				msg = msg.substring(index+1);
			}

			var index = msg.indexOf(":");
			senderType = msg.substring(0,index);
			msg = msg.substring(index+1);
		}
	}
	else
	{
		valid = true;
	}
	if(valid)
	{
		index = msg.indexOf(":");
		var senderID = msg.substring(0,index);
		msg = msg.substring(index+1);
		index = msg.indexOf(":");
		var msgIndex = msg.substring(0,index);
		var cmd = msg.substring(index+1);

		FireCommand(cmd,true);
	}

}

function QueueMessage(msg)
{
	var targetType = "*";
	var targetID = "*";
	var senderType = "m";
	var index = 0;
	if(msg.substring(0,1) == "#")
	{
		msg = msg.substring(1);

		index = msg.indexOf(":");
		targetType = msg.substring(0,index);
		msg = msg.substring(index+1);

		index = msg.indexOf(":");
		targetID = msg.substring(0,index);
		msg = msg.substring(index+1);

		index = msg.indexOf(":");
		senderType = msg.substring(0,index);
		msg = msg.substring(index+1);
	}

	index = msg.indexOf(":");
	var senderID = msg.substring(0,index);
	msg = msg.substring(index+1);

	index = msg.indexOf(":");
	var cmdIndex = msg.substring(0,index);

	var cmd = msg.substring(index+1);

	eventQueue[eventQueue.length]=new LiveEventCmd(targetType,targetID,senderType,senderID,cmdIndex,cmd);
	if(!synchronizing)
		LoadSyncData(false,true);

}

function IsMessageValid(targetTypeStr,targetIDStr)
{
	var targetTypeArray = targetTypeStr.split(",");
	var targetIDArray = targetIDStr.split(",");

	var valid = false;
	for(var i=0;i<targetTypeArray.length;i++)
	{
		if(targetTypeArray[i] == "*")
		{
			valid = true;
		}
		else if(targetTypeArray[i] == commandCode)
		{
			var j=0;
			if(targetIDArray.length > i)
				j = i;
			else
				j=targetIDArray.length-1;

			if(targetIDArray[j] == "*")
			{
				valid = true;
			}
		}
	}
	return valid;

}

function LoadSyncData_Timeout(force,useEventSyncFile)
{
	// If we aren't synched yet, and we should be synchronizing, try again... maybe
	// sync file didn't exist yet
	if (!synced  &&  synchronizing) {
		LoadSyncData(force, useEventSyncFile);
	}
}

var noCacheIndex = 0;
function LoadSyncData(force,useEventSyncFile)
{ 
	if(useEventSyncFile)
	{
		var preventCacheString = "?cache=" + Math.random()*1000000; 
//		var preventCacheString = "?cache=" + ((noCacheIndex++)%5); 

		if (synced  &&  !force)
			return;

		if(!force)
			setTimeout("LoadSyncData_Timeout("+force+","+useEventSyncFile+")", 10000);

		synchronizing = true;

		if (IE4)
			document.getElementById("updateScript").src = syncURL + ".ie" + preventCacheString;
		else if(!NS4)
		{
			var usc_elem = document.createElement('script');
			document.documentElement.appendChild(usc_elem);
			usc_elem.src = syncURL + ".ie" + preventCacheString;
		}
		else
			document['updateLayer'].load(syncURL + ".html" + preventCacheString, 100);
	}
	else
	{
		var preventCacheString = "&cache=" + ((noCacheIndex++)%5);

		if(synced)
			return;

		if(!force)
			setTimeout("LoadSyncData_Timeout("+force+","+useEventSyncFile+")", 10000);

		synchronizing = true;

		if (IE4) 
		   document.getElementById("updateScript").src = syncURL + "/sync.jsp?ns=0&guid=" + deploymentGUID + preventCacheString;
		else if(!NS4)
		{
			var usc_elem = document.createElement('script');
			document.documentElement.appendChild(usc_elem);
			usc_elem.src = syncURL + "/sync.jsp?ns=0&guid=" + deploymentGUID + preventCacheString;
		}
		else 
		   document['updateLayer'].load(syncURL+"/sync.jsp?ns=1&guid=" + deploymentGUID + preventCacheString,100);
	}
}


function EVENT_OnSync(eventArchive)
{
	DoSync(eventArchive);
}

/**
 *  Collapses all duplicate events in an event array optionally up to msEnd timestamp. Collapsing
 *  means replacing earlier occurrences of the same event with an empty string so the command
 *  isn't executed unnecessarily (for example, gotoslide in ppt --- only the last occurence is
 *  really necessary).
 */
var g_noCollapse = new Object();
function AddNoSyncCollapseFunction(funcName)
{
	g_noCollapse[funcName] = true;
}
function syncCollapseDuplicates(eventArray, nBegin, msEnd)
{
	for (var j=nBegin; j<eventArray.length; j++) {
		var curCmd = eventArray[j].cmd;
		if(curCmd=="")
			continue;
		var funcName = curCmd.substring(0,curCmd.indexOf("("));
		if(!g_noCollapse[funcName])
		{
			for (var k=j; k<eventArray.length; k++) {
				if (msEnd)
					if (eventArray[k].timestamp >= msEnd) break;

				var cmpCmd = eventArray[k].cmd;
				if(cmpCmd == "")
					continue;
				var index = curCmd.indexOf(",");
				if(index != -1)
				{
					if (curCmd.substring(0,index) == cmpCmd.substring(0,index) && curCmd.substring(index) != cmpCmd.substring(index) ) {
						eventArray[j].cmd = "";
						break;
					}
				}
			}
		}
	}
}


var g_msLastSyncPoint = new Date().getTime();	// Time last sync timestamp was received
var g_msLastTimestamp = 0;						// Last timestamp from "timesource"
var g_msStartTimestamp = 0;						// Timestamp of first event in array (i.e. timestamp for deltaTime=0)
var g_eventList = new Array();					// Current eventList array
var g_indexEventList = 0;						// Index into g_eventList of next command to execute

function syncLoop()
{
	// Wait until we receive first sync point to actually do the first synchronization
	if (g_msLastTimestamp == 0) {
		setTimeout("syncLoop()", 500);
//window.status = "waiting for first synch point";
		return;
	}

	if (g_indexEventList >= g_eventList.length) return;

	var ms = getCurrentSyncTime();

//window.status = "currentTime=" + ms + ",waiting for " + g_eventList[g_indexEventList].timestamp + ", " + (g_eventList[g_indexEventList].timestamp - ms) + " ms";

	syncCollapseDuplicates(g_eventList, g_indexEventList, ms);

	// Loop through events and execute any that the time is right...
	for ( ; g_indexEventList < g_eventList.length; g_indexEventList++) {
		var evt = g_eventList[g_indexEventList];
		if (!evt) continue;
		if (evt.cmd == "") continue;
		if (evt.timestamp > ms) {
			setTimeout("syncLoop()", 500);
			return;
		}
		FireCommand(evt.cmd,true);
	}
}

// eventArchive is the array
function DoSync(eventArchive, msStartTimestamp)
{
	for (var j=0; j<eventArchive.length; j++) {
		var valid = IsMessageValid(eventArchive[j].targetType,eventArchive[j].targetID);
		if(!valid)
			eventArchive[j].cmd = "";
	}

	// If a start timestamp is passed in, assume we are synching to a "timesource"
	if (msStartTimestamp  &&  getUseInjectedTimes()) {
		if (msStartTimestamp > 0) {
			g_msStartTimestamp = msStartTimestamp;
			g_eventList = eventArchive;
			g_msLastSyncPoint = new Date().getTime();
			syncLoop();
			return;
		}
	}

	syncCollapseDuplicates(eventArchive, 0);

	var inSync = (eventQueue.length == 0);
	for (; g_indexEventList<eventArchive.length; g_indexEventList++) {
		// If we are now overlapping events being received, exit now
		if (eventQueue.length!=0 && (eventArchive[g_indexEventList].senderID == eventQueue[0].senderID && eventArchive[g_indexEventList].index == eventQueue[0].index)) {
			inSync = true;
			break;
		}
		else {
			if (eventArchive[g_indexEventList] && eventArchive[g_indexEventList].cmd != "") {
				FireCommand(eventArchive[g_indexEventList].cmd,true);
			}
		}
	}

//	if(!inSync)
//		alert("Sync not possible due to data loss. Cache ends at:"+i+". Queue begins at:"+opener.eventQueue[0].index);

	// Fire all events that came in while synchronization was taking place
	for (i=0; i<eventQueue.length; i++) {
		var valid = this.IsMessageValid(eventQueue[i].targetType,eventQueue[i].targetID);
		if (valid)
			FireCommand(eventQueue[i].cmd,true);
	}
	synced = true;
	synchronizing = false;
}


/**
 *  Return the current sync time --- this is the current offset in milliseconds from the beginning
 *  of the presentation.
 */
function getCurrentSyncTime()
{
	return (g_msLastTimestamp - g_msStartTimestamp) + (new Date().getTime() - g_msLastSyncPoint) + g_deltaSync;
}

/**
 *  Set the current base synch point --- can be used to "reset" the internal timer at any time.
 *  First implementation that calls this is the Akamai conference system --- timestamps are embedded
 *  in the stream, and this function is called every time a timestamp is hit. Basetime should be
 *  passed in as the # of seconds since 1/1/70. NOTE: The "current" value can be gotten in javascript
 *  using code like "new Date().getTime() / 1000".
 */
function setSyncBaseTime(baseTime)
{
	var nSecs = parseInt(baseTime);
	if (isNaN(nSecs)) return;
	g_msLastTimestamp = new Date(nSecs * 1000).getTime();
	g_msLastSyncPoint = new Date().getTime();
}

///////////////////////////////////////////////////////////////////////
function GetParamFromQueryString(name, params) 
{
  var   offset = params.indexOf(name);

  if (offset == -1)
    return "";

  offset += name.length + 1;  // adjust for equal sign
  
  var   length = params.indexOf("&", offset);
  
  if (length == -1)
    length = params.length;
 
  return params.substr(offset, length - offset);
}

function getQueryStringValue_helper(name, qs)
{
	if (name == null  ||  qs == null)
		return "";

	var b = qs.split("&");
	for (var i=0; i<b.length; i++) {
		var c = b[i].split("=");
		if (c.length < 2) continue;
		var paramName = unescape(c[0].replace(/[+]/g," "));
		if (paramName.toUpperCase() == name.toUpperCase())
			return unescape(c[1].replace(/[+]/g," "));
	}
	return "";
}

function getQueryStringValue(name)
{
	// Searches for a QueryString parameter in this document's URL or any
	// of the parent's URL's up to maxLevels deep
	var maxLevels = 10;
	var w = window;

	while (w != null && typeof(w.document)!="unknown" && (--maxLevels > 0)) 
	{
		try
		{
			var qs_str = w.document.location.href; 
			if (qs_str.substr(qs_str.length-1, 1) == "#") qs_str = qs_str.substr(0, qs_str.length-1);
			var a = qs_str.split("?");
			if (a.length > 1) {
				var result = getQueryStringValue_helper(name, a[1]);
				if (result.length > 0)
					return result;
			}
			w = w.parent;
		}
		catch(e)
		{
			w = null;
		}
	}

	return "";
}

// includes the / at the end
function GetURLPath(w)
{
	var path = w.document.location.href;
	var index = path.indexOf("?");
	if(index!=-1)
		path = path.substring(0,index);
	index = path.lastIndexOf("/");
	path = path.substring(0,index+1);
	return path;
}

function getUrlPathParent(w,nParents)
{
	// Returns just the PATH portion of a URL, and goes up the parent levels nParents times
	if (!nParents) nParents = 1; else nParents++;
	var a = w.document.location.href.split("?");
	var b = a[0].split("//");
	var n = b[1].indexOf("/");
	var path = b[1].substring(n+1);
	for (var i=0; i<nParents; i++) {
		n = path.lastIndexOf("/");
		if (n > 0) path = path.substring(0, n); else path = "";
	}
	if (path.length > 0) path = "/" + path;
	return path;
}

function DefineEvents()
{
	if(NS4)
	{
		if(window.Event)
		{
			window.captureEvents(Event.MOUSEUP|Event.MOUSEOVER|Event.MOUSEOUT);
		}

		window.onmouseup=Window_HandleMouseUp;
		window.onmouseover=Window_HandleMouseOver;
		window.onmouseout=Window_HandleMouseOut;
	}

}

function Window_HandleMouseUp(e)
{
	if(e.target=="")
		HandleClick();
	routeEvent(e);
}

function Window_HandleMouseOver(e)
{
	if(typeof(e.target.name)!="undefined")
		routeEvent(e);
}

function Window_HandleMouseOut(e)
{
	if(typeof(e.target.name)!="undefined")
		routeEvent(e);
}

function GetChild(elem,elemID)
{
	if(NS4)
	{
		var child =  elem.document[elemID];
		if(!child)
		{
			for(var i=0;i<elem.document.forms.length;i++)
			{
				if((child = elem.document.forms[i].elements[elemID]) != null)
					break;
			}
		}
		return child;
	}
	else if(IE4)		
	{
		var child =  elem.children[elemID];
		if(!child)
		{
			for(var i=0;i<elem.document.forms.length;i++)
			{
				if((child = elem.document.forms[i].children[elemID]) != null)
					break;
			}
		}
		return child;
	}
	else
	{
		return document.getElementById(elemID);
	/*
		for(var i=0; i< elem.childNodes.length;i++)
		{
		alert(elem.childNodes[i].id);
			if(elem.childNodes[i].id == elemID)
				return elem.childNodes[i];
		}
		return null;
	*/
	}

}

function GetChildID(elem,elemID)
{
	if(NS4)
		return GetChild(elem,elemID).name;
	else		
	{
		return GetChild(elem,elemID).id;;
	}

}

function GetElemID(elem)
{
	if(NS4)
		return elem.name;
	else		
	{
		return elem.id;;
	}

}
///////////////////////////////////////////////////
var IVT_callUpdateBlocked = false;
var IVT_unblockTimer = null;
function CallUpdate(scriptName,layerName,url)
{
	if (!NS4)
		document.getElementById(scriptName).src = url;
	else
	{
		if(IVT_callUpdateBlocked)
			IVT_WaitUpdateBlocked(layerName,url);
		else
			IVT_ExecuteUpdate(layerName,url);
	}

}

function IVT_WaitUpdateBlocked(layerName,url)
{
	if(!IVT_callUpdateBlocked)
		IVT_ExecuteUpdate(layerName,url);
	else
		window.setTimeout("IVT_WaitUpdateBlocked('"+layerName+"','"+url+"');",1000);
}

function IVT_ExecuteUpdate(layerName,url)
{
	IVT_callUpdateBlocked = true;
	document[layerName].onload = IVT_UpdateOnload;
	document[layerName].load(url+"&ns=1", 100);
	IVT_unblockTimer = window.setTimeout("IVT_callUpdateBlocked = false",10000);
}

function IVT_UpdateOnload()
{
	if(IVT_unblockTimer)
		window.clearTimeout(IVT_unblockTimer);
	IVT_unblockTimer = null;
	IVT_callUpdateBlocked = false;
}
//////////////////////////////////////////////////
function ParseScriptCommand(i,paramStr)
{
	if(NS4)
	{
		if(commandLock)
		{
			delayArray[delayArray.length] = paramStr;
		}
		else
		{
			commandLock = true;
			eval(paramStr);
			window.setTimeout("UnlockCommandLock();",50)
		}
	}
	else
		eval(paramStr+"");

}

var delayArray = new Array();
var commandLock = false
function UnlockCommandLock()
{
	for(var i=0;i< delayArray.length;i++)
	{
		if(delayArray[i] != null)
		{
			eval(delayArray[i]+"");
			delayArray[i] = null;
			window.setTimeout("UnlockCommandLock();",50);
			return;
		}
	}

	commandLock = false;
	delayArray = new Array();
}

function ReplaceElementInnerHTML(elem,htmlStr)
{
	if (NS4) 
	{
		var doc = elem.document;
		doc.open();
		doc.write(htmlStr);
		doc.close();
	}
	else 
	{
		elem.innerHTML = htmlStr;
	}
}
/*
var g_elems = new Array();
function ReplacePart2(n, html)
{
	var doc = g_elems[n].document;
	doc.open();
	doc.write(unescape(html));
	doc.close();
	g_elems[n] = null;
}

function ReplaceElementInnerHTML(elem,htmlStr)
{
	if (NS4) {
		var s = escape(htmlStr);
		var n = g_elems.length;
		g_elems[n] = elem;
		setTimeout("ReplacePart2(" + n + ", '" + s + "')", 50);
	}
	else {
		elem.innerHTML = htmlStr;
	}
}
*/

function GetStyle(elemID,styleName)
{
	var param = null;
	if(NS4)
	{
		var obj = document[elemID];
		if (obj)
			param = eval("obj."+styleName);
	}
	else
	{
		var obj = document.getElementById(elemID);
		if (obj)
			param = eval("obj.style."+styleName);
	}
	return param;

}

function SetStyleInDoc(doc,elementID,styleName,param)
{
	if (IE4) {
		if (styleName == "left") styleName = "posLeft";
		if (styleName == "top") styleName = "posTop";
		if (styleName == "width") styleName = "posWidth";
		if (styleName == "height") styleName = "posHeight";
	}
	if (NS4) {
		var obj = doc[elementID];
		if (obj == null) return;

		eval("doc[\"" + elementID + "\"]." + styleName + " = '" + param+"';");
	}

	if(IE4) {
		var obj = doc.all(elementID);
		if (obj == null) return;
		if (obj.length)
			eval("doc.all(\"" + elementID + "\")[0].style." + styleName + " = '" + param+"';");
		else
			eval("doc.all(\"" + elementID + "\").style." + styleName + " = '" + param+"';");
	}
	if(!IE4 && !NS4)
	{
		var obj = doc.getElementById(elementID);
		if (obj == null) return;
		eval("obj.style." + styleName + " = '" + param+"';");

	}
}


function SetStyle(elementID,styleName,param)
{
	SetStyleInDoc(document,elementID,styleName,param);
}


function IVT_Event_GetTarget(e)
{
	if(e.target == null)
		return e.srcElement;
	else
		return e.target;
	
}

function GetFrame(frameName)
{
	return GetFrameRecursive(window.top,frameName);
}
function GetFrameRecursive(frame,frameName)
{
	if(frame.name == frameName) return frame;
	var childframes = frame.frames;var i;
	for(i=0;i< childframes.length;i++){if((f=GetFrameRecursive(childframes[i],frameName)) != null) return f;}
	return null;
}

function GetElement(n, d) 
{ 
	if (n == null) return new Object();
	if (typeof(n) != "string") { return new Object(); }
	var p,i,x;  
	if(!d) 
		d=document; 
	if((p=n.indexOf("?"))>0&&parent.frames.length) 
	{
		d=parent.frames[n.substring(p+1)].document;
		n=n.substring(0,p);
	}

	if (d.getElementById) if (x = d.getElementById(n)) return x;

	if (x = d[n]) return x;
	if (x = d.applets[n]) return x;
	if (typeof(d) != "unknown") {
		if (d.location) {
			if (typeof(d.embeds) != "unknown") {
				if (d.embeds.length > 0)
					if (x = d.embeds[n]) return x;
			}
		}
	}

	if (d.all)
		if (x=d.all[n])
			return x;
		
//  Temporarily don't look at forms --- seems to cause an error in Netscape
//	for (i=0;!x&&i< d.forms.length;i++) 
//		x=d.forms[i][n];

	for(i=0;!x&&d.layers&&i< d.layers.length;i++) 
		x=GetElement(n,d.layers[i].document); 
	
	return x;
}

function TraverseDOM(d, callbackFunc) 
{ 
	var p,i,x;  
	if(!d) 
		return false; 

	for(i=0;d.images&&i< d.images.length;i++)
	{
		if(callbackFunc(d.images[i]))
			return true;
	}

	//  Temporarily don't look at forms --- seems to cause an error in Netscape
//	for(i=0;d.forms&&i< d.forms.length;i++) {
//		for(j=0;j< d.forms[i].length;j++) {
//			if(callbackFunc(d.forms[i][j]))
//				return true;
//			if(TraverseDOM(d.forms[i][j].document, callbackFunc))
//				return true; 
//		}
//	}

	for(i=0;d.layers&&i< d.layers.length;i++)
	{
		if(callbackFunc(d.layers[i]))
			return true;
		if(TraverseDOM(d.layers[i].document, callbackFunc))
			return true; 
	}
	return false;
	
}

function GetCleanLabel(label)
{
	return label.replace(/[ -]/g, '_');
}

function getFormQuerystring(frm)
{
	var s = "";

	// Returns a querystring representing the contents of the indicated form object
	for (var i=0; i<frm.elements.length; i++) {
		var o = frm.elements[i];
		if (o.name == null  ||  o.value == null) continue;
		if (o.name.length < 1  ||  o.value.length < 1) continue;
		if (o.type == 'button'  ||  o.type == 'image'  ||  o.type == 'reset'  ||  o.type == 'submit'  ||  o.type == 'file') continue;

		if (o.type == 'radio'  ||  o.type == 'checkbox') {
			if (!o.checked)
				continue;
		}
		s += ((s.length > 0 ? "&":"") + (escape(o.name) + "=" + escape(o.value)));
	}

	return s;
}

function replaceAll(findStr, replaceStr)
{
	re = new RegExp(findStr,"g");
	return(this.replace(re, replaceStr));
}
// Assign this function to all strings
String.prototype.replaceAll = replaceAll
String.prototype.ltrim = function () { return this.replace(/^\s+/g, "") } ;
String.prototype.rtrim = function () { return this.replace(/\s+$/g, "") } ;
String.prototype.trim  = function () { return this.ltrim().rtrim() }  ;
String.prototype.left  = function (count) { return this.substr(0,count); }  ;
String.prototype.right  = function (count) { return this.substr(this.length-count,count); }  ;

function Log10(x)
{
	if(x==0)
		x=.0000000001;
	return Math.log(x) / Math.log(10);
}

/////////////////////// Precache Image ////////////////////////////////
var PRECACHE_IMAGE_MAX_RETRIES = 10;
function PrecacheImage_OnError(precacheImage,precacheImageArray,loadCallback,precacheErrorCallback)
{
	if (precacheImage == null) 
		return;

	for (var i=0; i< precacheImageArray.length; i++) 
	{
		if (precacheImageArray[i] == precacheImage)
		{
			if (++precacheImageArray[i].tryCount >= PRECACHE_IMAGE_MAX_RETRIES)
			{
				if(typeof(precacheErrorCallback)=="function") precacheErrorCallback();
				loadCallback();
			}
			else
			{
				var qs = (precacheImageArray[i].originalSource.indexOf("?") > 0 ? "&":"?") + "retry=" + precacheImageArray[i].tryCount;
				precacheImageArray[i].src = precacheImageArray[i].originalSource + qs;
			}
			return;
		}
	}
}

function PrecacheImage(lurl,loadCallback,errorCallback)
{
	var img = new Image();
	img.onerror = errorCallback;
	img.onload = loadCallback;
	img.tryCount = 0;
	img.originalSource = lurl;
	img.src = lurl;
	return img;
}



function mpLog(s)
{
	var win = window.open("", "mpLog", "width=600,height=400,resizable=yes");
	if (typeof(win.document.frmLog) == "undefined") {
		html =
			"<HTML>\r\n" +
			"<HEAD>\r\n" +
			"<TITLE>MediaPlatform Logger</TITLE>\r\n" +
			"</HEAD>\r\n" +
			"<BODY>\r\n" +
			"<FORM name='frmLog'>\r\n" +
			"<TEXTAREA name='log' rows=15 cols=60 wrap=off style='width:100%;height:100%'>\r\n" +
			"</TEXTAREA>\r\n" +
			"</FORM>\r\n" +
			"</BODY>\r\n" +
			"</HTML>";

		win.document.open();
		win.document.write(html);
		win.document.close();
	}

	if (typeof(win.document.frmLog) != "undefined")
		win.document.frmLog.log.value = win.document.frmLog.log.value + (new Date()) + ": " + s + "\r\n";

	return true;
}

var g_ignoreErrors = (getQueryStringValue("debug").length < 1);
function setIgnoreErrors(b) { g_ignoreErrors = true; }
function getIgnoreErrors(b) { return g_ignoreErrors; }
function window_mpErrHandler(msg, filename, line)
{
	if (getIgnoreErrors()) {
		window.status = '!';
		return true;
	}

	mpLog(msg + "," + filename + "," + line);
	return true;
}

if(getQueryStringValue("debug")!="2")
	window.onerror = window_mpErrHandler;


var g_useInjectedTimes = false;
function getUseInjectedTimes()  { return g_useInjectedTimes; }
function setUseInjectedTimes(b) { g_useInjectedTimes = b; }

function mpDebug(s) { if (!getIgnoreErrors()) mpLog(s); }


var g_passthroughParameters = new Array( "ivt", "req", "Aicc_sid", "Aicc_url" );
function addPassthroughParameter(s)
{
	// If parameter is already in list, exit now
	for (var i=0; i<g_passthroughParameters.length; i++)
		if (g_passthroughParameters == s)
			return;

	// Parameter wasn't found, so add it to list now
	g_passthroughParameters[g_passthroughParameters.length] = s;
}

function appendPassthroughParameters(url)
{
	for (var i=0; i<g_passthroughParameters.length; i++) {
		var v = (getQueryStringValue(g_passthroughParameters[i]));
		if (v.length < 1) continue;
		url += ((url.indexOf("?") >= 0 ? "&":"?") + escape(g_passthroughParameters[i]) + "=" + escape(v));
	}

	return url;
}

/** Resynchronize presentation based on this point in time. This is done by calling DoSync code with array of events. */
function doTimeWarp(elemID, currentTime)
{
	var e = Element(elemID);
	if (!e._tA) return;

	var events = new Array();
	for (var i=0; i < e._initEvents.length; i++) {
		var s = e._initEvents[i];
		s = s.replaceAll("\"", "\\\"");
//		s = s.replaceAll("\\'", "BCLBCLBCL");
		s = s.replaceAll("'", "\"");
//		s = s.replaceAll("BCLBCLBCL", "'");
		events[i] = new LiveEventCmd("*", "*", "m", "1", i, s, i);
	}

	var offset = e._initEvents.length;
	for (var i=0; i < e._tA.length; i++) {
		var tn = e._tA[i];
		if (tn>currentTime)
			break;
		e._cIndex = i;

		// Turn single quotes to double quotes.... FireCommand requires double quotes
		var s = e._pA[i];
		s = s.replaceAll("\"", "\\\"");
//		s = s.replaceAll("\\'", "BCLBCLBCL");
		s = s.replaceAll("'", "\"");
//		s = s.replaceAll("BCLBCLBCL", "'");
		events[i + offset] = new LiveEventCmd("*", "*", "m", "1", i, s, i);
	}
	g_indexEventList = 0;
	DoSync(events);
}

function PresentationComplete()
{
	var server = GetParamFromQueryString("msgsvr", document.location.search);
	var port = GetParamFromQueryString("msgport", document.location.search);
	var guid = GetParamFromQueryString("msgguid", document.location.search);
	var viewid = GetParamFromQueryString("msgviewid", document.location.search);
	if(server!="" && guid!="")
	{
		var img = new Image();
		img.src = server+":" + port + "/setevent.htm?guid=" + guid + "&msg=next:"+viewid;
	}

}

function LoadScript(url)
{
	var usc_elem = document.createElement('script');
	document.documentElement.appendChild(usc_elem);
	usc_elem.src = url;
 	
// 	var dtNow = new Date().getTime();
// 	var preventCacheString = "?" + dtNow;
// 	var usc_elem = document.createElement('script'); 
//	usc_elem.setAttribute('type','text/javascript'); 
//	usc_elem.setAttribute('src',url); 
//	document.documentElement.appendChild(usc_elem); 
}

var callscript = new Array();;
function CallScript(url,uniqueName,forceNew)
{
	if(uniqueName==null)
		uniqueName = "callscript";
	if(callscript[uniqueName]==null)
		callscript[uniqueName] = 0;

	var w = window.frames[uniqueName+'_'+callscript[uniqueName]];
	if(w==null)
	{
		var iframe_elem = document.createElement('iframe');
		iframe_elem.name = uniqueName+'_'+callscript[uniqueName];
		iframe_elem.id = uniqueName+'_'+callscript[uniqueName];
		iframe_elem.width=0;
		iframe_elem.height=0;
		iframe_elem.style.border=0;
		iframe_elem.style.position="absolute";
		document.documentElement.appendChild(iframe_elem);
		w = window.frames[uniqueName+'_'+callscript[uniqueName]];
	}

	if(forceNew)
	{
		callscript[uniqueName]++;
	}

	var index = url.indexOf("?");
	var upStr = "&up";
	if(index==-1)
		upStr = "?up";

	w.document.open();
	w.document.write("<SCR"+"IPT src='"+url+upStr+"'></SCR"+"IPT>");
	w.document.close();

}

function CallLogEvent(componentName, componentType, eventName, eventTime, eventDuration, trackrealtime)
{
	if (parent && parent!=window && parent.frames[0]) 
		parent.frames[0].LogEvent(componentName,componentType,eventName,eventTime,eventDuration,trackrealtime);	
	else
		LogEvent(componentName,componentType,eventName,eventTime,eventDuration,trackrealtime);	
}

function base10log(u) 
{ 
  return Math.log(u) / Math.LN10; 
} 
