/**
 * SWFObject v1.5: Flash Player detection and embed - http://blog.deconcept.com/swfobject/
 *
 * SWFObject is (c) 2007 Geoff Stearns and is released under the MIT License:
 * http://www.opensource.org/licenses/mit-license.php
 *
 */
if(typeof deconcept == "undefined") var deconcept = new Object();
if(typeof deconcept.util == "undefined") deconcept.util = new Object();
if(typeof deconcept.SWFObjectUtil == "undefined") deconcept.SWFObjectUtil = new Object();
deconcept.SWFObject = function(swf, id, w, h, ver, c, quality, xiRedirectUrl, redirectUrl, detectKey) {
	if (!document.getElementById) { return; }
	this.DETECT_KEY = detectKey ? detectKey : 'detectflash';
	this.skipDetect = deconcept.util.getRequestParameter(this.DETECT_KEY);
	this.params = new Object();
	this.variables = new Object();
	this.attributes = new Array();
	if(swf) { this.setAttribute('swf', swf); }
	if(id) { this.setAttribute('id', id); }
	if(w) { this.setAttribute('width', w); }
	if(h) { this.setAttribute('height', h); }
	if(ver) { this.setAttribute('version', new deconcept.PlayerVersion(ver.toString().split("."))); }
	this.installedVer = deconcept.SWFObjectUtil.getPlayerVersion();
	if (!window.opera && document.all && this.installedVer.major > 7) {
		// only add the onunload cleanup if the Flash Player version supports External Interface and we are in IE
		// fixes bug in some fp9 versions see http://blog.deconcept.com/2006/07/28/swfobject-143-released/
		if (!deconcept.unloadSet) {
			deconcept.SWFObjectUtil.prepUnload = function() {
				__flash_unloadHandler = function(){};
				__flash_savedUnloadHandler = function(){};
				if(!deconcept.prepUnloadSet) {
					deconcept.prepUnloadSet = true;
					window.attachEvent("onunload", deconcept.SWFObjectUtil.cleanupSWFs);
				}
			}
			window.attachEvent("onbeforeunload", deconcept.SWFObjectUtil.prepUnload);
			deconcept.unloadSet = true;
		}
	}
	if(c) { this.addParam('bgcolor', c); }
	var q = quality ? quality : 'high';
	this.addParam('quality', q);
	this.setAttribute('useExpressInstall', false);
	this.setAttribute('doExpressInstall', false);
	var xir = (xiRedirectUrl) ? xiRedirectUrl : window.location;
	this.setAttribute('xiRedirectUrl', xir);
	this.setAttribute('redirectUrl', '');
	if(redirectUrl) { this.setAttribute('redirectUrl', redirectUrl); }
}
deconcept.SWFObject.prototype = {
	useExpressInstall: function(path) {
		this.xiSWFPath = !path ? "expressinstall.swf" : path;
		this.setAttribute('useExpressInstall', true);
	},
	setAttribute: function(name, value){
		this.attributes[name] = value;
	},
	getAttribute: function(name){
		return this.attributes[name] || "";
	},
	addParam: function(name, value){
		this.params[name] = value;
	},
	getParams: function(){
		return this.params;
	},
	addVariable: function(name, value){
		this.variables[name] = value;
	},
	getVariable: function(name){
		return this.variables[name] || "";
	},
	getVariables: function(){
		return this.variables;
	},
	getVariablePairs: function(){
		var variablePairs = new Array();
		var key;
		var variables = this.getVariables();
		for(key in variables){
			variablePairs[variablePairs.length] = encodeURIComponent(key) +"="+ encodeURIComponent(variables[key]);
		}
		return variablePairs;
	},
	getSWFHTML: function() {
		var swfNode = "";
		if (navigator.plugins && navigator.mimeTypes && navigator.mimeTypes.length) { // netscape plugin architecture
			if (this.getAttribute("doExpressInstall")) {
				this.addVariable("MMplayerType", "PlugIn");
				this.setAttribute('swf', this.xiSWFPath);
			}
			swfNode = '<embed type="application/x-shockwave-flash" src="'+ this.getAttribute('swf') +'" width="'+ this.getAttribute('width') +'" height="'+ this.getAttribute('height') +'" style="'+ (this.getAttribute('style') || "") +'"';
			swfNode += ' id="'+ this.getAttribute('id') +'" name="'+ this.getAttribute('id') +'" ';
			var params = this.getParams();
			 for(var key in params){ swfNode += [key] +'="'+ params[key] +'" '; }
			var pairs = this.getVariablePairs().join("&");
			 if (pairs.length > 0){ swfNode += 'flashvars="'+ pairs +'"'; }
			swfNode += '/>';
		} else { // PC IE
			if (this.getAttribute("doExpressInstall")) {
				this.addVariable("MMplayerType", "ActiveX");
				this.setAttribute('swf', this.xiSWFPath);
			}
			swfNode = '<object id="'+ this.getAttribute('id') +'" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="'+ this.getAttribute('width') +'" height="'+ this.getAttribute('height') +'" style="'+ (this.getAttribute('style') || "") +'">';
			swfNode += '<param name="movie" value="'+ this.getAttribute('swf') +'" />';
			var params = this.getParams();
			for(var key in params) {
			 swfNode += '<param name="'+ key +'" value="'+ params[key] +'" />';
			}
			var pairs = this.getVariablePairs().join("&");
			if(pairs.length > 0) {swfNode += '<param name="flashvars" value="'+ pairs +'" />';}
			swfNode += "</object>";
		}
		return swfNode;
	},
	write: function(elementId){
		if(this.getAttribute('useExpressInstall')) {
			// check to see if we need to do an express install
			var expressInstallReqVer = new deconcept.PlayerVersion([6,0,65]);
			if (this.installedVer.versionIsValid(expressInstallReqVer) && !this.installedVer.versionIsValid(this.getAttribute('version'))) {
				this.setAttribute('doExpressInstall', true);
				this.addVariable("MMredirectURL", escape(this.getAttribute('xiRedirectUrl')));
				document.title = document.title.slice(0, 47) + " - Flash Player Installation";
				this.addVariable("MMdoctitle", document.title);
			}
		}
		if(this.skipDetect || this.getAttribute('doExpressInstall') || this.installedVer.versionIsValid(this.getAttribute('version'))){
			var n = (typeof elementId == 'string') ? document.getElementById(elementId) : elementId;
			n.innerHTML = this.getSWFHTML();
			return true;
		}else{
			if(this.getAttribute('redirectUrl') != "") {
				document.location.replace(this.getAttribute('redirectUrl'));
			}
		}
		return false;
	}
}

/* ---- detection functions ---- */
deconcept.SWFObjectUtil.getPlayerVersion = function(){
	var PlayerVersion = new deconcept.PlayerVersion([0,0,0]);
	if(navigator.plugins && navigator.mimeTypes.length){
		var x = navigator.plugins["Shockwave Flash"];
		if(x && x.description) {
			PlayerVersion = new deconcept.PlayerVersion(x.description.replace(/([a-zA-Z]|\s)+/, "").replace(/(\s+r|\s+b[0-9]+)/, ".").split("."));
		}
	}else if (navigator.userAgent && navigator.userAgent.indexOf("Windows CE") >= 0){ // if Windows CE
		var axo = 1;
		var counter = 3;
		while(axo) {
			try {
				counter++;
				axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash."+ counter);
//				document.write("player v: "+ counter);
				PlayerVersion = new deconcept.PlayerVersion([counter,0,0]);
			} catch (e) {
				axo = null;
			}
		}
	} else { // Win IE (non mobile)
		// do minor version lookup in IE, but avoid fp6 crashing issues
		// see http://blog.deconcept.com/2006/01/11/getvariable-setvariable-crash-internet-explorer-flash-6/
		try{
			var axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7");
		}catch(e){
			try {
				var axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6");
				PlayerVersion = new deconcept.PlayerVersion([6,0,21]);
				axo.AllowScriptAccess = "always"; // error if player version < 6.0.47 (thanks to Michael Williams @ Adobe for this code)
			} catch(e) {
				if (PlayerVersion.major == 6) {
					return PlayerVersion;
				}
			}
			try {
				axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash");
			} catch(e) {}
		}
		if (axo != null) {
			PlayerVersion = new deconcept.PlayerVersion(axo.GetVariable("$version").split(" ")[1].split(","));
		}
	}
	return PlayerVersion;
}
deconcept.PlayerVersion = function(arrVersion){
	this.major = arrVersion[0] != null ? parseInt(arrVersion[0]) : 0;
	this.minor = arrVersion[1] != null ? parseInt(arrVersion[1]) : 0;
	this.rev = arrVersion[2] != null ? parseInt(arrVersion[2]) : 0;
}
deconcept.PlayerVersion.prototype.versionIsValid = function(fv){
	if(this.major < fv.major) return false;
	if(this.major > fv.major) return true;
	if(this.minor < fv.minor) return false;
	if(this.minor > fv.minor) return true;
	if(this.rev < fv.rev) return false;
	return true;
}
/* ---- get value of query string param ---- */
deconcept.util = {
	getRequestParameter: function(param) {
		var q = document.location.search || document.location.hash;
		if (param == null) { return q; }
		if(q) {
			var pairs = q.substring(1).split("&");
			for (var i=0; i < pairs.length; i++) {
				if (pairs[i].substring(0, pairs[i].indexOf("=")) == param) {
					return pairs[i].substring((pairs[i].indexOf("=")+1));
				}
			}
		}
		return "";
	}
}
/* fix for video streaming bug */
deconcept.SWFObjectUtil.cleanupSWFs = function() {
	var objects = document.getElementsByTagName("OBJECT");
	for (var i = objects.length - 1; i >= 0; i--) {
		objects[i].style.display = 'none';
		for (var x in objects[i]) {
			if (typeof objects[i][x] == 'function') {
				objects[i][x] = function(){};
			}
		}
		objects[i].removeNode(true);
	}
}
/* add document.getElementById if needed (mobile IE < 5) */
if (!document.getElementById && document.all) { document.getElementById = function(id) { return document.all[id]; }}

/* add some aliases for ease of use/backwards compatibility */
var getQueryParamValue = deconcept.util.getRequestParameter;
var FlashObject = deconcept.SWFObject; // for legacy support
var SWFObject = deconcept.SWFObject;

//****************************************************************************
// Copyright (C) thePlatform for Media, Inc. All Rights Reserved.
//****************************************************************************

////// UTIL FUNCTIONS ////////////

// dynamically resize an element, for example, the category list
function tpResize(divID, height, width)
{
	var element = document.getElementById(divID);
	element.style.height = height + "px";
	element.style.width = width + "px";
}

// helper function for getting the "top" coordinate of an object
function tpGetTop(obj)
{
	result = 0;
	while (obj)
	{
		result += obj.offsetTop;
		obj = obj.offsetParent;
	}
	return result;
}

// helper function for getting the "left" coordinate of an object
function tpGetLeft(obj)
{
	result = 0;
	while(obj)
	{
		result += obj.offsetLeft;
		obj = obj.offsetParent;
	}
	return result;
}
tpThisMovie = function(movieName)
{
	var oDoc
	if (window.frame)
	{
		oDoc = frame.contentWindow.document || frame.contentDocument.document ;
	}
	else
	{
		oDoc = document
	}
	return oDoc.getElementById(movieName);
}
function tpDebug(str)
{
	if (document.getElementById("debugDiv"))
	{
		document.getElementById("debugDiv").innerHTML += str + "<br>";
	}
}

// open a new pop-up window
function tpOpenNewWindow(URLtoOpen, windowName, windowFeatures)
{
	var newWindow=window.open(URLtoOpen, windowName, windowFeatures); 
}

// handle tracking URLs
var tpTrackingImage = new Image();
function tpCallTrackingUrl(url)
{
	url = unescape(url);
	tpTrackingImage.src = url;
	for (i = 0; ((!tpTrackingImage.complete) && (i < 100000)); i++)
	{
	}
}

///// INIT tpController //////////
function tpGetUseJS() { return "true" }
function tpGetInstanceID() { return tpInstanceID; }
function tpGetCommManagerID() { return tpCommID; }
tpLogLevel = "warn";
function tpSetLogLevel(level){ tpLogLevel = level };
function tpGetLogLevel() { return tpLogLevel }
function tpGetProperties()
{
	//each pdk controller will call this to get the default properties
	var props = new Object();
	props.commManagerId = tpGetCommManagerID();
	props.instanceId = tpGetInstanceID();
	props.useJS = tpGetUseJS();
	props.registeredComponents = tpGetRegisteredIDs();
	props.logLevel = tpGetLogLevel();
	return props;
}

var registeredIDs = new Array();
function tpRegisterID(swfName)
{
	for (var i = 0; i < registeredIDs.length; i++)
	{
		if (registeredIDs[i] == swfName) return;
	}
	registeredIDs.push(swfName);
}
function tpGetRegisteredIDs()
{
	return registeredIDs;
}

// handle references to the communication manager
var tpController;
var tpCommID;
var tpBridgeID;
var tpExternalController;

//the kicks off the creation of the tpController, must be called before any pdk components are set on the page
function tpSetCommManagerID(commID, embed, commManagerUrl)
{
	// create a unique token for each set of player controls
	tpInstanceID = (new Date()).getTime() + "|" + Math.round(Math.random() * 100000000000000000);
	if (commID && embed)
	{
		//get rid of any existing commManager
		var divEl = window.document.getElementById("commManagerDiv");
		if (divEl)
		{
			divEl.parentNode.removeChild(divEl);
			divEl = null;
		}
		//create a commManager as the first element in the body
		divEl = window.document.createElement('div');
		divEl.id = "commManagerDiv";
		divEl.style.position = "absolute";
		var bodyTag = window.document.getElementsByTagName('body')[0];
		bodyTag.insertBefore(divEl, bodyTag.firstChild);
		var url = commManagerUrl ? commManagerUrl : "swf/commManager.swf"
		var so = new SWFObject(url, commID, "1", "1", "9.0.0.0");
		so.addParam("allowScriptAccess", "always");
		so.addParam("wmode", "transparent");
		so.write("commManagerDiv");
	}
	tpController = new tpControllerClass();
	tpCommID = commID;
	tpBridgeID = commID ? commID : "unknown";
	//external controller
	//tpCleanupExternal();
}

///// TPCONTROLLER CLASS /////////////

// implementation of the controller proxy in javascript
function tpControllerClass()
{
	//vars loaded at bottom
	/////// Send Messages to the rest of the app //////////////
	///////////////////////////////////////////////////////////
	
	//all communication to the communication manager happens here
	this.sendMessage = function(destination, message, skipBus)
	{
		//tpDebug("putting message on queue: " + message.name + " skipBus?" + skipBus + " canMessage?" + this.canMessage + " isLoading?" + this.isLoading);
		var sendObj = new Object();
		sendObj.message = message;
		sendObj.destination = destination;
		if (this.isLoading && !skipBus)
		{
			//these are low priority messages that should be sent only after OnPlayerLoaded is fired
			this.messageQueue.push(sendObj);
		}
		else if (!this.canMessage)
		{
			//these are high priority messages (like addEventListener or registerFunction) that usually need to be sent before OnPlayerLoaded is fired
			//but we still have to wait until after the communication manager has loaded or they'll just disappear
			this.priorityQueue.push(sendObj);
		}
		else
		{
			this.doSendMessage(sendObj);
		}
	}
	
	this.doSendMessage = function(sendObj)//private function
	{
		if (this.isShutDown) return;
		var obj = tpThisMovie(sendObj.destination);
		
		//tpDebug("sending: " + sendObj.message.name + " dest:" + sendObj.destination);
		// Flash ExternalInterface will convert any "" or " " string to null.  However,
		// in the PDK, null and "" mean different things.  So, if there are blank strings,
		// convert to a signal value, and then unconvert on the way out.
		/*for (var i=0; i<sendObj.parameters.length; i++)
		{
			var param = sendObj.parameters[i];
			if (typeof param == "string" && (param.length == 0 || param == " "))
			{
				sendObj.parameters[i] = this.blankString;
			}
		}*/
		//tpDebug("do send message: " + sendObj.message.name);
		obj.executeMessage(sendObj.message);	
	}
	
	this.checkMessageQueue = function()//private function
	{
		var len = this.messageQueue.length
		while (this.messageQueue.length > 0)
		{
			this.doSendMessage(this.messageQueue.shift());
		}
	}
	
	this.checkPriorityQueue = function()
	{
		while (this.priorityQueue.length > 0)
		{
			var sendObj = this.priorityQueue.shift();
			if (sendObj.destination == "unknown") sendObj.destination = tpBridgeID;
			this.doSendMessage(sendObj);
		}
	}
		
	this.wrapMessage = function(messageName, payload)
	{
		var comm = {globalDataType:this.getDataTypeName("CommInfo"), id:"javascript"}
		var message = {globalDataType:this.getDataTypeName("MessageInfo"), name:messageName, payload:payload, comm:comm};
		return message;
	}
	this.getDataTypeName = function(shortType)
	{
		switch(shortType)
		{
			case "ScopeInfo":return "com.theplatform.pdk.communication::ScopeInfo";
			case "MessageInfo":return "com.theplatform.pdk.communication::MessageInfo";
			case "DispatchInfo":return "com.theplatform.pdk.communication::DispatchInfo";
			case "HandlerInfo":return "com.theplatform.pdk.communication::HandlerInfo";
			case "CommInfo":return "com.theplatform.pdk.communication::CommInfo";
			case "CallInfo":return "com.theplatform.pdk.communication::CallInfo";
			case "FunctionInfo":return "com.theplatform.pdk.communication::FunctionInfo";
			case "PdkEvent":return "com.theplatform.pdk.events::PdkEvent";
			case "Clip":return "com.theplatform.pdk.data::Clip";
			case "BaseClip":return "com.theplatform.pdk.data::BaseClip";
			case "Banner":return "com.theplatform.pdk.data::Banner";
			case "Overlay":return "com.theplatform.pdk.data::Overlay";
			case "HyperLink":return "com.theplatform.pdk.data::HyperLink";
			case "TrackingUrl":return "com.theplatform.pdk.data::TrackingUrl";
			case "CustomData":return "com.theplatform.pdk.data::CustomData";
			case "Subtitles":return "com.theplatform.pdk.data::Subtitles";
			case "AdPattern":return "com.theplatform.pdk.data::AdPattern";
			case "Range":return "com.theplatform.pdk.data::Range";
			case "Sort":return "com.theplatform.pdk.data::Sort";
		}
	}
	this.createScope = function(scope)
	{
		if (scope == undefined) return this.defaultScope;
		else
		{
			scope.push("javascript");
			tpDebug("creating scopes: " + scope.toString());
			return {globalDataType:this.getDataTypeName("ScopeInfo"),controlId:"javascript",isGlobal:"true",isAny:"false",isEmpty:"false",scopeIds:scope};
		}
	}
	
	//////// handle communication to the rest of the app ///////
	////////////////////////////////////////////////////////////
	
	//register a function
	this.registerFunction = function(funcName, callback, scopes)
	{
		var scopeObj = this.createScope(scopes);
		var informComm = false;
		if (this.functions[funcName] == undefined)
		{
			this.functions[funcName] = new Object();
			informComm = true;
		}
		for (var i = 0; i < scopeObj.scopeIds.length; i++)
		{
			var s = scopeObj.scopeIds[i];
			if (s == "*") return;//can't register a scope of any
			this.functions[funcName][s] = callback;
		}
		if (informComm)
		{
			//send the registered function to the commManager
			var func = {globalDataType:this.getDataTypeName("FunctionInfo"),name:funcName,scope:scopeObj};
			var message = this.wrapMessage("registerFunction", func);
			this.sendMessage(tpBridgeID,message,true);
		}
	}
	
	this.unregisterFunction = function(funcName, scope)
	{
		var scopeObj = this.createScope(scopes);
		if (this.functions[funcName] != undefined)
		{
			var funcs = this.functions[funcName];
			for (var i = 0; i < scopeObj.scopeIds.length; i++)
			{
				var s = scopeObj.scopeIds[i];
				if (s == "*")
				{
					delete funcs;//delete them all
					break;
				}
				if (funcs[s] != undefined) delete funcs[s];//delete each scope
			}
			var funcsLeft = false;
			if (funcs != undefined)//prune the object
			{
				for (var sc in funcs)
				{
					funcsLeft = true;
					break;
				}
				if (!funcsLeft) delete this.functions[funcName];
			}
		}
		if (!funcsLeft)
		{
			var func = {globalDataType:this.getDataTypeName("FunctionInfo"),name:funcName,scope:scopeObj};
			var message = this.wrapMessage("unregisterFunction", func);
			this.sendMessage(tpBridgeID,message,true);
		}
	}
	
	this.addEventListener = function(eventName, callback, scope)
	{
		tpDebug("adding event listener: " + eventName + " callback:" + callback);
		var scopeObj = this.createScope(scope);
		var handler = {globalDataType:this.getDataTypeName("HandlerInfo"),name:eventName,handler:callback,scope:scopeObj}
		var informComm = false;
		if (this.events[eventName] == undefined)
		{
			this.events[eventName] = new Array();
			informComm = true;
		}
		var evts = this.events[eventName];
		var repeat = false;
		for (var i = 0; i < evts.length; i++)//repeats?
		{
			if (evts[i].handler == callback)
			{
				evts[i] = handler;//replace the scopes
				repeat = true;
				break;
			}
		}
		if (!repeat) evts.push(handler);
		tpDebug("how many listeners? " + evts.length);
		if (informComm)
		{
			tpDebug("informing comm of event listener");
			var message = this.wrapMessage("addEventListener", handler);
			this.sendMessage(tpBridgeID,message,true);
		}
	}
	this.removeEventListener = function(eventName, callback, scope)
	{
		if (this.events[eventName] != undefined)
		{
			var scopeObj = this.createScope(scope);
			var handler = {globalDataType:this.getDataTypeName("HandlerInfo"),name:eventName,handler:callback,scope:scopeObj}
		
			var eventArray = this.events[eventName];
			for (var i = 0; i < eventArray.length; i++)
			{
				var h = eventArray[i];
				if (h.handler == handler.handler)
				{
					eventArray = eventArray.splice(i, 1);
					break;
				}
			}
			if (eventArray.length == 0)
			{
				//no callbacks left, zap the variable
				delete this.events[eventName];
				var message = this.wrapMessage("removeEventListener", handler);
				this.sendMessage(tpBridgeID, message, true)
			}
		}
	}
	
	this.dispatchEvent = function(eventName, value, scope)
	{
		var scopeObj = this.createScope(scope);
		var evt = {globalDataType:this.getDataTypeName("PdkEvent"),type:eventName, data:value};
		var dispatch = {globalDataType:this.getDataTypeName("DispatchInfo"),evt:evt,scope:scopeObj};
		//check local events
		this.doDispatchEvent(dispatch);
		
		var message = this.wrapMessage("dispatchEvent", dispatch);
		this.sendMessage(tpBridgeID, message, true);
	}
		
	this.callFunction = function(funcName, args, scope)
	{
		var scopeObj = this.createScope(scope);
		var call = {globalDataType:this.getDataTypeName("CallInfo"),name:funcName,args:args,scope:scopeObj};
		this.doCallFunction(call);
		
		var message = this.wrapMessage("callFunction", call);
		this.sendMessage(tpBridgeID, message, true);
	}
	
	this.doDispatchEvent = function(dispatch)
	{
		tpDebug("do dispatching event: " + dispatch.evt.type);
		if (this.events[dispatch.evt.type] != undefined)
		{
			var handlers = this.events[dispatch.evt.type]
			for (var i = 0; i < handlers.length; i++)
			{
				var handler = handlers[i];
				tpDebug("checking handler? " + handler.handler)
				if (dispatch.scope.isAny)
				{
					eval(handler.handler)(dispatch.evt);
					continue;
				}
				for (var j = 0; j < handler.scope.scopeIds.length; j++)
				{
					var s = handler.scope.scopeIds[j];
					var fired = false;
					if (s == "*")
					{
						eval(handler.handler)(dispatch.evt);
						break;
					}
					for (var k = 0; k < dispatch.scope.scopeIds.length; k++)
					{
						tpDebug("running through scopes handler: " + s + " dispatch: " + dispatch.scope.scopeIds[k]);
						if (s == dispatch.scope.scopeIds[k])
						{
							fired = true;
							tpDebug("firing");
							eval(handler.handler)(dispatch.evt);
							break;
						}
					}
					if (fired) break;//go to next handler
				}
			}
		}
	}
	
	this.doCallFunction = function(call)
	{
		if (this.functions[call.name] != undefined)
		{
			//check local functions
			var funcsToCall = new Object();
			for (var i = 0; i < call.scope.scopeIds.length; i++)
			{
				var s = call.scope.scopeIds[i];
				if (this.functions[call.name][s] != undefined)
				{
					funcsToCall[this.functions[call.name][s]] = "f";//we need lookup
				}
			}
			for (var f in funcsToCall)
			{
				eval(f)(call.args);
			}
		}
	}
	
	
	
	
	//////// RECEIVE CALLS FROM AS //////////////
	////////////////////////////////////////////
	
	//all communication from the communication manager happens here
	this.receiveMessage = function(destination, message)
	{
		if (destination == "javascript")
		{
			//tpDebug("receiving message: " + message.name)
			var messStr = message.name;
			switch(messStr)
			{
				
				case "commReady":
					tpBridgeID = tpCommID;
					this.canMessage = true;
					this.checkPriorityQueue();
					break;
				case "bridgeReady":
					tpBridgeID = message.comm.id;
					this.canMessage = true;
					this.checkPriorityQueue();
					break;
				case "dispatchEvent":
					var dispatch = message.payload;
					this.receiveEvent(dispatch);
					break;
				case "callFunction":
					var call = message.payload;
					this.doCallFunction(call);
					break;
				default:
					break;
			}
		}
		else
		{
			//transfer the message to its final destination
			this.sendMessage(destination, message, true);
		}
	}
	this.receiveEvent = function(dispatch)
	{
		//tpDebug("RECIEVED:" + dispatch.evt.type)

		if (dispatch.evt.type == "OnPlayerLoaded")
		{
			this.isLoading = false;
			this.checkMessageQueue();
		}
		this.doDispatchEvent(dispatch);
	}
	
	//create a list of direct calls
	
	// PLAYER
	
	this.setRelease = function(release, replaceDefault, scope)
	{
		var args = [release, replaceDefault];
		this.callFunction("setRelease", args, scope);
	}
	this.loadRelease = function(release, replaceDefault, scope)
	{
		var args = [release, replaceDefault];
		this.callFunction("loadRelease", args, scope);
	}
	this.loadReleaseURL = function(releaseURL, replaceDefault, scope)
	{
		var args = [releaseURL, replaceDefault];
		this.callFunction("loadReleaseURL", args, scope);
	}
	this.setReleaseURL = function(url, replaceDefault, scope)
	{
		var args = [url, replaceDefault];
		this.callFunction("setReleaseURL", args, scope);
	}
	this.loadSmil = function(smil, replaceDefault, scope)
	{
		if (replaceDefault == undefined) replaceDefault = true;
		this.callFunction("loadSmil", [smil, replaceDefault], scope);
	}
	this.setSmil = function(smil, scope)
	{
		this.callFunction("setSmil", [smil], scope);
	}
	this.resetPlayer = function(scope)
	{
		this.callFunction("resetPlayer", [], scope);
	}
	this.setPlayerMessage = function(message, showDuration, scope)
	{
		if (showDuration == undefined) showDuration = 5000;
		this.callFunction("setPlayerMessage", [message, showDuration], scope);
	}
	this.clearPlayerMessage = function(scope)
	{
		this.callFunction("clearPlayerMessage", [], scope);
	}
	this.setCurrentReleaseList = function(id, scope)
	{
		var args = [id];
		this.callFunction("setCurrentReleaseList", args, scope);
	}
	this.seekToPosition = function(position, scope)
	{
		var args = [position];
		this.callFunction("seekToPosition", args, scope);
	}
	this.seekToPercentage = function(percent, scope)
	{
		var args = [percent];
		this.callFunction("seekToPercentage", args, scope);
	}
	this.nextClip = function(scope)
	{
		var args = [];
		this.callFunction("nextClip", args, scope);
	}
	this.previousClip = function(scope)
	{
		var args = [];
		this.callFunction("previousClip", args, scope);
	}
	this.mute = function(muted, scope)
	{
		var args = [muted];
		this.callFunction("mute", args, scope);
	}
	this.pause = function(paused, scope)
	{
		var args = [paused];
		this.callFunction("pause", args, scope);
	}
	this.setPreviewImageUrl = function(url, scope)
	{
		var args = [url];
		this.callFunction("setPreviewImageUrl", args, scope);
	}
	this.showFullScreen = function(isFullScreen, scope)
	{
		var args = [isFullScreen];
		this.callFunction("showFullScreen", args, scope);
	}
	this.showEmailForm = function(visible, scope)
	{
		var args = [visible];
		this.callFunction("showEmailForm", args, scope);
	}
	this.showLinkForm = function(visible, scope)
	{
		var args = [visible];
		this.callFunction("showLinkForm", args, scope);
	}
	this.trace = function(str, className, level)
	{
		var args = [str, className, level];
		this.callFunction("trace", args, null); 
	}
	this.useDefaultPlayOverlay = function(useDefault, scope)
	{
		var args = [useDefault];
		this.callFunction("useDefaultPlayOverlay", args, scope);
	}
	this.getUseDefaultPlayOverlay = function(scope)
	{
		var args = [];
		this.callFunction("getUseDefaultPlayOverlay", args, scope);
	}
	this.useDefaultLinkForm = function(useDefault, scope)
	{
		var args = [useDefault];
		this.callFunction("useDefaultLinkForm", args, scope);
	}
	this.useDefaultEmailForm = function(useDefault, scope)
	{
		var args = [useDefault];
		this.callFunction("useDefaultEmailForm", args, scope);
	}
	this.getSubtitleLanguage = function(requestor, scope)
	{
		var args = [requestor];
		this.callFunction("getSubtitleLanguage", args, scope);
	}
	this.clickPlayButton = function(scope)
	{
		var args = [];
		this.callFunction("clickPlayButton", args, scope);
	}
	this.disablePlayerControls = function(disable, exceptions, scope)
	{
		var args = [disable, exceptions];
		this.callFunction("disablePlayerControls", args, scope);
	}
	this.setSubtitleLanguage = function(language, scope)
	{
		var args = [language];
		this.callFunction("setSubtitleLanguage", args, scope);
	}	
	this.getPlayerVariables = function(names, scope)
	{
		var args = [names];
		this.callFunction("getPlayerVariables", args, scope);	
	}
	this.setVolume = function(volume, scope)
	{
		var args = [volume];
		this.callFunction("setVolume", args, scope);
	}
	
	// RELEASE MODEL
	
	this.refreshReleaseModel = function(category, search, sort, range, params, secondaryParams, scope)
	{
		if (sort) sort.globalDataType = this.getDataTypeName("Sort");
		if (range) range.globalDataType = this.getDataTypeName("Range");
		var args = [category, search, sort, range, params, secondaryParams];
		this.callFunction("refreshReleaseModel", args, scope);
	}
	
	// CATEGORY MODEL
	
	this.refreshCategoryModel = function(params, scope)
	{
		var args = [params];
		this.callFunction("refreshCategoryModel", args, scope);
	}
	
	// NAVIGATION
	
	this.nextRange = function(scope)
	{
		var args = [];
		this.callFunction("nextRange", args, scope);
	}
	this.previousRange = function(scope)
	{
		var args = [];
		this.callFunction("previousRange", args, scope);
	}
	
	
	// CLIP INFO
	
	this.setClipInfo = function(clip, isDefault, scope)
	{
		clip = this.modClip(clip);
		var args = [clip, isDefault];
		this.callFunction("setClipInfo", args, scope);
	}
	
	// CATEGORY LIST

	this.clearCategorySelection = function(scope) 
	{		
		var args = [];
		this.callFunction("clearCategorySelection", args, scope);
	}

	// RELEASE LIST
	
	this.suspendPlayAll = function(suspend, scope) 
	{		
		var args = [suspend];
		this.callFunction("suspendPlayAll", args, scope);
	}
	this.playNext = function(wrapAround, naturalEnd, scope) 
	{		
		var args = [wrapAround, naturalEnd];
		this.callFunction("playNext", args, scope);
	}
	this.playPrevious = function(wrapAround, scope) 
	{		
		var args = [wrapAround];
		this.callFunction("playPrevious", args, scope);
	}
	
	// GENERAL
	this.modClip = function(clip)
	{
		if (clip)
		{
			//set the class names correctly for casting in as3.
			clip.globalDataType = this.getDataTypeName("Clip");
			var baseClip = clip.baseClip;
			if (!baseClip) baseClip = new Object();
			if (clip.banners) baseClip.banners = clip.banners;
			if (clip.overlays) baseClip.overlays = clip.overlays;
			clip.baseClip = this.modBaseClip(baseClip);
			if (clip.chapter) clip.chapter.globalDataType = this.getDataTypeName("Chapter");
		}
		return clip;
	}
	this.modBaseClip = function(baseClip)
	{
		if (!baseClip) baseClip = new Object();
		baseClip.globalDataType = this.getDataTypeName("BaseClip");
		if (baseClip.moreInfo)
		{
			baseClip.moreInfo.globalDataType = this.getDataTypeName("HyperLink");
			if (baseClip.moreInfo.clickTrackingUrls) baseClip.moreInfo.clickTrackingUrls = this.modTracking(baseClip.moreInfo.clickTrackingUrls);
		}
		if (baseClip.banners)
		{
			for (var i = 0; i < baseClip.banners.length; i++)
			{
				baseClip.banners[i].globalDataType = this.getDataTypeName("Banner");
				if (baseClip.banners[i].clickTrackingUrls) baseClip.banners[i].clickTrackingUrls = this.modTracking(baseClip.banners[i].clickTrackingUrls)
			}
		}
		if (baseClip.overlays)
		{
			for (var i = 0; i < baseClip.overlays.length; i++)
			{
				baseClip.overlays[i].globalDataType = this.getDataTypeName("Overlay");
				if (baseClip.overlays[i].clickTrackingUrls) baseClip.overlays[i].clickTrackingUrls = this.modTracking(baseClip.overlays[i].clickTrackingUrls)
			}
		}
		if (baseClip.availableSubtitles)
		{
			for (var i = 0; i < baseClip.availableSubtitles; i++)
			{
				baseClip.availableSubtitles[i].globalDataType = this.getDataTypeName("Subtitles");
			}
		}
		if (baseClip.adPattern) baseClip.adPattern.globalDataType = this.getDataTypeName("AdPattern");
		if (baseClip.trackingURLs) baseClip.trackingURLs = this.modTracking(baseClip.trackingURLs);
		if (baseClip.contentCustomData) baseClip.contentCustomData.globalDataType = this.getDataTypeName("CustomData");
		if (baseClip.ownerCustomData) baseClip.ownerCustomData.globalDataType = this.getDataTypeName("CustomData");
		if (baseClip.outletCustomData) baseClip.outletCustomData.globalDataType = this.getDataTypeName("CustomData");
		return baseClip;
	}
	this.modTracking = function(trackingUrls)
	{
		for (var i = 0;i < trackingUrls.length;i++)
		{
			trackingUrls.globalDataType = this.getDataTypeName("TrackingUrl")
		}
		return trackingUrls
	}
	this.shutDown = function()
	{
		var args = [];
		this.callFunction("shutDown", args, ["*"]);
		this.isShutDown = true;//prevent any more messages		
	}
	//vars initialized
	this.events = new Object();
	this.functions = new Object();
	this.isLoading = true;
	this.canMessage = false;
	this.messageQueue = new Array();
	this.priorityQueue = new Array();
	this.sendQueue = new Array();//yet another queue for timing externalInterface calls
	this.isSending = false;
	this.sendInterval;
	this.shutdownIDs;//array to keep all the controller ids for shutdown
	this.isShutDown = false;
	this.blankString = "__blank_string__";
	this.defaultScope = {globalDataType:this.getDataTypeName("ScopeInfo"),controlId:"javascript",isGlobal:true,isAny:false,isEmpty:false,scopeIds:["javascript","default"]};
	
}

function tpReceiveMessage(destination, message)
{
	//tpDebug("---message received---" + message.name + " dest:" + destination)
	tpController.receiveMessage(destination, message);
}


//functions for controlling external players

var tpHolderName = "pdkHolder";
var tpExternalJS;

function tpSetPlayerIDForExternal(playerName){};//no longer needed

function tpSetHolderIDForExternal(holderName)//needed
{
	tpHolderName = holderName;
}

function tpLoadExternalMediaJS()
{
	tpExternalJS = tpLoadExternalMediaJS.arguments;
	
	for (var i = 0; i < tpExternalJS.length; i++)
	{
		tpLoadScript(tpExternalJS[i]);
	}
}

function tpCleanupExternal()
{
	if (tpExternalJS)//if there's no external js, then nothing was loaded in
	{
		var scripts = window.document.getElementsByTagName('head')[0].getElementsByTagName('script');
		for (var i = 0; i < scripts.length;i++)
		{
			for (var j = 0; j < tpExternalJS.length; j++)
			{
				if (scripts[i].src == tpExternalJS[j])
				{
					window.document.getElementsByTagName('head')[0].removeChild(scripts[i]);
					break;
				}
			}
		}
		tpExternalJS.length = 0;
	}
	if (tpExternalController)
	{
		tpExternalController.cleanup();
	}
}


/////////////////////////////////////////////////////////////////////

tpScriptLoader = new ScriptLoader();

// called from flash via ExternalInterface
function tpLoadJScript(scriptFile, callback, id, atts)
{
	tpScriptLoader.addScript(scriptFile, callback, id, atts);
}

// need to wrap method to fix scoping issue on callback
function callbackDispatcher(loadObj) { tpScriptLoader.callbackDispatcher(loadObj) }
function invokeCallbacks(loadObj) { tpScriptLoader.invokeCallbacks() }

/////////////////////////////////////////////////////////////////////
//					L O A D   O B J E C T
/////////////////////////////////////////////////////////////////////
function LoadObj(scriptFile, callback, id, atts)
{
	this.script = scriptFile;
	this.callback = callback;
	this.id = id;
	this.atts = atts;
}

/////////////////////////////////////////////////////////////////////
//					S C R I P T   L O A D E R
/////////////////////////////////////////////////////////////////////


// constructor
function ScriptLoader()
{
	// queued up for loading scripts
	this.scriptQueue = new Array();
	
	// queued up for invoking callbacks
	this.callbackQueue = new Array();
}

/////////////////////////////////////////////////////////////////////
ScriptLoader.prototype.addScript = function(scriptFile, callback, id, atts)
{
	var loadObj = new LoadObj( scriptFile, callback, id, atts );
	this.scriptQueue.push(loadObj);
	
	// if the queue was empty, we need to kick
	// off the queue processing again.
	
	if (this.scriptQueue.length == 1)
		this.checkScriptQueue();
}

/////////////////////////////////////////////////////////////////////
ScriptLoader.prototype.checkScriptQueue = function()
{
	if (this.scriptQueue.length)
	{
		var loadObj = this.scriptQueue.shift();
		this.loadScript(loadObj);
	}
	else
	{
		// as a timing precaution, we wait until the queue
		// empties out before we invoke callbacks
		interval_id = setInterval("invokeCallbacks()",100) // more timing precautions :-/
		//this.invokeCallbacks();
	}
}
	
/////////////////////////////////////////////////////////////////////
ScriptLoader.prototype.callbackDispatcher = function(loadObj)
{
	for (var i in this.callbackQueue)
	{
		if (this.callbackQueue[i] == loadObj)
		{
			this.checkScriptQueue();
			return;
		}
	}
	this.callbackQueue.push(loadObj);
	this.checkScriptQueue();
}

/////////////////////////////////////////////////////////////////////
ScriptLoader.prototype.invokeCallbacks = function()
{
	clearInterval(interval_id);
	while (this.callbackQueue.length)
	{
		var loadObj = this.callbackQueue.shift();
		eval(loadObj.callback)(loadObj.script);
	}
}

/////////////////////////////////////////////////////////////////////
ScriptLoader.prototype.loadScript = function(loadObj)
{
	var scriptFilename = loadObj.script;
	var callbackFunction = loadObj.callback;
	var id = loadObj.id;
	var atts = loadObj.atts;
	
	// Create script element and set it to load the requested script
	var scriptEl = window.document.createElement('script');
	scriptEl.charset = "utf-8";
	if (id) scriptEl.id = id;
	scriptEl.type = "text/javascript";
	//scriptEl.defer = true;
	if (atts)
	{
		for (var i = 0; i < atts.length; i++)
			scriptEl.setAttribute(atts[i].att, atts[i].value);
	}
	scriptEl.src = scriptFilename;
	
	if (callbackFunction)
	{
		// Function to be called when script has finished loading
		var _onFinished = function(_loadObj, _callback)
		{
			// Invoke the callback function
			_callback(_loadObj)

			// Clean up event handlers
			this.onreadystatechange = null;
			this.onload = null;
			this.onerror = null;
		};

		// Set callback for IE
		// In defiance of MSDN documentation IE's script object has no onload handler
		scriptEl.onreadystatechange = function()
		{
			_onFinished(loadObj, callbackDispatcher);
		};

		// Set callback for W3C-compatible browsers
		scriptEl.onload = function()
		{
			_onFinished(loadObj, callbackDispatcher);
		};
		// Set another callback for W3C-compatible browsers
		// since onreadystatechange for IE also fires in case of an error
		scriptEl.onerror = function()
		{
			_onFinished(loadObj, callbackDispatcher);
		};
	}

	// Add script element to the document
	window.document.getElementsByTagName('head')[0].appendChild(scriptEl);
}

/////////////////////////////////////////////////////////////////////
// ORIGINAL LOADSCRIPT - USED BY MOVENETWORKS 
/////////////////////////////////////////////////////////////////////
function tpLoadScript(scriptFilename, callbackFunction, id, atts)
{
   	// Create script element and set it to load the requested script
   	var scriptEl = window.document.createElement('script');
   	scriptEl.charset = "utf-8";
   	if (id) scriptEl.id = id;
   	scriptEl.type = "text/javascript";
   	//scriptEl.defer = true;
   	if (atts)
   	{
   		for (var i = 0; i < atts.length; i++)
   		{
   			scriptEl.setAttribute(atts[i].att, atts[i].value);
   		}
   	}
   	scriptEl.src = scriptFilename;
   	if (callbackFunction)
   	{
   		// Function to be called when script has finished loading
   		var _onFinished = function(_callbackFunction, _scriptFilename)
   		{
   			// Invoke the callback function
   			_callbackFunction(_scriptFilename);
   
   			// Clean up event handlers
   			this.onreadystatechange = null;
   			this.onload = null;
   			this.onerror = null;
   		};
   
   		// Set callback for IE
   		// In defiance of MSDN documentation IE's script object has no onload handler
   		scriptEl.onreadystatechange = function()
   		{
   			_onFinished(callbackFunction, scriptFilename);
   		};
   
   		// Set callback for W3C-compatible browsers
   		scriptEl.onload = function()
   		{
   			_onFinished(callbackFunction, scriptFilename);
   		};
   		// Set another callback for W3C-compatible browsers
   		// since onreadystatechange for IE also fires in case of an error
   		scriptEl.onerror = function()
   		{
   			_onFinished(callbackFunction, scriptFilename);
   		};
   	}
   
   	// Add script element to the document
   	window.document.getElementsByTagName('head')[0].appendChild(scriptEl);
}

/////////////////////////////////////////////////////////////////////



//constructor for tpExternalControl
function tpExternalControllerClass()
{
	this.playerTypes = new Object();//keep a lookup of classes
	this.extPlayers = new Object();//keep the instances here
	
	this.registerExternalPlayer = function(type, playerClass)
	{
		this.playerTypes[type] = playerClass;//keep the class as a string
	}
	
	this.routeMessage = function(swfId, controllerId, streamType, funcName, args)
	{
		var curController = this.extPlayers[controllerId];//see if we have the existing controller lookup
		if (!curController) curController = this.extPlayers[controllerId] = {};//make a lookup for the controller
		var curPlayer = curController[streamType];//now see if we have the actual player object instantiated
		if (!curPlayer)
		{
			var playerClass = this.playerTypes[streamType];
			if (!playerClass) return; //we don't have the correct stream type on hand
			curPlayer = eval("new " + playerClass + "('" + swfId + "', '" + controllerId + "');");//create a new instance of the class
			if (!curPlayer) return;//abort here, too
			curController[streamType] = curPlayer;
		}
		curPlayer[funcName](args);
	}
	
	this.returnMessage = function(swfId, controllerId, funcName, args)
	{
		var obj = tpThisMovie(swfId);
		obj.receiveJSMessage(controllerId, funcName, args);
	}
	
	this.cleanup = function()
	{
		for (var controllerId in this.extPlayers)
		{
			var players = this.extPlayers[controllerId];
			for (var player in players)
			{
				players[player].cleanup();
				delete players[player];
			}
			delete this.extPlayers[controllerId];
		}
	}
}

function tpExternalMessage(swfId, controllerId, streamType, funcName, args)
{
	tpExternalController.routeMessage(swfId, controllerId, streamType, funcName, args);
}

//build this without needing the commManager
tpExternalController = new tpExternalControllerClass();

function tpShowAlert(alertCode) 
{
	switch(alertCode)
	{
		case "FULLSCREEN_DISABLED":
		//if (deconcept.SWFObjectUtil.getPlayerVersion().major < 9)
		alert("Full screen is only available with Flash 9 or later")
		break;
	}
}


/**********************************
Here is a list of the events that are produced by the flvPlayer.
Data structures are explained below.  NOTE: The mediaType for any event that sends back an entire playlist
is always "ALL".

Events that send in a playlist data type (which can include multiple clips):
onPlaylistBegin -- fired when new playlist data is first received by the player
onPlaylistEnd -- fired when a playlist has completed playing, either naturally or when it is replaced by another playlist
onClipTime -- fired every 5 seconds or so to give a snapshot of the state of the current playlist and the clips within it

Events that send in a single clip data type:
onBeginMedia -- fired when a media first starts playing, after it has buffered sufficiently.
onEndMedia -- fired when a media has completed naturally.  If a media ends because the playlist has been replaced, this event is not fired.
onMidMedia -- fired when a media reaches a point between 40 and 60 percent.  If the user skips over this section of the media, this event is not fired

playlist data type:
pl.currentDate
pl.playlistID
pl.userName
pl.countryCode
pl.regionCode
pl.browser
pl.operatingSystem
pl.feed
pl.affiliateTag
pl.playerName
pl.clips //array of clips below

clip data type:
clip.baseClip.title
clip.baseClip.author
clip.baseClip.abstract
clip.baseClip.copyright
clip.baseClip.height
clip.baseClip.width
clip.baseClip.isAd
clip.baseClip.keywords
clip.baseClip.releaseID
clip.baseClip.releaseLength -- the length of the clip as shown in system, in milliseconds
clip.baseClip.bitrate -- the bitrate of the clip as shown in system, bps (not kbps)
clip.baseClip.trueLength -- the actual length of the clip as determined at runtime, in milliseconds
clip.baseClip.trueBitrate -- the actual bitrate of the clip as determined at runtime, in kbps (not bps)
clip.baseClip.connectionBitrate -- the actual bitrate of the user's connection as determined at runtime, if this data could not be ascertained, this value will be undefined, in kbps (not bps)
clip.baseClip.loadTime -- the total miliseconds between when the request is made for the clip and when the clip starts running.
clip.baseClip.lengthPlayed -- the total miliseconds that the clip actually played, if the clip did not play, this value is undefined
clip.baseClip.rebufferingTime -- the total miliseconds the player spent buffering itself.

***************************************/

tpQOSTypeArray = new Array();
var tpQOScurrentPL;
var tpQOSunloading;

function tpRegisterQOSType(eventType, mediaType, callback)
{
	for (var i = 1; i < tpQOSTypeArray.length; i++)
	{
		if (tpQOSTypeArray[i].eventType == eventType && tpQOSTypeArray[i].mediaType == mediaType && tpQOSTypeArray[i].callback == callback)
		{
			return;//there's already one there, don't put another in
		}
	}	
	var qosTypeObj = {mediaType:mediaType, eventType:eventType, callback:callback}
	tpQOSTypeArray.push(qosTypeObj);
}

function tpUnregisterQOSType(type, callback)
{
	for (var i = 1; i < tpQOSTypeArray.length; i++)
	{
		if (tpQOSTypeArray[i].eventType == eventType && tpQOSTypeArray[i].mediaType == mediaType && tpQOSTypeArray[i].callback == callback)
		{
			tpQOSTypeArray.splice(i, 1);//get rid of the element
			break;
		}
	}
}

//called from the Player when an event is fired
function tpReceiveQOSEvent(eventType, mediaType, obj)
{
	if (obj == undefined) return;//don't do anything, the data is bad
	
	if (eventType == "onClipTime" || eventType == "onPlaylistBegin")
	{
		tpQOScurrentPL = obj;
	}
	else if (eventType == "onPlaylistEnd")
	{
		tpQOScurrentPL = null;//get rid so we don't hit twice if browser closes and a new playlist hasn't yet replaced the old
	}
	
	//go through the type array and see if we have a match
	
	for (var i = 0; i < tpQOSTypeArray.length; i++)
	{
		if (tpQOSTypeArray[i].eventType == eventType && (mediaType == "ALL" || tpQOSTypeArray[i].mediaType == mediaType || tpQOSTypeArray[i].mediaType == "ALL"))
		{
			eval(tpQOSTypeArray[i].callback)(obj);
		}
	}
}

window.onunload = function()
{
	tpQOSUnload();
}

function tpQOSUnload()
{
	if(tpQOScurrentPL == undefined || tpQOScurrentPL == null) return;
	//mock up a playlist end event
	tpQOSunloading = true;
	tpReceiveQOSEvent("onPlaylistEnd", "ALL", tpQOScurrentPL);
}

function tpQOSSendURL(url)
{
	var connection = new Image();
	connection.src = url;
	if (tpQOSunloading)
	{
		for (i = 0; ((!connection.complete) && (i < 100000)); i++)
		{
		}
	}
}




//register our functionality with the qos component
tpRegisterQOSType("onPlaylistEnd", "ALL", "QOSMPS_handlePLEnd");

//what's the base url for the mps qos?
var QOSMPS_baseUrl = "http://release.theplatform.com/tracker.log"
var QOSMPS_qs = "";
var QOSMPS_baseCount = 0;
var QOSMPS_baseClips = new Array();

function QOSMPS_handlePLEnd(pl)
{
	QOSMPS_baseCount = 0;
	QOSMPS_baseClips.length = 0;
	//the first 3 values are always the same
	
	QOSMPS_qs = "?type=qos&ver=1";
	//let's parse out the query string
	if (pl.currentDate != undefined && pl.currentDate != null && pl.currentDate != "null") QOSMPS_appendStr_qs("d", pl.currentDate);
	if (pl.userName != undefined && pl.userName != null && pl.userName != "null") QOSMPS_appendStr_qs("un", pl.userName);
	if (pl.countryCode != undefined && pl.countryCode != null && pl.countryCode != "null") QOSMPS_appendStr_qs("cc", pl.countryCode);
	if (pl.regionCode != undefined && pl.regionCode != null && pl.regionCode != "null") QOSMPS_appendStr_qs("rc", pl.regionCode);
	if (pl.browser != undefined && pl.browser != null && pl.browser != "null") QOSMPS_appendStr_qs("br", pl.browser);
	if (pl.operatingSystem != undefined && pl.operatingSystem != null && pl.operatingSystem != "null") QOSMPS_appendStr_qs("os", pl.operatingSystem);
	if (pl.feed != undefined && pl.feed != null && pl.feed != "null") QOSMPS_appendStr_qs("p", pl.feed);
	if (pl.player != undefined && pl.player != null && pl.player != "null") QOSMPS_appendStr_qs("pl", pl.player);
	if (pl.affiliate != undefined && pl.affiliate != null && pl.affiliate != "null") QOSMPS_appendStr_qs("af", pl.affiliate);
	if (pl.playlistID != undefined && pl.playlistID != null && pl.playlistID != "null") QOSMPS_appendStr_qs("prid", pl.playlistID);
	for (var i = 0;i < pl.clips.length;i++)
	{
		QOSMPS_parseClip(pl.clips[i]);
	}
	
	if (QOSMPS_baseClips.length > 1) QOSMPS_parseAggregate(pl.playlistID)//parse the aggregate data only if there are 2 or more clips
	QOSMPS_sendData(QOSMPS_qs);
}

function QOSMPS_parseClip(c)
{
	var bc = c.baseClip;
	var isC = false;
	for (var i = 0; i < QOSMPS_baseClips.length; i++)
	{
		if (QOSMPS_baseClips[i].releaseID == bc.releaseID)
		{
			if (bc.isAd)
			{
				QOSMPS_appendStr_qs("c" + QOSMPS_baseCount, "1");
				break;
			}
			else
			{
				return;//don't parse this one, it's a repeat content
			}
		}
	}
	QOSMPS_baseClips.push(bc);
	if (bc.releaseID != undefined)  QOSMPS_appendStr_qs("rid" + QOSMPS_baseCount, bc.releaseID);
	
	if (bc.title != undefined && bc.title != null && bc.title != "null")  QOSMPS_appendStr_qs("t" + QOSMPS_baseCount, bc.title);
	if (bc.author != undefined && bc.author != null && bc.author != "null")  QOSMPS_appendStr_qs("a" + QOSMPS_baseCount, bc.author);
	if (bc.releaseLength != undefined)  QOSMPS_appendStr_qs("l" + QOSMPS_baseCount, bc.releaseLength);
	if (bc.bitrate != undefined && bc.bitrate != NaN && bc.bitrate != "NaN")  QOSMPS_appendStr_qs("b" + QOSMPS_baseCount, bc.bitrate);
	if (bc.loadTime != undefined)  QOSMPS_appendStr_qs("lt" + QOSMPS_baseCount, bc.loadTime);
	if (bc.trueLength == undefined && c.baseClip.releaseLength != undefined) bc.trueLength = bc.releaseLength;
	if (bc.lengthPlayed != undefined)
	{
		var percentPlayed;
		if (bc.trueLength == -1)
		{
			percentPlayed = 100;//if it's streaming content, this is automatically 100
		}
		else
		{
			percentPlayed = QOSMPS_round((bc.lengthPlayed / bc.trueLength) * 100, 2);
		}		 
		if (percentPlayed > 100) percentPlayed = 100;
		if (!isNaN(percentPlayed))
		{
			QOSMPS_appendStr_qs("pp" + QOSMPS_baseCount, percentPlayed);
		}
	}
	if (bc.rebufferingTime != undefined)
	{
		var percentRebuff = QOSMPS_round((bc.rebufferingTime / (bc.rebufferingTime + bc.lengthPlayed)) * 100, 2);
		if (!isNaN(percentRebuff)) QOSMPS_appendStr_qs("pr" + QOSMPS_baseCount, percentRebuff);
	}
	var percentBW;
	if (bc.connectionBitrate != undefined)
	{
		if (bc.trueBitrate == undefined && bc.bitrate != undefined) bc.trueBitrate == bc.bitrate / 1000;
		percentBW = QOSMPS_round((bc.connectionBitrate / bc.trueBitrate) * 100, 2);
		if (!isNaN(percentBW))
		{
			if (percentBW > 100) percentBW = 100;//cap it out at 100%
		}
		else
		{
			percentBW = 100;
		}
	}
	else
	{
		percentBW = 100;
	}
	if (bc.lengthPlayed != undefined && bc.lengthPlayed > 0)//don't include unless the clip has played
	{
		bc.percentBW = percentBW;
		QOSMPS_appendStr_qs("pb" + QOSMPS_baseCount, percentBW)
	}
	else
	{
		bc.percentBW = undefined;
	}
	if (bc.lengthPlayed != undefined && bc.lengthPlayed > 0)  QOSMPS_appendStr_qs("lp" + QOSMPS_baseCount, bc.lengthPlayed);
	QOSMPS_baseCount++;
}

function QOSMPS_parseAggregate(plid)
{
	if (plid != undefined) QOSMPS_appendStr_qs("rid" + QOSMPS_baseCount, plid);
	var loadTime = QOSMPS_baseClips[0].loadTime;
	var trueLength = 0;
	var lengthPlayed = 0;
	var percentBW = 100;
	var bwLength = 0;//the length of the clips that have bandwidth data
	var rebuffTime = 0;
	var bwCalcArray = new Array();
	//aggregate values
	for (var i = 0; i < QOSMPS_baseClips.length; i++)
	{
		var bc = QOSMPS_baseClips[i];
		if (bc.trueLength != undefined) trueLength += bc.trueLength;
		if (bc.lengthPlayed != undefined)
		{
			if (bc.lengthPlayed > bc.trueLength) bc.lengthPlayed = bc.trueLength;//account for duration errors so pp is always <= 100;
			lengthPlayed += bc.lengthPlayed;
		}
		if (bc.rebufferingTime != undefined) rebuffTime += bc.rebufferingTime;
		if (bc.percentBW != undefined)
		{
			var bwObj = new Object();
			bwObj.percentBW = bc.percentBW;
			bwObj.trueLength = bc.trueLength;
			bwCalcArray.push(bwObj);
			bwLength += bc.trueLength;
		}
	}
	
	//calculate the weighted bandwidth
	var compositeBW = 0;
	if (bwLength > 0)
	{
		for (var i = 0; i < bwCalcArray.length; i++)
		{
			var bwObj = bwCalcArray[i];
			var percentTotal = bwObj.trueLength / bwLength;
			compositeBW += bwObj.percentBW * percentTotal
		}
	}
	if (compositeBW > 100) compositeBW = 100;
	if (trueLength > 0) QOSMPS_appendStr_qs("l" + QOSMPS_baseCount, trueLength);
	if (loadTime != undefined) QOSMPS_appendStr_qs("lt" + QOSMPS_baseCount, loadTime);
	if (lengthPlayed > 0 && trueLength > 0)
	{
		var percentPlayed = QOSMPS_round((lengthPlayed / trueLength) * 100, 2);
		if (percentPlayed > 100) percentPlayed = 100;
		if (!isNaN(percentPlayed)) QOSMPS_appendStr_qs("pp" + QOSMPS_baseCount, percentPlayed);
	}
	if (rebuffTime > 0 && trueLength > 0)
	{
		var percentRebuff = QOSMPS_round((rebuffTime / (rebuffTime + lengthPlayed))*100, 2);
		if (!isNaN(percentRebuff)) QOSMPS_appendStr_qs("pr" + QOSMPS_baseCount, percentRebuff);
	}
	if (compositeBW > 0) QOSMPS_appendStr_qs("pb" + QOSMPS_baseCount, QOSMPS_round(compositeBW, 2));
	if (lengthPlayed > 0) QOSMPS_appendStr_qs("lp" + QOSMPS_baseCount, lengthPlayed);
}

function QOSMPS_appendStr_qs(name, value)
{
	QOSMPS_qs += "&" + name + "=" + value;
}

function QOSMPS_sendData(qString)
{
	//send the query string
	var theUrl = QOSMPS_baseUrl + qString;
	tpQOSSendURL(theUrl);
	//reset the query string
	QOSMPS_qs = ""
	
}

function QOSMPS_round(num, power)
{
	var mult = Math.pow(10, power);
	var raw = num * mult;
	raw = Math.round(raw);
	return raw / mult;
}

