
					
					
						
						
					 	
							/* global functions */
/**
 * Global function for actionscript to call.
 * @private
 * @param {Object} theObj The component to search.
 * @param {Object} thePath The component's depth within the CVP.
 * @returns A recursive call.
 * @type Function
 */
function cvpSearchTheClient(theObj, thePath)
{
	if(theObj===null)
		theObj = window;

	var index = thePath.indexOf(".");
	if(index == -1)
	{
		if (thePath.indexOf("(") != -1 && thePath.indexOf(")") != -1)
			return eval("theObj." + thePath);
		else
			return theObj[thePath];
	}

	var objName = thePath.substring(0, index);
	var subPath = thePath.substring(index+1);

	var childObj = theObj[objName];
	if (objName.indexOf("(") != -1 && objName.indexOf(")") != -1)
		childObj = eval("theObj." + objName);

	if(childObj === null)
		return "";

	if(subPath.length < 1)
		return childObj.toString();

	return cvpSearchTheClient(childObj, subPath);
}

(function() {

var debug = true;
if (typeof window.CVP != 'undefined') {
	return;
}

var Class = (function(){var initializing=false, fnTest=/xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/; var Class = function(){}; Class.extend = function(prop) { var _super = this.prototype; initializing = true; var prototype = new this(); initializing = false; for (var name in prop) { prototype[name] = typeof prop[name] == "function" && typeof _super[name] == "function" && fnTest.test(prop[name]) ? (function(name, fn){ return function() { var tmp = this._super; this._super = _super[name]; var ret = fn.apply(this, arguments); this._super = tmp; return ret; }; })(name, prop[name]) : prop[name]; } function Class() { if ( !initializing && this.init ) this.init.apply(this, arguments); } Class.prototype = prototype; Class.constructor = Class; Class.extend = arguments.callee; return Class;}; return Class;})();


var VERSION = "1.6";;
var FLASH_VERSION = "9.0.115.0";

var HTML5 = "html5";
var FLASH = "flash";

var HTML5_JS = "http://i.cdn.turner.com/xslo/cvp/js/cvp.html5/cvp.html5_0.8.min.js";

/* The CVP constructor */
/**
 * Constructs a new CVP object.
 * @class This is the main CVP class.
 * Here is where the player is created and its behaviors are defined.
 * @constructor
 * @param {Object} options The various parameters that define a player.
 * @return The CVP instance.
 * @type CVP
 */
var CVP = window.CVP = function(options) {

	this.options = extend({
		id : 'cvp_player',
		width : '320',
		height : '240',
		flashVars : { },
		playerType : FLASH,
		initialize : function() {}
	}, options || {});

	this.options.embed = extend({
		containerSwf : '',
		expressInstallSwf : 'http://i.cdn.turner.com/v5cache/turnerplayer/flash/expressInstall.swf',
		flashVersion : FLASH_VERSION
	}, this.options.embed || {});

	this.options.embed.options = extend({
		quality : 'high',
        bgcolor : '#000000',
        allowFullScreen : 'true',
        allowScriptAccess : 'always'
	}, this.options.embed.options || {});

	if (!this.options.embed.containerSwf || this.options.embed.containerSwf == '') {
		log('Invalid containerSwf...exiting');
		throw "Invalid containerSwf";
		return;
	}

	this.options.initialize();

	var id = this.options.id,
		width = this.options.width,
		height = this.options.height,
		flashVars = this.options.flashVars,
		embed= this.options.embed
	;

	this._playerType = this.options.playerType;

	var player = null;
	if (this._playerType == HTML5 || (CVP.Browser.apple_mobile))
	{
		if (this.options.flashVars.containerUrl
			&& this.options.flashVars.configUrl)
		{
			log("instantiating the HTML5 player");
			this._playerType = HTML5;
			player = new CVP.Players.HTML5(this.options);
		}
		else
		{
			log("invalid HTML5 params...instantiating null player");
			this._playerType = false;
			player = new CVP.Players.NullPlayer(this.options);
		}

		this.getPlayer = function()
		{
			return player;
		};
	}
	else
	{
		log("instantiating the Flash player");
		this._playerType = FLASH;
	}

	if (CVP.findInstance(id) || byId(id)) {
		log(id + ' is already in use...exiting');
		throw id + ' is already in use';
		return;
	}

	this.getId = function() { return id };
	this.getWidth = function() { return width };
	this.getHeight = function() { return height };
	this.getFlashVars = function() { return flashVars };
	this.getEmbed = function() { return embed };
	this.getPlayerType = function() { return this._playerType };

	if (!createCallbackHandler(id)) {
		log('callback handler for id "' + id + '" could not be created...exiting');
		throw 'callback handler for id "' + id + '" could not be created...exiting';
		return;
	}

	this.callbacks = {};
	delete this.options.initialize;
	for (var p in this.options) {
		if (isFunc(this.options[p])) {
			this.callbacks[p] = this.options[p];
		}
	}

	this.handleCallBack = function() {
		var ret = null;

		if (arguments.length) {
			var funcName = arguments[0];
			var args = Array.prototype.slice.call(arguments, 1);
			log("handleCallback - " + funcName + " args(" + args.length + ")");

			if (typeof this[funcName] != 'undefined'
				&& isFunc(this[funcName])) {
				try {
					log("Found internal CB");
					ret = this[funcName].apply(this, args);
				} catch(e) {
					log("Warning - exception on internal CB " + funcName);
					log("Exception - " + e.message);
				}
			}

			if (this.callbacks[funcName]
				&& isFunc(this.callbacks[funcName])) {
				try {
					log("Found user CB");
					ret = this.callbacks[funcName].apply(this, args);
				} catch(e) {
					log("Warning - exception on user CB " + funcName);
					log("Exception - " + e.message);
				}
			}
		}

		return ret;
	};

	var contentId = this.options.flashVars.contentId || '',
		contentUrl = this.options.flashVars.contentUrl || '',
		playlistId = this.options.flashVars.playlistId || '',
		context = this.options.flashVars.context || '',
		playerInstance = context,

		contentType = '',
		contentWidth = 0,
		contentHeight = 0,

		duration = 0,
		playhead = 0,

		buffering = false,
		bufferProgress = 0,

		paused = false
	;

	this.getPlayerInstance = function() { return playerInstance };
	this.getContentId = function() { return contentId };
	this.getContentUrl = function() { return contentUrl };
	this.playlistId = function() { return playlistId };
	this.getContext = function() { return context };

	this.getContentWidth = function() { return contentWidth };
	this.getContentHeight = function() { return contentHeight };

	this.getDuration = function() { return duration };
	this.getPlayhead = function() { return playhead };

	this.isBuffering = function() { return buffering };
	this.getBufferProgress = function() { return bufferProgress };

	this.isPaused = function() { return paused };


	this.onContentMetadata = function(pContentId, pDuration, pWidth, pHeight) {
		contentId = pContentId;
		playhead = 0;
		duration = pDuration;
		contentWidth = pWidth;
		contentHeight = pHeight;

	};

	this.onContentBegin = function(pContentId) {
		contentId = pContentId;
	};

	this.onContentBuffering = function(pBuffering, pBufferProgress) {
		buffering = pBuffering;
		bufferProgress = pBufferProgress;
	};

	this.onContentPlayHead = function(pContentId, pPlayhead, pTotalDuration) {
		playhead = pPlayhead;
	};

	this.onContentPause = function(pContentId, pPaused) {
		paused = pPaused;
	};

	this.onPlayerReady = function() {
		playerInstance = this.getPlayer().getPlayerInstance();
	};

	CVP.registerInstance(id, this);
	return this;
};

/* The CVP function prototype, representing the API */
CVP.prototype = {

	/**
	 * References the player based on the browser.
	 * @returns The CVP instance.
	 * @type CVP
	 */
	getPlayer : function() {
		if (navigator.appName.indexOf("Microsoft") != -1) {
			return window[this.getId()];
		} else {
			return document[this.getId()];
		}
	},

	/**
	 * Deprecated.  Use embed() instead.
	 */
	embedSWF : function(containerElementId) {
		return this.embed.apply(this, arguments);
	},

	/**
	 * Global function for actionscript to call.
	 * @param {String} containerElementId The container element's id.
	 * @returns The CVP instance.
	 * @type CVP
	 */
	embed : function(containerElementId) {
		if (this._playerType == FLASH)
		{
			var flashvars = this.getFlashVars();
			flashvars.domId = this.getId();
			flashvars.w = this.getWidth();
			flashvars.h = this.getHeight();

			var embed = this.getEmbed();
			var container = embed.containerSwf;
			var params = embed.options;
			var express = embed.expressInstallSwf;
			var version = validateFlashVersion(embed.flashVersion);

			var attributes = {
				id : this.getId(),
				name : this.getId()
			};

			if(!CVP.swfobject.hasFlashPlayerVersion("1.0.0"))
				this.handleCallBack("onNoFlashDetected");

			CVP.swfobject.embedSWF(container, containerElementId, this.getWidth(), this.getHeight(), version, express, flashvars, params, attributes);
		}
		else
		{
			if (this.getPlayer().embed)
			{
				this.getPlayer().embed(containerElementId);
			}
		}
		return this;
	},

	/**
	 * Removes the swfobject from CVP.
	 * @returns The CVP instance.
	 * @type CVP
	 */
	removeSWF : function() {
		if (CVP.swfobject
			&& CVP.swfobject.removeSWF) {
			CVP.swfobject.removeSWF(this.getId());
		}
		return this;
	},

	/**
	 * Play a specified video by id. This call will reset the video queue and will
	 * start playing the video immediately.
	 * @param {String} id The id of the content being played.
	 * @param {Object} options More parameters for playing content.
	 * @returns The CVP instance.
	 * @type CVP
	 */
	play:function(id, options) {
		this.getPlayer().playContent(id, options || {});
		return this;
	},

	/**
	 * Plays a video from the specified URL. The queue will be cleared and the video
	 * will play immediately. The videoId will be set to the passed URL.
	 * @param {String} url The complete URL to the video.
	 * @returns The CVP instance.
	 * @type CVP
	 */
	playVideoFromUrl:function(url) {
		this.getPlayer().playVideoFromUrl(url);
		return this;
	},

	/**
	 * Paused the video playback. Asynchronous call, a callback will be made when
	 * the call completes. See callbacks.
	 * @param {String} id The id of the content being played.
	 * @param {Object} options More parameters for playing content.
	 * @returns The CVP instance.
	 * @type CVP
	 */
	pause:function() {
		this.getPlayer().pause();
		return this;
	},

	/**
	 * Resumes video playback. Asynchronous call, a callback will be made when the
	 * call completes. See callbacks.
	 * @returns The CVP instance.
	 * @type CVP
	 */
	resume:function() {
		this.getPlayer().resume();
		return this;
	},

	/**
	 * Add a video to the play queue. The video will be added to the end of the queue.
	 * If the queue is empty and there is no video playing the video will start playing
	 * immediately.
	 * @param {String} id The id of the content.
	 * @param {Object} options More parameters for playing content.
	 * @returns The CVP instance.
	 * @type CVP
	 */
	queue:function(id, options) {
		this.getPlayer().queue(id, options || {});
		return this;
	},

	/**
	 * Empties the content queue.
	 * @returns The CVP instance.
	 * @type CVP
	 */
	emptyQueue:function() {
		this.getPlayer().emptyQueue();
		return this;
	},

	/**
	 * Seeks the video playhead to a specified position. Asynchronous call, a callback
	 * will be made when the call completes. See callbacks.
	 * @param {float} time The seconds from the beginning of the video to seek to.
	 * @returns The CVP instance.
	 * @type CVP
	 */
	seek:function(time) {
		this.getPlayer().seek(time);
		return this;
	},

	/**
	 * Mutes the video player. The current volume setting will be preserved and restored
	 * when unmute is called. Calling setVolume() will unmute the player. Asynchronous
	 * call, a callback will be made when the call completes. See callbacks.
	 * @returns The CVP instance.
	 * @type CVP
	 */
	mute:function() {
		this.getPlayer().mute();
		return this;
	},

	/**
	 * Un-mutes the video player. The previous volume setting will be restored. Asynchronous
	 * call, a callback will be made when the call completes. See callbacks.
	 * @returns The CVP instance.
	 * @type CVP
	 */
	unmute:function() {
		this.getPlayer().unmute();
		return this;
	},

	/**
	 * Returns the current audio volume from the player.
	 * @param {float} volume A volume setting between 0 and 1.
	 */
	setVolume:function(volume) {
		this.getPlayer().setVolume(volume);
		return this;
	},

	/**
	 * Returns the current audio volume from the player.
	 * @returns The volume is a value between 0 and 1.
	 * @type float
	 */
	getVolume:function() {
		return this.getPlayer().getVolume();
	},

	/**
	 * Checks if the player is muted.
	 * @returns A boolen (true or false) depending if the player is muted or not.
	 * @type Boolean
	 */
	isMuted:function() {
		return this.getPlayer().isMuted();
	},

	/**
	 * Shows the menu.
	 * @returns The CVP instance.
	 * @type CVP
	 */
	showMenu:function() {
		this.getPlayer().showMenu();
		return this;
	},

	/**
	 * Hides the menu.
	 * @returns The CVP instance.
	 * @type CVP
	 */
	hideMenu:function() {
		this.getPlayer().hideMenu();
		return this;
	},

	/**
	 * Squeezes the content area.
	 * @returns The CVP instance.
	 * @type CVP
	 */
	squeeze:function(secs) {
		this.getPlayer().squeeze(secs);
		return this;
	},

	/**
	 * Un-squeezes the content area.
	 * @returns The CVP instance.
	 * @type CVP
	 */
	unsqueeze:function(secs) {
		this.getPlayer().unsqueeze(secs);
		return this;
	},

	/**
	 * This call will return the JSON for a content entry.
	 * @param {String} id The id of the content.
	 * @returns The CVP instance.
	 * @type CVP
	 */
	getContentEntry:function(id) {
		return this.getPlayer().getContentEntry(id);
	},

	/**
	 * Launch the player into full screen mode. The current video will
	 * continue to play from where it was without interruptions. Asynchronous
	 * call, a callback will be made when the call completes. See callbacks.
	 * @returns The CVP instance.
	 * @type CVP
	 */
	goFullScreen:function() {
		this.getPlayer().goFullScreen();
		return this;
	},

	/**
	 * Returns a URL for a companion Ad.
	 * @param {String} size The dimensions of the companion Ad requested. Example: ï¿½728x90ï¿½.
	 * @returns The url for a companion ad.
	 * @type String
	 */
	getCompanionAd:function(size) {
		return this.getPlayer().getCompanionAd(size);
	},

	/**
	 * Returns the dynamically generated tile id used in calls to DE.
	 * @returns The tile id as a String
	 * @type String
	 */
	getAdId:function() {
		return this.getPlayer().getAdId();
	},

	/**
	 * Returns the ad id associated to the given ad.  The id returned is the one received
	 * from the ad server response.  Please note that currently only DFP sets the ad id.
	 * @returns The ad id as a String
	 * @type String
	 */
	getTileId:function() {
		return this.getPlayer().getTileId();
	},

	/**
	 * Sets the video quality of the player. The quality change will not be applied
	 * to the current video; quality becomes effective from the next video.
	 * @param {String} String with ï¿½highï¿½ or ï¿½lowï¿½, representing the video quality
	 * @returns The CVP instance.
	 * @type CVP
	 */
	setContentQuality:function(quality) {
		this.getPlayer().setContentQuality(quality);
		return this;
	},

	/**
	 * Returns the current video quality of the video control.
	 * @returns Returns a string with ï¿½highï¿½ or ï¿½lowï¿½, representing the video quality.
	 * @type String
	 */
	getContentQuality:function() {
		return this.getPlayer().getContentQuality();
	},

	/**
	 * Disables the overlaid toolbar from appearing. Useful when the video control is
	 * being driven from Javascript
	 * @returns The CVP instance.
	 * @type CVP
	 */
	disableToolBar:function() {
		this.getPlayer().disableToolBar();
		return this;
	},

	/**
	 * Enable the overlaid toolbar. Please note the toolbar is enabled by default.
	 * @returns The CVP instance.
	 * @type CVP
	 */
	enableToolBar:function() {
		this.getPlayer().enableToolBar();
		return this;
	},

	/**
	 * Enable the next up slate.
	 * @returns The CVP instance.
	 * @type CVP
	 */
	enableNextUpSlate:function() {
		this.getPlayer().enableNextUpSlate();
		return this;
	},

	/**
	 * Disable the next up slate.
	 * @returns The CVP instance.
	 * @type CVP
	 */
	disableNextUpSlate:function() {
		this.getPlayer().disableNextUpSlate();
		return this;
	},

	/**
	 * Writes the logged comments to he debugger.
	 * @param {Object} filters Parameters for filtering the logs.
	 * @returns The CVP instance.
	 * @type CVP
	 */
	startLogging:function(filters) {
		this.getPlayer().startLogging(filters);
		return this;
	},

	/**
	 * Resets the number of videos to play before an ad is shown.
	 * @returns The CVP instance.
	 * @type CVP
	 */
	resetAdFrequency:function() {
		this.getPlayer().resetAdFrequency();
		return this;
	},

	/**
	 * Sets the current ad context's name.
	 * @param {String} strContextName The name of the context to set.
	 * @param {int} bGlobalFrequency The global ad frequency.
	 * @returns The CVP instance.
	 * @type CVP
	 */
	setAdCurrentContext:function(strContextName, bGlobalFrequency) {
		this.getPlayer().setAdCurrentContext(strContextName, bGlobalFrequency);
		return this;
	},

	/**
	 * Sets the current ad section.
	 * @param {String} section The name of the section to set.
	 * @param {int} bGlobalFrequency The global ad frequency.
	 * @returns The CVP instance.
	 * @type CVP
	 */
	setAdSection:function(section) {
		this.getPlayer().setAdSection(section);
		return this;
	},

	/**
	 * Sets the current ad's value based on a passed key.
	 * @param {String} key The key to set.
	 * @param {String} value The value to set the key to.
	 * @returns The CVP instance.
	 * @type CVP
	 */
	setAdKeyValue:function(key, value) {
		this.getPlayer().setAdKeyValue(key, value);
		return this;
	},

	/**
	 * Returns the currently available bitrates.
	 * @param {Object} filter Parameters to further organize the results.
	 * @returns A list of bitrates.
	 * @type Object
	 */
	getAvailableBitrates:function(filter)
	{
		return this.getPlayer().getAvailableBitrates(filter);
	},

	/**
	 * Returns the passed bitrate's label.
	 * @param {String} bitrate Parameters to further organize the results.
	 * @returns The bitrate's string label.
	 * @type String
	 */
	getBitrateLabel:function(bitrateId)
	{
		return this.getPlayer().getBitrateLabel(bitrateId);
	},

	/**
	 * Returns the bitrate's id.
	 * @returns The bitrate's id.
	 * @type String
	 */
	getBitrateId:function()
	{
		return this.getPlayer().getBitrateId();
	},

	/**
	 * Sets the current bitrate's id.
	 * @param {String} bitrateId The id to set.
	 * @returns The bitrate's string label.
	 * @type String
	 */
	setBitrateId:function(bitrateId)
	{
		return this.getPlayer().setBitrateId(bitrateId);
	},

	/**
	 * Sets the current tracking context.
	 * @param {String} value The context value to set.
	 * @returns The CVP instance.
	 * @type CVP
	 */
	setTrackingContext:function( value) {
		this.getPlayer().setTrackingContext(value);
		return this;
	},

	/**
	 * Returns the current context.
	 * @returns The context string.
	 * @type String
	 */
	getTrackingContext:function() {
		return this.getPlayer().getTrackingContext();
	},

	/**
	 * Pause when the next content is available.
	 * @returns The CVP instance.
	 * @type CVP
	 */
	pauseNextUpCountdown:function() {
		this.getPlayer().pauseNextUpCountdown(true);
		return this;
	},

	/**
	 * Resume when the next content is available.
	 * @returns The CVP instance.
	 * @type CVP
	 */
	resumeNextUpCountdown:function() {
		this.getPlayer().pauseNextUpCountdown(false);
		return this;
	},

	/**
	 * Resizes video player area
	 * @returns The CVP instance.
	 * @newWidth The new width of the CVP player
	 * @newHeight The new height of the CVP player
	 */
   resizeVideo: function(newWidth, newHeight) {
      this.getPlayer().resizeVideo(newWidth,newHeight);
      return this;
    }


};

/* Stubs */
CVP.Utils = {};
CVP.Events = {};
CVP.Browser = {};
CVP.Players = {};

/* 'Static' members on the CVP object */
/**
 * The current CVP version.
 * @private
 */
CVP.version = VERSION;

/**
 * An error constant for video not found.
 * @private
 */
CVP.VIDEO_NOT_FOUND_ERROR = "video not found";
/**
 * An error constant for xml not found.
 * @private
 */
CVP.VIDEO_XML_NOT_FOUND_ERROR = "cms error";

/**
 * Instances object.
 * @private
 */
CVP.instances = {};

/**
 * Sets the specified CVP instance.
 * @private
 * @param {String} id The instance's id.
 * @param {Object} instance The instance object to set.
 */
CVP.registerInstance = function(id, instance) {
	CVP.instances[id] = instance;
};

/**
 * Un-registers the specified CVP instance.
 * @private
 * @param {String} id The instance's id.
 */
CVP.unregisterInstance = function(id) {
	CVP.instances[id] = null;
};

/**
 * Returns the specified CVP instance.
 * @private
 * @param {String} id The instance's id.
 * @returns The CVP instance object.
 * @type Object
 */
CVP.findInstance = function(id) {
	return CVP.instances[id];
};

/**
 * Handles a registered callback.
 * @private
 * @param {String} id The callback's id.
 * @param {Object} args Optional parameters for the callback function.
 */
CVP.onCallback = function(id, args) {
	var instance = CVP.findInstance(id);
	if (instance) {
		return instance.handleCallBack.apply(instance, args);
	} else {
		log("Error - onCallback - unable to find instance " + id);
	}
};

/**
 * Sets all instances of CVP to null.
 * @private
 */
CVP.cleanup = function() {
	for (var inst in CVP.instances) {
		window[inst + '_callback_handler'] = null;
		CVP.instances[inst] = null;
	}
};

/* Event impl
 * Note - this should come before utils, as some utilities make use of the custom event class
 */

/**
 * Event handling functionality
 */

/**
 * Will fire an event as soon as the DOM is ready
 * @param handler The function to execute on ready.
 */
CVP.Events.onReady = function(handler)
{
	if (!CVP.swfobject)
		throw new Error("swfobject is required for onReady functionality");
	CVP.swfobject.addDomLoadEvent(handler);
};

CVP.Events.addListener = function(element, type, handler)
{
	if (element.addEventListener)
		element.addEventListener(type, handler, false);
	else
	{
		if (!handler.$$guid) handler.$$guid = CVP.Events.addListener.guid++;
		if (!element.events) element.events = {};
		var handlers = element.events[type];
		if (!handlers)
		{
			handlers = element.events[type] = {};
			if (element['on' + type]) handlers[0] = element['on' + type];
			element['on' + type] = CVP.Events._handleEvent;
		}

		handlers[handler.$$guid] = handler;
	}
};
CVP.Events.addListener.guid = 1;

CVP.Events.removeListener = function(element, type, handler)
{
	if (element.removeEventListener)
		element.removeEventListener(type, handler, false);
	else if (element.events && element.events[type] && handler.$$guid)
		delete element.events[type][handler.$$guid];
};

CVP.Events._handleEvent = function(event)
{
	event = event || CVP.Events._fixEvent(window.event);
	var returnValue = true;
	var handlers = this.events[event.type];

	for (var i in handlers)
	{
		if (!Object.prototype[i])
		{
			this.$$handler = handlers[i];
			if (this.$$handler(event) === false) returnValue = false;
		}
	}

	if (this.$$handler) this.$$handler = null;

	return returnValue;
};

CVP.Events._fixEvent = function(event)
{
	event.preventDefault = CVP.Events._fixEvent._preventDefault;
	event.stopPropagation = CVP.Events._fixEvent._stopPropagation;
	return event;
};
CVP.Events._fixEvent._preventDefault = function()
{
	this.returnValue = false;
};
CVP.Events._fixEvent._stopPropagation = function()
{
	this.cancelBubble = true;
};



CVP.Events.CustomEvent = Class.extend({
	init : function(type) {
		this._type = type;
		this._listeners = [];
	},

	addListener : function(fn, scope) {
		this._listeners.push({ fn : fn, scope : scope });
	},

	removeListener : function(fn, scope) {
		var len = this._listeners.length;
		for (var i = 0; i < len; i++)
		{
			var o = this._listeners[i];
			if (o.fn == fn && o.scope == scope)
			{
				this._listeners.splice(i, 1);
				break;
			}
		}
	},

	dispatch : function() {
		var len = this._listeners.length;
		for (var i = 0; i < len; i++)
		{
			var o = this._listeners[i];
			o.fn.apply(o.scope, arguments);
		}
	}
});

/* CVP Utilities */
/**
 * An object containing miscellaneous utility functions and
 * variables.
 * @class An object containing miscellaneous utility functions
 * and variables.
 */
CVP.Utils = {

	/**
	 * Tests to determine if the obj parameter is undefined.
	 * @param {Object} obj The object to test.
	 * @returns The Boolean result: true or false.
	 * @type Boolean.
	 */
	undef : function(obj) {
		return obj == undefined;
	},

	/**
	 * Tests to determine if the obj parameter is null.
	 * @param {Object} obj The object to test.
	 * @returns The Boolean result: true or false.
	 * @type Boolean.
	 */
	isNull : function(obj) {
		return CVP.Utils.undef(obj) || obj == null;
	},

	/**
	 * Tests to determine if the str param is an empty String.
	 * @param {String} str The String to test.
	 * @returns The Boolean result: true or false.
	 * @type Boolean.
	 */
	empty : function(str) {
		return CVP.Utils.undef(str) || CVP.Utils.isNull(str) || str == "";
	},

	/**
	 * Tests to determine if the parameter's type is 'function'.
	 * @param {Object} f The object to test.
	 * @returns The Boolean result: true or false.
	 * @type Boolean.
	 */
	isFunc : function(f) {
		return typeof f == 'function';
	},

	/**
	 * Tests to determine if the parameter's type is 'object'.
	 * @param {Object} obj The object to test.
	 * @returns The Boolean result: true or false.
	 * @type Boolean.
	 */
	isObject : function(obj) {
		return typeof obj == "object";
	},

	/**
	 * Tests to determine if the parameter's type is 'string'.
	 * @param {Object} obj The object to test.
	 * @returns The Boolean result: true or false.
	 * @type Boolean.
	 */
	isString : function(obj) {
		return typeof obj == "string";
	},

	/**
	 * Tests to determine if the passed string flag is active.
	 * The possible true values are "yes", "true", and "on".
	 * All other values will return false.
	 * @param {String} str The string flag.
	 * @param {String} bDefault The flag's default value.
	 * @returns The Boolean result: true or false.
	 * @type Boolean.
	 */
	isFlagActive : function(str, bDefault)
	{
		if (CVP.Utils.empty(str))
			return bDefault;

		switch (str.toLowerCase())
		{
			case "yes":
			case "true":
			case "on":
				return true;
			break;
			default:
				return false;
		}
	},

	/**
	 * extend.
	 * @param {Object} target
	 * @param {Object} source
	 * @returns The target object.
	 * @type Object
	 */
	extend : function (target, source) {
		if (!target) target = {};
		for (var p in source) {
			target[p] = source[p];
		}
		return target;
	},

	/**
	 * Retrieves the object on the page by the passed in id.
	 * @param {String} id The element's unique identifier.
	 * @returns The desired element.
	 * @type Object
	 */
	byId : function(id) {
		return document.getElementById(id);
	},

	/**
	 * Query the page for a specific element.
	 * @param {String} str The query string.
	 * @returns The desired element.
	 * @type Object
	 */
	query : function(str)
	{
		return CVP.Utils.isString(id) ? document.querySelector(str) : str;
	},

	/**
	 * Performs the slice function on the passed array.
	 * @param {Array} arr The array to slice.
	 * @param {int} index The array's index to start the slice.
	 * @returns The resulting array after it has been sliced at the
	 * passed index.
	 * @type Array
	 */
	slice : function(arr, index) {
		return Array.prototype.slice.call(arr, index || 0);
	},

	/**
	 * bind.
	 * @param {Function} func
	 * @param {String} scope
	 * @param {Object} args
	 * @returns
	 * @type
	 */
	bind : function(func, scope, args) {
		var args = CVP.Utils.slice(arguments, 2);
		return function() {
			var a = args.concat(CVP.Utils.slice(arguments));
  			return func.apply(scope, a);
		}
	},

	/**
	 * template.
	 * @param {Object} template
	 * @param {Object} values
	 * @returns The template.
	 * @type Object
	 */
	template : function(template, values)
	{
		var matches = template.match(/{.*?}/g);
		if (matches && matches.length)
		{
			var args = CVP.Utils.slice(arguments, 1),
				isObj = CVP.Utils.isObject(values),
				key,
				len = matches.length;

			for (var i = 0; i < len; i++)
			{
				if (isObj)
				{
					key = matches[i].split("{")[1].split("}")[0];
					if (!values[key])
						continue;
					template = template.replace(matches[i], values[key]);
				}
				else if (i < args.length)
				{
					value = args[i];
					template = template.replace(matches[i], args[i]);
				}
			}
		}
		return template;
	},

	/**
	 * Epoch to Date instance
	 * @param {Number} epoch
	 * @return The Date instance
	 * @type Date
	 */
	epochToDate : function(epoch) {
		if(epoch < 10000000000)
			epoch *= 1000;
		var d = new Date();
		d.setTime(epoch);
		return d;
	},

	/**
	 * Parses the passed object into a string inserting the passed
	 * delimiter string.
	 * @param {Object} obj The object to parse into a string.
	 * @param {String} delimiter The string added to the result as a delimiter.
	 * @returns A string of the parsed object.
	 * @type String
	 */
	joinKeys : function(obj, delimiter)
	{
		if (nil(delimiter)) delimiter = ",";

		var str = "";
		for (var p in obj)
		{
			str += p + "=" + obj[p] + delimiter;
		}
		str = str.substr(0, str.length - 1);
		return str;
	},

	/**
	 * Returns a map of query params
	 *
	 * @param {Str} str The optional query string source
	 * @returns A map of query params
	 * @type Object
	 */
	getQueryParams : function(str) {
	  	var params = {},
	  		source = str || document.location.href;

		try{
			var data = (source.split("?", 2)[1] || "").split("#")[0].split("&") || [];
			for(var i = 0; i< data.length; i++){
				var pair = data[i].split("=");
				if(pair[0])
					params[pair[0]] = unescape(pair[1]);
			}
		}
		catch(e){
			CVP.Utils.log("unable to get url params");
		}

		Utils.getQueryParams = function() { return params; };
		return Utils.getQueryParams();
	},

	/**
	 * Returns a query param value
	 *
	 * @param {Str} key The query param to retrieve
	 * @returns The query param value
	 * @type String
	 */
	getQueryParam : function(key) {
	  	return CVP.Utils.getQueryParams()[key];
	},

	/**
	 * Prints the logs.
	 */
	log : function() {
		if (window.console
			&& window.console.log
			&& debug) {
			window.console.log(CVP.Utils.slice(arguments).join(" | "));
		}
	},

	/**
	 * Prints the logs.
	 * @param {Object} obj
	 * @param {String} str
	 */
	print : function(obj, str) {
		if (str != "nested")
			CVP.Utils.log("\nPrint all values for ", str);

		for (var o in obj)
		{
			if (!o) continue;

			if (CVP.Utils.isObject(obj[o]))
			{
				CVP.Utils.log("Printing nested object value", o);
				CVP.Utils.print(obj[o], "nested");
			}
			else
			{
				CVP.Utils.log(str=="nested" ? "\t" : "", "key:", o, "value:", obj[o]);
			}
		}

		if (str != "nested")
		{
			CVP.Utils.log("End Print all values for ", str);
			CVP.Utils.log("\n");
		}
	}
};

/**
 * The queue containing the CVP's requested commands.
 * @class The queue containing the CVP's requested commands.
 * @extends CVP.Utils
 */
CVP.Utils.CommandQueue = Class.extend({

	/**
	 * Initializes the queue.
	 * @function
	 * @memberOf CVP.Utils.CommandQueue
	 */
	init : function()
	{
		this._queue = [];
	},

	/**
	 * Pushes a new command into the queue.
	 * @param {Function} fn The function to put in the queue.
	 * @param {String} scope The scope of the command.
	 * @param {Object} args Additional, optional parameters.
	 * @memberOf CVP.Utils.CommandQueue
	 */
	push : function(fn, scope, args)
	{
		this._queue.push({ fn : fn, scope : scope, args : args });
	},

	/**
	 * Removes a command from the queue according to the given index.
	 * @param {int} index The index of the queue to remove the command.
	 * @memberOf CVP.Utils.CommandQueue
	 */
	remove : function(index)
	{
		index = CVP.Utils.isNull(index) ? this._queue.length - 1 : index;
		this._queue.splice(index, 1);
	},

	/**
	 * Run the commands in the queue.
	 * @memberOf CVP.Utils.CommandQueue
	 */
	execute : function()
	{
		var len = this._queue.length;
		if (len)
		{
			for (var i = 0; i < len; i++)
			{
				var cmd = this._queue[i];
				cmd.fn.apply(cmd.scope, cmd.args);
			}
		}
	}
});

/**
 * A base class representing an asset to be used by CVP.
 * @class Contains variables and methods pertaining to the management of an
 * assets.
 * @extends CVP.Utils
 */
CVP.Utils.Asset = Class.extend({

	/**
	 * Initializes the asset.
	 * @param {String} url The asset's source url.
	 * @param {String} type The asset's type.
	 * @memberOf CVP.Utils.Asset
	 */
	init : function(url, type)
	{
        this._firedSuccess = false;
		this._url = url;
		this._type = CVP.Utils.isNull(type) ? this._determineType() : type;
		this.id = "cvp_asset_" + Math.round(Math.random() * 1000);

		this.eSuccess = new CVP.Events.CustomEvent();
		this.eFailure = new CVP.Events.CustomEvent();
	},

	/**
	 * Determine's the type of the asset.
	 * @private
	 * @returns The extension of the file.
	 * @type String
	 * @memberOf CVP.Utils.Asset
	 */
	_determineType : function()
	{
		var ext = (CVP.Utils.empty(this._url)) ? "" : this._url.substring(this._url.lastIndexOf(".") + 1);
		return ext;
	},

	/**
	 * Loads the asset.
	 * @memberOf CVP.Utils.Asset
	 */
	load : function()
	{
		log("Asset", "loading type", this._type);
		switch(this._type)
		{
			case "js":
				this._loadJs();
				break;
			case "css":
				this._loadCss();
				break;
			default:
				this._failure();
		}
	},

	/**
	 * This function is called when the asset loads successfullly.
	 * @private
	 * @memberOf CVP.Utils.Asset
	 */
	_success : function()
	{
		log("Asset", "successfully loaded asset", this._url);
		this.eSuccess.dispatch();
        this._firedSuccess = true;
	},

	/**
	 * This function is called when the asset fails to load.
	 * @private
	 * @memberOf CVP.Utils.Asset
	 */
	_failure : function()
	{
		log("Asset", "failed to load asset", this._url);
		this.eFailure.dispatch();
	},

	/**
	 * Loads a javascript asset.
	 * @private
	 * @memberOf CVP.Utils.Asset
	 */
	_loadJs : function()
	{
		var head = document.getElementsByTagName("head")[0];
		if (!head)
		{
			this._failure();
			return;
		}

		var script = document.createElement('script');
		script.id = this.id;
		script.type = 'text/javascript';

        var success = CVP.Utils.bind(this._success, this);
        var successCB = function() {
        	if (this._firedSuccess)
            	return;

        	success();
        	script.onload = script.onreadystatechange = null;
        	head.removeChild(script);
        };

		script.onload = successCB;
		script.onerror = CVP.Utils.bind(this._failure, this);
        script.onreadystatechange= function ()
        {
            if (this.readyState == 'loaded' || this.readyState == 'complete')
            {
               successCB();
            }
        };

		script.src = this._url;
		head.appendChild(script);

	},

	/**
	 * Loads a css asset.
	 * @private
	 * @memberOf CVP.Utils.Asset
	 */
	_loadCss : function()
	{
		var head = document.getElementsByTagName("head")[0];
		if (!head)
		{
			this._failure();
			return;
		}

		var node = document.createElement('link');
		node.type = 'text/css';
		node.rel = 'stylesheet';
		node.href = src;
		node.media = 'screen';
		head.appendChild(node);

		this._success();
	}
});

/* 'Private' Utils */

/**
 * Add the global callback handler for a particular instance of CVP.
 * @private
 * @param {String} id The callback id.
 * @returns True or false based on the success of the creation of
 * the callback.
 * @type Boolean
 */
function createCallbackHandler(id) {
	var funcName = id + '_callback_handler';
	if (typeof window[funcName] != 'undefined')
		return false;

	window[funcName] = function() {
		var ret = CVP.onCallback(id, arguments);
		if (typeof ret != 'undefined') {
			return ret;
		}
	};
	return true;
}

/**
 * Validate the embed flash version against our min version.
 * @private
 * @param {String} embedVersion The embed version's name.
 * @returns The correct flash version name.
 * @type String
 */
function validateFlashVersion(embedVersion)
{
	if (embedVersion === FLASH_VERSION)
		return embedVersion;

	if (typeof embedVersion == "undefined" || embedVersion == null)
		return FLASH_VERSION;

	FLASH_VERSION += "";
	embedVersion += "";

	var f1 = FLASH_VERSION.split(".");
		f2 = embedVersion.split("."),
		f1V = 0,
		f2V = 0
	;

	for (var i = 0; i < f1.length; i++)
	{
		f1V = f1[i] * 1;
		f2V = f2[i] * 1;

		if (isNaN(f2V) ||
			f1V > f2V)
			return FLASH_VERSION;
		else if (f2V > f1V)
			return embedVersion;
	}
	return FLASH_VERSION;
}

/**
 * Adds before unloading.
 * @private
 * @param {Function} func The function to add.
 */
function addBeforeUnLoadEvent(func)
{
	var oldfunc = window.onbeforeunload;
	if (typeof window.onbeforeunload != 'function')
	{
		window.onbeforeunload = func;
	}
	else
	{
		window.onbeforeunload = function()
		{
			if (oldfunc)
			{
				oldfunc();
			}
			func();
		}
	}
}

/* Aliases */
var byId = CVP.Utils.byId;
var extend = CVP.Utils.extend;
var isFunc = CVP.Utils.isFunc;
var bind = CVP.Utils.bind;
var log = CVP.Utils.log;

/**
 * Class object.
 * @private
 */
CVP.Class = Class;

/* Converters */
CVP.Utils.JsonConverter = {
	escapeString : function(str)
	{
		var s = "";
		var ch;

		if (!CVP.Utils.empty(str))
		{
			var len = str.length;

			for (var i = 0; i < len; i++)
			{

				ch = str.charAt(i);

				switch (ch)
				{
					case '"': // quotation mark
						s += "\\\\\"";
						break;


					case '\\': // reverse solidus
						s += "\\\\";
						break;

					case '\b': // bell
						s += "\\b";
						break;

					case '\f': // form feed
						s += "\\f";
						break;

					case '\n': // newline
						s += "\\n";
						break;

					case '\r': // carriage return
						s += "\\r";
						break;

					case '\t': // horizontal tab
						s += "\\t";
						break;

					default: // everything else

						if (ch < ' ')
						{
							var hexCode = ch.charCodeAt(0).toString(16);

							var zeroPad = hexCode.length == 2 ? "00" : "000";

							s += "\\u" + zeroPad + hexCode;
						}
						else
						{

							s += ch;

						}
				} // end switch

			} // end for loop
		return "\"" + s + "\"";
		}
	},

	convertNode : function(xml, ident, nodeType)
	{
		if (CVP.Utils.empty(ident))
			ident = ""; //optional param

		if (CVP.Utils.empty(nodeType))
			nodeType = ""; //optional param

		var json = ident;

		if (nodeType == "")
			json += "{";

		ident = ident + "\t";
		var first = true;

		if (!CVP.Utils.undef(xml.attributes))
		{
			var removeAttributes = new Array();
			for (var i = 0; i < xml.attributes.length; i++)
			{
				var attribute = xml.attributes[i];

				if (!CVP.Utils.undef(attribute.nodeName) && !(attribute.nodeName.indexOf('xmlns') >= 0))
				{
					if (first)
					{
						first = false;
						json += "\n";
					}
					else
					{
						json += ",\n";
					}

					if (nodeType == 'array')
						json += ident + "{";
					else
						json += ident;

					json += "\"" + attribute.nodeName + "\":" + CVP.Utils.JsonConverter.escapeString(attribute.nodeValue);

					if (nodeType == 'array')
						json += "}";
				} else {
					if (!CVP.Utils.undef(attribute.nodeName)) {
						removeAttributes.push(attribute.nodeName);
					}
				}
			}
			if (removeAttributes.length > 0) {
				for (var i = 0; i < removeAttributes.length; i++) {
					xml.removeAttribute(removeAttributes[0]);
				}
			}
		}

		var type;
		var name;

		if (!CVP.Utils.undef(xml.childNodes))
		{
			for (var i = 0; i < xml.childNodes.length; i++)
			{
				var node = xml.childNodes[i];

				if (!CVP.Utils.undef(node.tagName))
				{
					if (first)
					{
						first = false;
						json += "\n";
					}
					else
					{
						json += ",\n";
					}

					name = node.tagName;

					if (CVP.Utils.empty(name))
					{
						name = "text";
					}

					/**
					 * If it's an array, the output should look like this :
					 * prop : [
					 * 		{ entry1 : { prop1 : hi } },
					 * 		{ entry2 : { prop2 : bye } },
					 * ]
					 */

					json += ident;

					if (nodeType == 'array')
						json += "{";

					if ((CVP.Utils.empty(node.childNodes) || node.childNodes.length <= 1) &&
						(CVP.Utils.empty(node.attributes) || node.attributes.length == 0) &&
						!(node.childNodes.length > 0 && node.childNodes[0].nodeType == 1))
					{
						if (node.childNodes.length > 0)
							json += "\"" + name + "\":" + CVP.Utils.JsonConverter.escapeString(node.childNodes[0].nodeValue);
						else
							json += "\"" + name + "\":" + "\"\"";
					}
					else
					{
						var isArray = CVP.Utils.JsonConverter.isNodeAnArray(node);
						json += "\"" + name + "\":" + (isArray ? "[" : "{") + "\n";

						if (node.childNodes.length > 0 && !CVP.Utils.empty(node.childNodes[0].nodeValue))
							json += "\"text\":" + CVP.Utils.JsonConverter.escapeString(node.childNodes[0].nodeValue) + ",";

						type = isArray ? 'array' : 'object';
						json += CVP.Utils.JsonConverter.convertNode(node, ident, type);
					}

					if (nodeType == 'array')
						json += "}";
				}
			}
		}
		ident = ident.substr(0, ident.length - 1);
		json += "\n" + ident;
		json += (nodeType == 'array') ? "]" : "}";
		return json;
	},

	/**
	 * Detect if an XML node should be converted to a
	 * JSON array
	 *
	 * This assumes that if two or more child nodes of the
	 * passed in node have the same name, than the node
	 * should be treated as an array
	 *
	 * Example : <files> would be treated as an array
	 *  <files>
	 *  <file bitrate="150" type="hp">...</file>
	 *  <file bitrate="300" type="standard">...</file>
	 *  <file bitrate="600" type="hd">...</file>
	 *  </files>
	 */
	isNodeAnArray : function(node)
	{
		var names = {};

		if (!CVP.Utils.undef(node.childNodes))
		{
			for (var i = 0; i < node.childNodes.length; i++)
			{
				var element = node.childNodes[i];

				if (!CVP.Utils.empty(element.tagName))
				{
					if (!CVP.Utils.empty(names[element.tagName]))
						return true;
					else
						names[element.tagName] = "exists";
				}
			}
		}
		return false;
	},

	encodeXmlObject : function(xmlObj)
	{
		var json = CVP.Utils.JsonConverter.convertNode(xmlObj);
		return json;
	}
};

/* Browser detection */
/**
 * A function to detect the current browser.
 * @private
 * @returns An object with browser info.
 * @type Object
 */
CVP.Browser = (function() {
	var ua = navigator.userAgent;

	var chrome = !!ua.match(/chrome/i);

	var iphone = !!ua.match(/iPhone/i);
	var ipod = !!ua.match(/iPod/i);
	var ipad = !!ua.match(/iPad/i);

	var apple_mobile = (iphone || ipod || ipad);

	return {
		chrome : chrome,

		iphone : iphone,
		ipod : ipod,
		ipad : ipad,
		apple_mobile : apple_mobile
	};
})();

/* Player impls */
/**
 * The HTML5 player.
 * @private
 */
CVP.HTML5 = HTML5;
/**
 * The Flash player.
 * @private
 */
CVP.FLASH = FLASH;

CVP.Players.NullPlayer = Class.extend({
	init : function()
	{
		var functions = "play,playVideoFromUrl,pause,resume,queue,emptyQueue,seek,mute,unmute,setVolume,getVolume,isMuted,showMenu,hideMenu,squeeze,unsqueeze,getContentEntry,goFullScreen,getCompanionAd,getAdId,getTileId,setContentQuality,getContentQuality,disableToolBar,enableToolBar,enableNextUpSlate,disableNextUpSlate,startLogging,resetAdFrequency,setAdCurrentContext,setAdSection,setAdKeyValue,getAvailableBitrates,getBitrateLabel,getBitrateId,setBitrateId,setTrackingContext,getTrackingContext,pauseNextUpCountdown";
		var functions = functions.split(",");
		for (var f in functions)
		{
			if (!this[functions[f]])
				this[functions[f]] = function() {};
		}
	}
});

/**
 * Wrapper around the HTML5 Player instance
 */
CVP.Players.HTML5 = CVP.Players.NullPlayer.extend({
	init : function(options)
	{
		this._super();

		this._options = options;
		this._instance = null;

		this._loadQ = new CVP.Utils.CommandQueue();
		this._loaded = false;


		this._load();
	},

	_load : function()
	{
		if (CVP.Players._HTML5Player)
		{
			this._onLoaded();
		}
		else
		{
			var asset = new CVP.Utils.Asset(this._options.flashVars.html5_js_url || HTML5_JS);
			asset.eSuccess.addListener(bind(this._onLoaded, this));
			asset.eFailure.addListener(bind(this._onLoadError, this));
			asset.load();
		}
	},

	_onLoaded : function()
	{
		if (CVP.Players._HTML5Player)
		{
			this._instance = new CVP.Players._HTML5Player(this._options);
			this._instance.ePlayerLoaded.addListener(this._onPlayerLoaded, this);
			this._instance.ePlayerReady.addListener(this._onPlayerReady, this);

			this._instance.ePlayerReady.addListener(bind(this._onCallBack, this, 'onPlayerReady'));
			this._instance.eContentBegin.addListener(bind(this._onCallBack, this, 'onContentBegin'));
			this._instance.eContentPlay.addListener(bind(this._onCallBack, this, 'onContentPlay'));
			this._instance.eContentCompleted.addListener(bind(this._onCallBack, this, 'onContentCompleted'));

			this._instance.eAdStarted.addListener(bind(this._onCallBack, this, 'onAdStarted'));
			this._instance.eAdFinished.addListener(bind(this._onCallBack, this, 'onAdFinished'));
			this._instance.eAdError.addListener(bind(this._onCallBack, this, 'onAdError'));
		}
		else
		{
			log("HTML5 player not found");
		}
	},

	_onLoadError : function()
	{
		log("HTML5 load error");
	},

	_onPlayerLoaded : function()
	{
		log("_onPlayerLoaded");
		this._loaded = true;
		this._loadQ.execute();
	},

	_onPlayerReady : function()
	{
		log("_onPlayerReady");
	},

	embed : function(containerElement)
	{
		if (!this._loaded)
		{
			log("queuing embed");
			this._loadQ.push(this.embed, this, arguments);
			return;
		}
		log("executing embed");
		this._instance.render(containerElement);
	},

	playContent : function(contentId, options)
	{
		this._instance.play(contentId, options);
	},

	queue : function(contentId, options)
	{
		this._instance.queue(contentId, options);
	},

	pause : function()
	{
		this._instance.pause();
	},

	resume : function()
	{
		this._instance.resume();
	},

	setVolume : function(v)
	{
		this._instance.setVolume(v);
	},

	getVolume : function()
	{
		return this._instance.getVolume();
	},

	mute : function()
	{
		this._instance.mute();
	},

	unmute : function()
	{
		this._instance.unmute();
	},

	getContentEntry:function(id)
	{
		return this._instance.getContentEntry(id);
	},

	_onCallBack : function()
	{
		log("HTML5", arguments[0]);
		CVP.onCallback(this._options.id, arguments);
	},

	instance : function()
	{
		return this._instance;
	},

	supported : function()
	{
		return !!document.createElement('video').canPlayType;
	}
});




/* Keep swfobject at the bottom */
/**
 * Update: swfobject is already a library included on SI - referencing this instance.
 */
CVP.swfobject = swfobject;


/* Code for immediate execution */
addBeforeUnLoadEvent(CVP.cleanup);

})();
(function(container) {

if (!container || !container.CVP)
{
	throw "CVP is a required dependency for the HTML5 player";
}

var debug = false;

var HTML5VERSION = "0.9.4";

var FREEWHEEL_JS_URL = "http://i.cdn.turner.com/xslo/cvp/ads/freewheel/js/AdManager.js";
var OMNITURE_JS_URL = "";

var Class = CVP.Class;


var undef = CVP.Utils.undef;
var nil = CVP.Utils.isNull;
var empty = CVP.Utils.empty;
var extend = CVP.Utils.extend;
var byId = CVP.Utils.byId;
var query = CVP.Utils.query;
var bind = CVP.Utils.bind;
var slice = CVP.Utils.slice;
var template = CVP.Utils.template;
var joinKeys = CVP.Utils.joinKeys;
var isFlagActive = CVP.Utils.isFlagActive;
var print = CVP.Utils.print;

var Event = CVP.Events.CustomEvent;
var CommandQueue = CVP.Utils.CommandQueue;
var Asset = CVP.Utils.Asset;

/**
 * Prints the logs.
 */
var log = function() {
	if (window.console
		&& window.console.log
		&& debug) {
		window.console.log(slice(arguments).join(" | "));
	}
};

var ConditionalTask = function(condition, success, interval) {
	this._interval = nil(interval) ? 10 : interval;
	this._maxTries = 500;

	this._condition = condition;
	this._success = success;

	this._tries = 0;

	this.conditionWrapper = bind(function() {
		var ret = this._condition();
		if (ret == true)
		{
			clearInterval(this._timer);
			this._success();
		}
		else if (this._tries > this._maxTries)
		{
			log("condition never met!");
			clearInterval(this._timer);
		}
		this._tries++;
	}, this);;

	this.start = function() {
		this._timer = setInterval(this.conditionWrapper, this._interval);
	};
};

var ConfigUtils = {
	stringReplace : function(str, entry, uriEncode) {
			var patterns = this.getReplacementPatterns(str);

			if (!empty(patterns)) {
			for (var i = 0; i < patterns.length; i++)
			{
				var pattern = patterns[i];
				var replaceStr = "";

				replaceStr = this.getReplacementText(pattern, entry);

				if (empty(replaceStr))
					replaceStr = "";
				else if (uriEncode)
					replaceStr = encodeURI(replaceStr);

				str = str.replace(pattern, replaceStr);
			}
			}

			return str;
	},

	getReplacementPatterns : function(str) {
		return(str.match(/[$][{][^}]*[}]/g));
	},

	getReplacementText : function(pattern, entry) {
			var replaceStr = "";

			switch (pattern)
			{
				case "${page.domain}":
					if (player)
						replaceStr = document.domain;
					break;

				case "${page.url}":
					replaceStr = document.location.href;
					break;

				case "${videoId}":
				case "${video.id}":
					if (entry)
						replaceStr = entry.getId();
					break;

				default:
					var nodeName = pattern.substr(2, pattern.length - 3);

					var array = nodeName.split('.');
					var objName = array[0];

					if (array.length > 1)
					{
						nodeName = nodeName.substr(objName.length + 1);

						switch (objName)
						{
							case "video":
								if (entry)
									replaceStr = XMLUtils.getNodeValue(entry._xmlEntry, nodeName);
							break;
							default:
								replaceStr = pattern;
							break;
						}
					}
					else
						replaceStr = pattern;
				break;
			}

			return replaceStr;
		}
};
var Ajax = {
	get : function(obj) {
		obj.type = "GET";
		this._request(obj);
	},
	getXml : function(obj) {
		obj.dataType = "xml";
		this.get(obj);
	},
	post : function(obj) {
		obj.type = "POST";
		this._request(obj);
	},

	_request : function(obj)
	{
		var request = new XMLHttpRequest();

		request.onreadystatechange = function()
		{
			if (request.readyState == 4)
			{
				if (request.status <= 200 && request.status < 400)
				{
					if (obj.success)
						obj.success(request.responseText);
				}
				else
				{
					if (obj.error)
						obj.error(request);
				}
				request = null;
			}
		}

		request.open(obj.type, obj.url, true);
		request.send(obj.type == "POST" ? obj.data : null);
	}
};

var Loader = Class.extend({
	init : function() {
		this.eLoaded = new Event("LoadedEvent");
		this.eLoadError = new Event("LoadErrorEvent");
	},

	load : function(url) {
		var self = this;

		var success = function(data) {
			log("Loader", "success:", url);
			self.eLoaded.dispatch(data);
		};

		var error = function(requestObj, textStatus, errorThrown) {
			log("Loader", "error:", url,"text:",textStatus);
			self.eLoadError.dispatch(requestObj, textStatus, errorThrown);
		};

		Ajax.get({
			url : url,
			success : success,
			error : error
		});
	}
});

var XMLLoader = Class.extend({
	init : function() {
		this._loader = new Loader();
		this._loader.eLoaded.addListener(this._onLoaded, this);
		this._loader.eLoadError.addListener(this._onLoadError, this);

		this.eLoaded = new Event();
		this.eLoadError = new Event();
	},

	load : function(url) {
		this._loader.load(url);
	},
	_onLoaded : function(xmlStr) {
		xmlStr = XMLUtils.clean(xmlStr);
		var xDoc = XMLUtils.createDoc(xmlStr);

		log("XMLLoader", "XMl loaded");
		this.eLoaded.dispatch(xDoc);
	},

	_onLoadError : function(requestObj, textStatus, errorThrown) {
		log("XMLParser","onLoadError:", textStatus);

		if (textStatus == "parsererror") {
			log("XMLParser", "ParseError...attempting to create an xml doc manually");
			var xmlStr = requestObj.responseText;

			xmlStr = XMLUtils.clean(xmlStr);

			var xDoc = XMLUtils.createDoc(xmlStr);
			if (xDoc)
				this.eLoaded.dispatch(xDoc);	//TODO after cleaning up ajax impl, clean this up
			else
				this.eLoadError.dispatch(requestObj, textStatus, errorThrown);
		}
	}
});
var XMLParser = Class.extend({
	init : function() {
		this._loader = new XMLLoader();
		this._loader.eLoaded.addListener(this.onLoaded, this);
		this._loader.eLoadError.addListener(this.onLoadError, this);
	},

	/**
	 * Load and parse the xml
	 * @param url The url of the xml to load and parse
	 */
	parse : function(url) {
		log("XMLParser", "Loading the xml to parse", url);
		this.load(url);
	},

	load : function(url) {
		this._loader.load(url);
	},
	onLoaded : function(xml) {
		log("XMLParser", "XMl loaded");
		this.parseXml(xml);
	},
	onLoadError : function(requestObj, textStatus, errorThrown) {
		log("XMLParser","onLoadError:", textStatus);
	},

	parseXml : function(xml) {
	}
});

var ContainerParser = XMLParser.extend({
	init : function() {
		this.eParseCompleted = new Event();
		this.eParseError = new Event();

		this._super();
	},

	parseXml : function(xml) {
		var self = this,
			docElement = xml.documentElement,
			contextName = _params.context || "",
			contexts = null,
			context = null,
			node = null
		;

		contexts = docElement.getElementsByTagName("context");

		for (var i = 0; i < contexts.length; i++)
		{
			if (XMLUtils.getAttribute(contexts[i],"name") == contextName)
			{
				context = contexts[i];
				break;
			}
		}

		if (context)
		{
			var players = context.getElementsByTagName("player");
			var playerName = XMLUtils.getAttribute(players[players.length - 1],"instance");

			if (empty(playerName))
				playerName = contextName;

			_containerInfo.playerInstance = playerName;
		}
		CVP.Utils.print(_containerInfo, "_containerInfo");

		this.eParseCompleted.dispatch();
	}
});

var ConfigParser = XMLParser.extend({
	init : function() {
		this.eParseCompleted = new Event();
		this.eParseError = new Event();

		this._super();
	},

	parseXml : function(xml) {
		var self = this,
			docElement = xml.documentElement,
			playerInstanceName = _containerInfo.playerInstance || "",
			player = null,
			node
		;

		var players = docElement.getElementsByTagName("player");
		while (players.length) {
			node = players[players.length - 1];

			if (XMLUtils.getAttribute(node,"name") == playerInstanceName)
			{
				player = node.cloneNode(true);
			}

			docElement.removeChild(node);
		}

		var process = function(xml, objToAssign) {
			if (nil(xml))
				return;

			var childNodes = xml.childNodes,
				xmlLength = childNodes.length,
				childNode,
				obj,
				i = 0
			;

			if (xmlLength == 0)
				return;

			do {
				childNode = childNodes[i];

				obj = self.findMapping(childNode.nodeName);
				if (!nil(obj))
				{

					self.parseAttributes(obj, childNode);
					if (childNode.childNodes.length)
					{
						process(childNode, obj);
					}
				}
				else if (childNode.nodeName == "param")
				{
					self.parseParams(objToAssign,
						XMLUtils.getAttribute(childNode, "name"),
						XMLUtils.getAttribute(childNode, "value")
					);
				}

				i++;
			} while(i < xmlLength);
		};

		process(docElement, _configInfo);

		if (!nil(player))
		{
			process(player, _configInfo);
		}

		CVP.Utils.print(_configInfo, "_configInfo");

		players = player = childNodes = childNode = null;
		this.eParseCompleted.dispatch();
	},

	/**
	 * Parse the param nodes from the config.
	 * @param obj - the object to assign the property to
	 * @param xml - the xml to parse
	 */
	parseParams : function(obj, name, value) {
		switch(name)
		{
				case "ad_api":
					obj.apiUrl = value;
					break;
				case "ad_man_root_url":
					obj.adManRootUrl = value;
					break;
				case "ad_server_root_url":
					obj.adServerRootUrl = value;
					break;
				case "ad_video_root_url":
					obj.adVideoRootUrl = value;
					break;
				case "ad_video_extension":
					obj.adVideoExtension = value;
					break;
				case "additional_video_segvars":
					obj.additionalVideoSegVars = value;
					break;
				case "additional_sync_segvars":
					obj.additionalSyncSegVars = value;
					break;
				case "ad_section":
					obj.adSection = value;
					break;
				case "ad_network_id":
					obj.adNetworkId = value;
					break;
				case "ad_video_network_id":
					obj.adVideoNetworkId = value;
					break;
				case "ad_video_asset_id":
					obj.adVideoAssetId = value;
					break;
				case "ad_player_profile":
					obj.adPlayerProfile = value;
					break;
				case "renderers_url":
					obj.renderersUrl = value;
					break;
				case "external_slots":
					obj.externalSlots = isFlagActive(value, obj.externalSlots);
					break;
				case "ad_live_content_duration":
					obj.liveDuration = value;
					break;

				default:
					obj[name] = value;
		}
	},

	parseAttributes : function(obj, node)
	{
		if (node.hasAttributes)
		{
			if (!obj.attr)
				obj.attr = {};
			XMLUtils.assignAttributes(obj.attr, node.attributes);
		}
	},

	findMapping : function(nodeName) {
		var obj = null;
		switch(nodeName)
		{
			case "ad_server":
				obj = _configInfo.ads;
				break;
		}
		return obj;
	}
});
var XMLUtils = {
	createDoc : function(xmlString) {
		if (undef(window.DOMParser))
		{
			this.createDoc = function(xmlString) {
				if (empty(xmlString)) return null;

				var xDoc = new ActiveXObject("MSXML2.DOMDocument");
   				xDoc.async = false;
    			xDoc.loadXML(xmlString);
				return xDoc;
			};
		}
		else
		{
			this.createDoc = function(xmlString) {
				if (empty(xmlString)) return null;

				var parser = new DOMParser();
    			var xDoc = parser.parseFromString(xmlString, "text/xml");
    			return xDoc;
			};
		}
		return this.createDoc(xmlString);
	},

	clean : function(xmlString) {
		xmlString = xmlString.replace(/\>\s*?\</g, "><");

		xmlString = xmlString.replace(/\t*/g, "");

		xmlString = xmlString.replace(/\n*/g, "");

		xmlString = xmlString.replace(/<!--(.*?)-->/g, "");

		xmlString = xmlString.replace(/&/g, "&amp;");

		while (xmlString.indexOf('xmlns') > -1) {
			var start = xmlString.indexOf('xmlns');
			var firstQuote = xmlString.indexOf('"',start);
			var endQuote = xmlString.indexOf('"',firstQuote+1);

			xmlString = xmlString.slice(0,start) + xmlString.slice(endQuote+1);
		}

		return xmlString;
	},

	getNodeValue : function(doc, nodeName) {
		if (doc)
		{
			if (!nodeName)
				return (!nil(doc.firstChild) ? doc.firstChild.nodeValue : null);

			var nodes = doc.getElementsByTagName(nodeName);
			if (nodes.length > 0)
				return nodes[0].firstChild.nodeValue;
		}
		return null;
	},

	getAttribute : function(node, attrName) {
		if (node
			&& node.attributes
			&& !empty(attrName))
		{
			var attr = node.attributes.getNamedItem(attrName);
			return attr ? attr.nodeValue : null;
		}
	},

	assignAttributes : function(obj, attributes)
	{
		for (var a in attributes)
		{
			obj[attributes[a].nodeName] = attributes[a].nodeValue;
		}
	},

	toString : function(xmlDoc) {
		if (undef(window.XMLSerializer))
		{
			this.toString = function(xmlDoc) {
				return xmlDoc.xml;
			};
		}
		else
		{
			this.toString = function(xmlDoc) {
				return new XMLSerializer().serializeToString(xmlDoc);
			};
		}
		return this.toString(xmlDoc);
	}
};
var DependencyMananger = Class.extend({
	init : function()
	{
		this._dependencies = [];
		this._currentDependency = null;

		this.eSuccess = new Event();				// All required dependencies loaded successfully
		this.eFailure = new Event();				// One or more required dependencies failed to load
		this.eDependencySuccess = new Event();		// A dependency loaded successfully
		this.eDependencyFailure = new Event();		// A dependency failed to load
	},

	addDependency : function(dependency)
	{
		dependency.setManager(this);
		this._dependencies.push(dependency);
	},

	load : function()
	{
		this._currentDependency = this._dependencies.shift();
		this._currentDependency.eSuccess.addListener(this._onDependencySuccess, this);
		this._currentDependency.eFailure.addListener(this._onDependencyFailure, this);

		var self = this;
		setTimeout(function() { self._currentDependency.load() }, 10);
	},

	_onDependencySuccess : function()
	{
		this.eDependencySuccess.dispatch(this._currentDependency.getDesc());
		this._next();
	},

	_onDependencyFailure : function()
	{
		this.eDependencyFailure.dispatch(this._currentDependency.getDesc());

		if (this._currentDependency.required)
		{
			this._onFailure(this._currentDependency.getDesc());
			return;
		}

		this._next();
	},

	_next : function()
	{
		if (this._dependencies.length)
			this.load();
		else
			this._onSuccess();
	},
	_onSuccess : function(desc)
	{
		this.eSuccess.dispatch(desc);
	},
	_onFailure : function(desc)
	{
		this.eFailure.dispatch(desc);
	}
});

var Dependency = Class.extend({
	init : function(assetUrl, required)
	{
		this._assetUrl = assetUrl;
		this.required = required;

		this._manager = null;

		this.eSuccess = new Event();
		this.eFailure = new Event();
	},

	load : function()
	{
		log("Dependency", "loading asset", this._assetUrl);
		var assetLoader = new Asset(this._assetUrl);
		assetLoader.eSuccess.addListener(this._success, this);
		assetLoader.eFailure.addListener(this._failure, this);
		assetLoader.load();
	},

	_success : function()
	{
		log("Dependency", "successfully loaded dependency", this._assetUrl);
		this.eSuccess.dispatch();
	},

	_failure : function()
	{
		log("Dependency", "failed to load dependency", this._assetUrl);
		this.eFailure.dispatch();
	},

	setManager : function(manager)
	{
		this._manager = manager;
	},

	getDesc : function()
	{
		return this._assetUrl;
	}
});

var ContainerDependency = Dependency.extend({
	init : function()
	{
		this._super.apply(this, arguments);
		this.required = true;

		this._parser = new ContainerParser();
		this._parser.eParseCompleted.addListener(this._onParseCompleted, this);
		this._parser.eParseError.addListener(this._onParseError, this);
	},

	load : function()
	{
		log("ContainerDependency", "loading xml", this._assetUrl);
		this._parser.parse(this._assetUrl);
	},

	_onParseCompleted : function()
	{
		this._success();
	},

	_onParseError : function()
	{
		this._failure();
	},

	getDesc : function()
	{
		return "ContainerDependency: " + this._assetUrl;
	}
});

var ConfigDependency = Dependency.extend({
	init : function()
	{
		this._super.apply(this, arguments);
		this.required = true;

		this._parser = new ConfigParser();
		this._parser.eParseCompleted.addListener(this._onParseCompleted, this);
		this._parser.eParseError.addListener(this._onParseError, this);
	},

	load : function()
	{
		this._parser.parse(this._assetUrl);
	},

	_onParseCompleted : function()
	{
		if (this._manager)
		{
			if (_configInfo.ads.attr.type.toLowerCase() == "freewheel")
			{
				log("ContainerDependency", "adding FW dependency");
				this._manager.addDependency(new Dependency(FREEWHEEL_JS_URL, true));
			}

			if (!empty(_configInfo.omniture.omniture_account))
			{
				log("ContainerDependency", "adding Omniture dependency");
			}
		}

		this._success();
	},

	_onParseError : function()
	{
		this._failure();
	},

	getDesc : function()
	{
		return "ConfigDependency: " + this._assetUrl;
	}
});

var CMS = Class.extend({
	init : function() {
		this._catalogDataURL = "";
		this._requestPendingQueue = [];
		this._videoCatalog = [];
		this._requests = {};

		this._loader = new XMLLoader();
		this._loader.eLoaded.addListener(this._onContentIdRequestComplete, this);
		this._loader.eLoadError.addListener(this._onContentIdRequestIOError, this);

		this.eRequestCompleted = new Event("CmsRequestCompletedEvent");
	},

	addContentId : function(contentId) {
		var entry = this.getContentId(contentId);

		if (nil(entry))
			this._requestPendingQueue.push(contentId);
		else {
			var index = contentId.split("|")[1];
                            contentId = contentId.split("|")[0];
			this._notifyListeners(contentId, contentId, index);
		}

		if (this._requestPendingQueue.length == 1)
			this._processNextRequest();
	},

	getContentId : function(contentId) {
		contentId = contentId.split("|")[0];

		var ct = this._videoCatalog.length;

		for (var i = 0; i < ct; i++)
		{
			var entry = this._videoCatalog[i];

			if (entry.getId() == contentId)
				return entry;
		}
		return null;
	},

	clear : function() {
		this._videoCatalog = [];
	},

	setDataUrl : function(url) {
		this._catalogDataURL = url;
	},

	_getRequestUrl : function(contentId) {
		var requestUrl;

		var start = this._catalogDataURL.substr(0).search(/\$\{/);
		if (start != -1)
		{
			var end = this._catalogDataURL.substr(start).search(/\}/);

			if (end != -1)
			{
				var pattern = this._catalogDataURL.substr(start, end + 1);
				requestUrl = this._catalogDataURL.replace(pattern, contentId);
			}
		}
		else
		{
			requestUrl = this._catalogDataURL + "/" + contentId + ".xml";
		}

		return requestUrl;
	},

	_createContentEntryFromRequestData : function(requestData, fileId) {
		try
		{
			return new ContentCatalogEntry(requestData);
		}
		catch(e)
		{
			alert(this._catalogDataURL + "/" + fileId + ".xml: " + e.message);
		}

		return null;
	},

	_processNextRequest : function() {
		if (this._requestPendingQueue.length > 0)
		{
			var contentId = this._requestPendingQueue[0].split("|")[0];
			this._requestVideoWithId(contentId);
		}
	},

	_requestVideoWithId : function(contentId) {
		var url = this._getRequestUrl(contentId);
		this._loader.load(url);
	},

	_onContentIdRequestComplete : function(data) {
		var request = this._requestPendingQueue[0].split("|");
		var contentId = request[0];
		var requestIndex = request[1];

		if (data != null)
		{
			var entry = this._createContentEntryFromRequestData(data, contentId);

			if (!entry)
			{
				this._notifyListeners(contentId, contentId, requestIndex, "No URLLoader");
			}
			else
			{
				entry.requestId = contentId;

				this._videoCatalog.push(entry);
				this._notifyListeners(entry.getId(), entry.requestId, requestIndex, "");
			}
		}
		else
		{
			this._notifyListeners(contentId, contentId, requestIndex, "No URLLoader");
		}

		this._requestPendingQueue.shift();
		this._processNextRequest();
	},

	_onContentIdRequestIOError : function() {
		var request = this._requestPendingQueue[0].split("|");
		var contentId = request[0];
		var requestIndex = request[1];


		this._notifyListeners(contentId, contentId, "IOError : " + event.text);

		this._requestPendingQueue.shift();
		this._processNextRequest();
	},

	_notifyListeners : function(contentId, requestId, index, errorMsg) {
		this.eRequestCompleted.dispatch(contentId, requestId, index, errorMsg);
	}
});
var ContentCatalogEntry = Class.extend({
	init : function(xml) {
		this._xmlEntry = xml.documentElement;
		this._requestId = null;

		this._name = XMLUtils.getNodeValue(this._xmlEntry, "slug");
		this._title = XMLUtils.getNodeValue(this._xmlEntry, "headline");
		this._category = XMLUtils.getNodeValue(this._xmlEntry, "category");
		this._trt = XMLUtils.getNodeValue(this._xmlEntry, "trt") * 1;

		var files = this._xmlEntry.getElementsByTagName("files");
		if (files.length)
		{
			files = files[0].childNodes;

			this._fileList = {};
			for (var f in files)
			{
				if (files[f].nodeType != 1) continue;

				var fKey = XMLUtils.getAttribute(files[f], "bitrate");
				var fFallback = XMLUtils.getAttribute(files[f], "fallback");
				var fValue = XMLUtils.getNodeValue(files[f]);
				var ext = empty(fValue) ? "" : fValue.substring(fValue.lastIndexOf(".") + 1);
				log("ContentCatalogEntry", fKey, fValue, ext);

				this._fileList[fKey] = {
					url : fValue,
					fallback : fFallback,
					ext : ext
				};
			}
		}
		else
		{
			log("ContentCatalogEntry", "No file entries found!");
		}

		var images = this._xmlEntry.getElementsByTagName("images");
		if (images.length)
		{
			images = images[0].childNodes;

			this._imageList = {};
			for (var image in images)
			{
				if (images[image].nodeType != 1) continue;

				var iWidth = XMLUtils.getAttribute(images[image], "width");
				var iHeight = XMLUtils.getAttribute(images[image], "height");

				var iValue = XMLUtils.getNodeValue(images[image]);
				log("ContentCatalogEntry", "images", iWidth, iHeight, iValue);

				var iKey = iWidth + "|" + iHeight;
				this._imageList[iKey] = {
					url : iValue,
					width : iWidth,
					height : iHeight
				};
			}
		}
	},

	getId : function()
	{
		var attr = XMLUtils.getAttribute(this._xmlEntry, "id");
		if (!empty(attr))
			return attr;
		else
			return this._requestId;
	},

	getName : function()
	{
		return this._name;
	},

	getTitle : function()
	{
		return this._title;
	},

	getCategory : function()
	{
		return this._category;
	},

	getTrt : function()
	{
		return this._trt;
	},

	getContentUrl : function(quality)
	{
		var url = null;
		var dbgFound = false;

		for (var bitrate in this._fileList)
		{
			if (bitrate == quality)
			{
				url = this._fileList[bitrate].url;
				if (url.indexOf("://") == -1)
					url = _configInfo.media_src + url;
				dbgFound = true;
				break;
			}
		}

		if (!dbgFound)
			log("Config XML specifies a " + quality + " bitrate entry, but there is no <file> node in video XML where bitrate attribute = " + quality + ".");
		else if (empty(url))
			log("text attribute is empty in the video XML for the <file> node whose quality is " + quality + ".");

		return url;
	},

	getContentUrlFromFallback : function(fallback) {
		var url = null;
		for (var bitrate in this._fileList) {
			if (!(empty(this._fileList[bitrate].fallback)) && fallback == this._fileList[bitrate].fallback) {
				url = this._fileList[bitrate].url;
				if (url.indexOf("://") == -1)
					url = _configInfo.media_src + url;
				break;
			}
		}
		return url;
	},

	getContentUrlFromType : function(ext)
	{
		var url = null;
		for (var bitrate in this._fileList)
		{
			if (ext == this._fileList[bitrate].ext)
			{
				url = this._fileList[bitrate].url;
				if (url.indexOf("://") == -1)
					url = _configInfo.media_src + url;
				break;
			}
		}
		return url;
	},

	getThumbnailUrl : function(width, height)
	{
		var url = null;
		var key = width + "|" + height;

		for (var k in this._imageList)
		{
			if (k == key)
			{
				url = this._imageList[k].url;
				break;
			}
		}
		return url;
	},

	getXML : function()
	{
		return this._xmlEntry;
	}
});

var BasePlayer = Class.extend({
	init : function(options) {
		this.options = extend({
			containerElement : '',
			elementId : '',
			autoplay : true,
			controls : true,
			width : 0,
			height : 0
		}, options || {});

		this.containerElement = byId(this.options.containerElement);

		this.elementId = this.options.elementId;
		if (empty(this.elementId))
		{
			log("Invalid element id...exiting");
			throw new "Invalid element id";
		}

		this.playerOptions = {};

		this.width = this.options.width;
		this.height = this.options.height;
		this.airplay = (!CVP.Browser.apple_mobile && (undef(_params.ios_airplay) || undef(_configInfo.ios_airplay))) ? "" : "x-webkit-airplay=\"allow\"";
		this.perVideoFallbacks = (undef(_params.perVideoFallbacks)) ? new Array() : _params.perVideoFallbacks;


		this.element = null;

		this.rendering = false;

		this.position = {
			top : null,
			right : null,
			bottom : null,
			left : null
		};

		this.eRendered = new Event();			// After the markup for the media element has been rendered
		this.eContentBegin = new Event();		// When play is called, before the ad preroll plays
		this.eContentPlay = new Event();		// After any prerolls, before the video starts playing
		this.eContentEnded = new Event();		// After the video has completed, before any postrolls have been played
		this.eContentCompleted = new Event();	// After any postrolls have been played
	},

	getMarkup : function() {
		return "";
	},

	render : function(containerElement) {
		log("Player", "render");
		if (!empty(containerElement))
			this.containerElement = byId(containerElement);

		if (nil(this.containerElement))
		{
			log("Container element could not be found...cannot render...exiting");
			throw new "Container could not be found";
		}

		var markup = this.getMarkup();
		this.rendering = true;
		this.containerElement.innerHTML = markup;

		var self = this;
		new ConditionalTask(
			function() {
				if (!nil(byId(self.elementId)))
					return true;
			},
			function () {
				self.rendering = false;
				self.element = byId(self.elementId);
				self.fireRendered();
			}
		).start();
	},

	rendered : function() {
		return this.element && this.element.parentNode==this.containerElement;
	},

	show : function() {
		if (this.element)
		{
			if (this.position.left)
				this.element.style.left = this.position.left
		}
	},
	hide : function() {
		if (this.element)
		{
			this.position.left = this.element.style.left;
			this.element.style.left = "-5000px";
		}
	},

	addPlayerListeners : function() {
	},
	removePlayerListeners : function() {
	},

	fireRendered : function() {
		this.eRendered.dispatch("video");
	},
	fireBegin : function() {
		this.eContentBegin.dispatch(this._catalogEntry.getId());
	},
	firePlay : function() {
		this.eContentPlay.dispatch();
	},
	fireEnded : function() {
		this.eContentEnded.dispatch();
	},
	fireCompleted : function() {
		this.eContentCompleted.dispatch();
	}
});

var VideoPlayer = BasePlayer.extend({
	init : function(options) {
		this._super(options);

		this.playerOptions["controls"] = this.options.controls;
		this.playerOptions["autoplay"] = this.options.autostart;

		this._supportedFileTypes = this._determineSupportedFileTypes();

		this._firePlay = false;
		this._addedListeners = false;

		this._onLoadedMetaDataBind = bind(this._onLoadedMetaData, this);
		this._onContentPlayBind = bind(this._onContentPlay, this);
		this._onContentEndedBind = bind(this._onContentEnded, this);
	},

	getMarkup : function() {
		return template("<video id=\"{0}\" width={1} height={2} controls {3}></video>", this.elementId, this.width, this.height, this.airplay);
	},

	play : function(catalogEntry) {
		if (CVP.Browser.apple_mobile)
		{
			this.play = function(catalogEntry)
			{
				this._catalogEntry = catalogEntry;
				var url = this._getFileUrl(catalogEntry);
				this.element.src = url;

				this._setOptions();
				this._setThumbnail();
				this.element.load();

				this.element.play();

				this._firePlay = true;
			}
		}
		else
		{
			this.play = function(catalogEntry)
			{
				this._catalogEntry = catalogEntry;
				var url = this._getFileUrl(catalogEntry);
				this.element.src = url;

				if (!this.playerOptions.autoplay)
				{
					this._setThumbnail();
				}
				this.element.load();
			}
		}
		this.play(catalogEntry);
	},

	pause : function()
	{
		this.element.pause();
	},

	resume : function()
	{
		if (this.element.paused)
			this.element.play();
	},

	setVolume : function(v)
	{
		this.element.volume = v;
	},

	getVolume : function()
	{
		return this.element.volume;
	},

	mute : function()
	{
		this.element.muted = true;
	},

	unmute : function()
	{
		this.element.muted = false;
	},

	_setOptions : function()
	{
		for (var option in this.playerOptions)
		{
			this.element[option] = this.playerOptions[option];
		}
	},

	_setThumbnail : function()
	{
		var image = this._catalogEntry.getThumbnailUrl(this.width, this.height);
		log("thumb", image);
		if (image)
		{
			this.element.poster = image;
		}
	},

	_onLoadedMetaData : function()
	{
		if (CVP.Browser.apple_mobile)
		{
			this._onLoadedMetaData = function()
			{
				log("VideoPlayer", "_onLoadedMetaData");
			}
		}
		else
		{
			this._onLoadedMetaData = function()
			{
				log("VideoPlayer", "_onLoadedMetaData");
				this._onLoaded();
			}
		}
		this._onLoadedMetaData();
	},

	_onLoaded : function()
	{
		this._setOptions();
		this._firePlay = true;
		this.element.play();
	},

	_onReadyStateChange : function()
	{
		log("VideoPlayer", "_onReadyStateChange");
	},

	_onContentPlay : function()
	{
		log("VideoPlayer", "_onContentPlay");
		if (this._firePlay)
		{
			this.firePlay();
			this._firePlay = false;
		}
	},

	_onContentPlaying : function()
	{
		log("VideoPlayer", "_onContentPlaying");
	},

	_onContentPaused : function()
	{
		log("VideoPlayer", "_onContentPaused");
	},

	_onContentTimeUpdate : function()
	{
	},

	_onContentEnded : function()
	{
		log("VideoPlayer", "_onContentEnded");
		this.fireEnded();
	},

	addPlayerListeners : function() {
		if (this.element
			&& !this._addedListeners)
		{
			log("VideoPlayer", "addPlayerListeners");
			this.element.addEventListener("loadedmetadata", this._onLoadedMetaDataBind, false);
			this.element.addEventListener("play", this._onContentPlayBind, false);
			this.element.addEventListener("ended", this._onContentEndedBind, false);

			this.element.addEventListener("readystatechange", this._onReadyStateChange, false);
			this.element.addEventListener("playing", this._onContentPlaying, false);
			this.element.addEventListener("pause", this._onContentPaused, false);
			this.element.addEventListener("timeupdate", this._onContentTimeUpdate, false);

			this._addedListeners = true;
		}
	},
	removePlayerListeners : function() {
		if (this.element
			&& this._addedListeners)
		{
			log("VideoPlayer", "removePlayerListeners");
			this.element.removeEventListener("loadedmetadata", this._onLoadedMetaDataBind, false);
			this.element.removeEventListener("play", this._onContentPlayBind, false);
			this.element.removeEventListener("ended", this._onContentEndedBind, false);

			this.element.removeEventListener("readystatechange", this._onReadyStateChange, false);
			this.element.removeEventListener("playing", this._onContentPlaying, false);
			this.element.removeEventListener("pause", this._onContentPaused, false);
			this.element.removeEventListener("timeupdate", this._onContentTimeUpdate, false);

			this._addedListeners = false;
		}
	},

	_getFileUrl : function(catalogEntry)
	{
		var url = this._getFileByParameterFallback(catalogEntry);
		if (url == null)
			url = this._getFileByFallback(catalogEntry)
		if (url == null) {
			var url = catalogEntry.getContentUrl(_configInfo.low_bitrate);
			if (!this._isFileSupported(url))
			{
				log("VideoPlayer", "File is not supported!", url);
				log("VideoPlayer", "Attempting to find a compatible file");
				url = this._getFileBySupportedType(catalogEntry);
				if (empty(url))
					url = this._getFileByConfigFallbackParam(catalogEntry);
				log("VideoPlayer", "Found:", url);
			}
		} else {
			log("VideoPlayer", "Fallback file found", url);
		}
		return url;
	},

	_getFileByParameterFallback : function(catalogEntry) {
		var foundit = -1;
		for (var i = 0; i < this.perVideoFallbacks.length; i++) {
			var dvf = this.perVideoFallbacks[i];
			var criteria = ConfigUtils.stringReplace(dvf.criteria, catalogEntry, false);
			if (dvf.evaluate(criteria)) {
				return ConfigUtils.stringReplace(dvf.filter, catalogEntry, false);
			}
		}
		return null;
	},

	_getFileByConfigFallbackParam : function(catalogEntry) {
		var str = _configInfo.fallback_filename_iOS;
		if (empty(str))
			return str;
		else
			str = ConfigUtils.stringReplace(str, catalogEntry, false);
		return str;
	},

	_getFileByFallback : function(catalogEntry) {
		if (CVP.Browser.apple_mobile) {
			return catalogEntry.getContentUrlFromFallback("iOS");
		}
	},

	_getFileBySupportedType : function(catalogEntry)
	{
		var url = null;
		var len = this._supportedFileTypes.length;
		for (var i = 0; i < len; i++)
		{
			url = catalogEntry.getContentUrlFromType(this._supportedFileTypes[i]);
		}
		return url;
	},

	_isFileSupported : function(url)
	{
		if (!empty(url))
		{
			var ext = url.indexOf(".") > -1 ? url.substring(url.lastIndexOf(".") + 1) : url;
			var len = this._supportedFileTypes.length;
			for (var i = 0; i < len; i++)
			{
				if (ext == this._supportedFileTypes[i])
				{
					return true;
				}
			}
		}
		return false;
	},

	_determineSupportedFileTypes : function()
	{
		if (CVP.Browser.apple_mobile)
		{
			return ["m3u8", "mp4"]
		}
		else
		{
			return ["mp4"];
		}
	}
});
var PlayerController = Class.extend({
	init : function()
	{
		this._commandQ = new CommandQueue();;

		this._videoPlayer = new VideoPlayer({
			containerElement : "player_container",
			elementId : "videoPlayer",
			width : _params.width,
			height : _params.height,
			controls : true,
			autostart : _params.autostart
		});

		this._videoPlayer.eRendered.addListener(this._onRendered, this);
		this._videoPlayer.eContentPlay.addListener(this._onContentPlay, this);
		this._videoPlayer.eContentEnded.addListener(this._onContentEnded, this);

		this._adProxy = new AdServerProxy();
		this._adProxy.eAdStarted.addListener(this._onAdStarted, this);
		this._adProxy.eAdEnded.addListener(this._onAdEnded, this);
		this._adProxy.eAdError.addListener(this._onAdError, this);

		this._contentQueue = [];

		this.eRendered = new Event();
		this.eContentBegin = new Event();
		this.eContentPlay = new Event();
		this.eContentCompleted = new Event();

		this.eAdStarted = new Event();
		this.eAdFinished = new Event();
		this.eAdError = new Event();

	},

	render : function(containerElement)
	{
		this._adProxy.setVideoDisplayBase(containerElement);
		this._videoPlayer.render(containerElement)
	},

	_onRendered : function(type)
	{
		log("_onRendered", type);

		this._commandQ.execute();
		this.eRendered.dispatch();
	},

	play : function(catalogEntry) {
		log("PlayerController", "play", catalogEntry.getId());
		this._catalogEntry = catalogEntry;

		if (!this._videoPlayer.rendered())
		{
			this._commandQ.push(this.play, this, arguments);
			return;
		}

		this._onContentBegin();
		if (this._adProxy.enabled)
			this._adProxy.loadAds(catalogEntry);
		else
			this._playContent();
	},

	_playContent : function()
	{
		log("PlayerController", "_playContent");
		this._videoPlayer.addPlayerListeners();
		this._videoPlayer.play(this._catalogEntry);
	},

	queue : function(catalogEntry)
	{
		log("PlayerController", "queue", catalogEntry.getId());
		this._contentQueue.push(catalogEntry);
	},

	emptyQueue : function()
	{
		this._contentQueue = [];
	},

	pause : function()
	{
		this._videoPlayer.pause();
	},

	resume : function()
	{
		this._videoPlayer.resume();
	},

	setVolume : function(v)
	{
		this._videoPlayer.setVolume(v);
	},

	getVolume : function()
	{
		return this._videoPlayer.getVolume();
	},

	mute : function()
	{
		this._videoPlayer.mute();
	},

	unmute : function()
	{
		this._videoPlayer.unmute();
	},

	_onContentBegin : function()
	{
		log("PlayerController", "_onContentBegin");
		this.eContentBegin.dispatch(this._catalogEntry.getId());
	},

	_onContentPlay : function()
	{
		log("PlayerController", "_onContentPlay");
		this.eContentPlay.dispatch(this._catalogEntry.getId());
	},

	_onContentEnded : function()
	{
		log("PlayerController", "_onContentEnded");

		if (this._adProxy.enabled)
			this._adProxy.playPostroll();
		else
			this._onContentCompleted();
	},

	_onContentCompleted : function()
	{
		log("PlayerController", "_onContentCompleted");
		this.eContentCompleted.dispatch(this._catalogEntry.getId());
		if (this._contentQueue.length)
			this.play(this._contentQueue.shift());
	},

	_onAdStarted : function(e)
	{
		log("PlayerController", "_onAdStarted");
		this.eAdStarted.dispatch();
		this._videoPlayer.removePlayerListeners();
	},
	_onAdEnded : function(e)
	{
		timePositionClass = e && e.timePositionClass ? e.timePositionClass : null;

		log("PlayerController", "_onAdEnded", timePositionClass);

		this.eAdFinished.dispatch();
		if (timePositionClass == AdServerProxy.PREROLL
			|| this._adProxy.currentAdType == AdServerProxy.PREROLL)
			this._playContent();
		else
			this._onContentCompleted();
	},
	_onAdError : function(e)
	{
		this.eAdError.dispatch();
	}
});
var AdServerProxy = Class.extend({
	init : function()
	{
		this._adServerInfo = _configInfo.ads;

		this._freewheel = null;
		if (!undef(window.tv) && window.tv.freewheel)
		{
			if (!AdServerProxy.initialized)
			{
				AdServerProxy.PREROLL = tv.freewheel.SDK.TIME_POSITION_CLASS_PREROLL;
				AdServerProxy.POSTROLL = tv.freewheel.SDK.TIME_POSITION_CLASS_POSTROLL;
				AdServerProxy.initialized = true;
			}

		}
		else
		{
			this.enabled = false;
		}

		this.currentAdType = null;
	   	this._adSection = this.getConfigProperty("ad_section");

	   	this.eAdStarted = new Event();
	   	this.eAdEnded = new Event();
	   	this.eAdError = new Event();
	},

	setVideoDisplayBase : function(videoDisplayBase)
	{
		if (!undef(window.tv) && window.tv.freewheel)
		{
			this.displayBase = videoDisplayBase;
			this.enabled = true;
		}
	},

	loadAds : function(catalogEntry)
	{
		this._freewheel = new tv.freewheel.SDK.AdManager();

  	var serverUrl = this.getConfigProperty("ad_server_root_url") + "/ad/g/1?nw=" + this.getConfigProperty("ad_network_id") +
			"&prof=" + this.getConfigProperty("ad_network_id") + ":" + this.getConfigProperty("ad_player_profile") + "&flag=+sltp+exvt+slcb+unka+unks;";

		this._freewheel.setServerURL(serverUrl);
		this._freewheel.registerVideoDisplayBase(this.displayBase);

		var duration = catalogEntry.getTrt();

		var adId = "";
		if (empty(this._adServerInfo.adVideoAssetId))
			adId = catalogEntry.getId();
		else
			adId = ConfigUtils.stringReplace(this._adServerInfo.adVideoAssetId, catalogEntry, false);

		this._freewheel.setVideoAsset(adId, duration);

    	this._freewheel.setSiteSection(this._adSection);
     	this._freewheel.submitRequest(bind(this.onRequestCompleted, this), 2000);
	},

	onRequestCompleted : function(e)
	{
		log("AdServerProxy", "onRequestCompleted");
		this.currentAdType = AdServerProxy.PREROLL;
	    this._startAd(AdServerProxy.PREROLL, bind(this.onPrerollCompleted, this), e);
	},

	onPrerollCompleted : function(e)
	{
		log("AdServerProxy", "onPrerollCompleted");
		this._adEnded(e);
	},

	playPostroll : function()
	{
		this.currentAdType = AdServerProxy.POSTROLL;
		this._startAd(AdServerProxy.POSTROLL, bind(this.onPostrollCompleted, this));
	},

	onPostrollCompleted : function(e)
	{
		log("AdServerProxy", "onPostrollCompleted");
		this._adEnded(e);
	},

	_startAd : function(slot, cb, e)
	{
		 this.eAdStarted.dispatch(e);
		 this._freewheel.playSlots(slot, cb);
	},

	_adEnded : function(e)
	{
		this.eAdEnded.dispatch(e);
		this._freewheel.dispose();
	},

	onAdPlayHead : function(playhead, duration)
	{

	},

	getConfigProperty : function(key)
	{
		var value = null;
		var required = false;
		switch (key)
		{
			case 'ad_api':
				value = this._adServerInfo.apiUrl;
				required = true;
				break;
			case 'ad_server_root_url':
				value = this._adServerInfo.adServerRootUrl;
				required = true;
				break;
			case 'ad_network_id':
				value = this._adServerInfo.adNetworkId;
				required = true;
				break;
			case 'ad_video_network_id':
				value = this._adServerInfo.adVideoNetworkId;
				required = true;
				break;
			case 'ad_video_asset_id':
				value = this._adServerInfo.adVideoAssetId;
				required = true;
				break;
			case 'ad_section':
				value = this._adServerInfo.adSection;
				required = true;
				break;
			case 'ad_player_profile':
				value = this._adServerInfo.adPlayerProfile;
				required = true;
				break;
			case 'renderers_url':
				value = this._adServerInfo.renderersUrl;
				required = false;
				break;
			case 'sensitive_fallback_id':
				value = this._adServerInfo.sensitiveFallbackId;
				required = false;
				break;
			case 'ad_live_content_duration':
				value = this._adServerInfo.liveDuration;
				required = false;
				break;
		}

		if (empty(value))
		{
			if (required)
				log("the following required ad server config value is missing:", key);
			else
				log("the following optional ad server config value is missing:", key);
		}

		return value;
	}
});
AdServerProxy.PREROLL = null;
AdServerProxy.POSTROLL = null;
var MainController = {
		init : function(options)
		{
		_params = this._options = options;
		_params.context =_params.flashVars && _params.flashVars.context;
		_params.contentId = _params.flashVars && _params.flashVars.contentId;
		_params.autoplay = _params.flashVars && isFlagActive(_params.flashVars.autostart);
		_params.containerUrl = _params.flashVars && _params.flashVars.containerUrl;
		_params.configUrl = _params.flashVars && _params.flashVars.configUrl;

		this._bootStrapper = new DependencyMananger();
		this._bootStrapper.addDependency(new ContainerDependency(this._options.containerUrl), true);
		this._bootStrapper.addDependency(new ConfigDependency(this._options.configUrl), true);

		this._bootStrapper.eSuccess.addListener(this._bootStrapSuccess, this);
		this._bootStrapper.eFailure.addListener(this._bootStrapFailure, this);
		this._bootStrapper.load();

		this.ePlayerLoaded = new Event();
		this.ePlayerRendered =  new Event();
		this.eContentBegin = new Event();
		this.eContentPlay =  new Event();
		this.eContentCompleted =  new Event();

		this.eAdStarted = new Event();
		this.eAdFinished = new Event();
		this.eAdError = new Event();
	},

	/**
	 * At this point, the following should true:
	 * - the container is loaded and parsed
	 * - the config is loaded and parsed
	 * - any other initially required dependencies are loaded
	 * 		i.e., FW, Omniture, UI-related tools, etc..
	 */
	_bootStrapSuccess : function()
	{
		log("MainController", "_bootStrapSuccess");

		this._playerController = new PlayerController();
		this._playerController.eRendered.addListener(this._onRendered, this);
		this._playerController.eContentBegin.addListener(this._onContentBegin, this);
		this._playerController.eContentPlay.addListener(this._onContentPlay, this);
		this._playerController.eContentCompleted.addListener(this._onContentCompleted, this);

		this._playerController.eAdStarted.addListener(this._onAdStarted, this);
		this._playerController.eAdFinished.addListener(this._onAdFinished, this);
		this._playerController.eAdError.addListener(this._onAdError, this);

		this._cms = new CMS();
		this._cms.setDataUrl(_configInfo.data_src);
		this._cms.eRequestCompleted.addListener(this._onCmsRequestCompleted, this);

		this._loadingEntryQueue = {};

		this.ePlayerLoaded.dispatch();
	},

	/**
	 * Catastraphic failure, some required dependencies were not loaded
	 * Send an error event back to the page
	 */
	_bootStrapFailure : function()
	{
		log("MainController", "_bootStrapFailure");
	},

	render : function(containerElement)
	{
		this._playerController.render(containerElement);
	},

	_onRendered : function()
	{
		if (!nil(_params.contentId))
		{
			this.playContentWithId(_params.contentId);
		}

		this.ePlayerRendered.dispatch();
	},

	playContentWithId : function(id, options)
	{
		log("MainController", "playContentWithId", id);
		var index = this._getNextIndexForId(id);
		var key = id + "|" + index;
		log("MainController", "playContentWithId", "key", key);
		this._loadingEntryQueue[key] = {play: true, additionalParams: options};
		this._cms.addContentId(key, options);
	},

	queueContentWithId : function(id, options)
	{
		log("MainController", "queueContentWithId", id);
		var index = this._getNextIndexForId(id);
		var key = id + "|" + index;
		log("MainController", "queueContentWithId", "key", key);
		this._loadingEntryQueue[key] = {play: false, additionalParams: options};
		this._cms.addContentId(key, options);
	},

	pause : function()
	{
		this._playerController.pause();
	},

	resume : function()
	{
		this._playerController.resume();
	},

	setVolume : function(v)
	{
		this._playerController.setVolume(v);
	},

	getVolume : function()
	{
		return this._playerController.getVolume();
	},

	mute : function()
	{
		this._playerController.mute();
	},

	unmute : function()
	{
		this._playerController.unmute();
	},

	getContentEntry:function(id)
	{
		var catalogEntry = this._cms.getContentId(id);
		return CVP.Utils.JsonConverter.encodeXmlObject(catalogEntry.getXML());
	},

	_onContentBegin : function()
	{
		this.eContentBegin.dispatch(arguments[0]);
	},

	_onContentPlay : function()
	{
		this.eContentPlay.dispatch(arguments[0]);
	},

	_onContentCompleted : function()
	{
		this.eContentCompleted.dispatch(arguments[0]);
	},

	_onAdStarted : function()
	{
		this.eAdStarted.dispatch();
	},

	_onAdFinished : function()
	{
		this.eAdFinished.dispatch();
	},

	_onAdError : function()
	{
		this.eAdError.dispatch();
	},

	_onCmsRequestCompleted : function(contentId, requestId, index, errorMsg)
	{
		log("_onCmsRequestCompleted", contentId, requestId, index, errorMsg);

		var key = requestId + "|" + index;
		var catalogEntry = this._cms.getContentId((contentId + "|" + index));

		if (this._loadingEntryQueue[key] != null)
		{
			log("onCmsRequestCompleted", contentId, this._loadingEntryQueue[key].play);
			if (this._loadingEntryQueue[key].play)
			{
				this._playerController.emptyQueue();
				this._playerController.play(catalogEntry, this._loadingEntryQueue[key].additionalParams);
			}
			else
			{
				this._playerController.queue(catalogEntry, this._loadingEntryQueue[key].additionalParams);
			}

			delete this._loadingEntryQueue[key];
		}
	},

	_getNextIndexForId : function(contentId)
	{
		var index = 0;
		for (var p in this._loadingEntryQueue)
		{
			var q = p.split("|");
				if (q[0] == contentId
					&& q[1] >= index)
				{
					index = q[1] + 1;
				}
			}
			return index;
		}
};
/**
 * A CVP wrapper for html5.
 * @name HTML5Player
 * @class A CVP wrapper for html5.
 * Here is where the player is created and its behaviors are defined.
 */
container.CVP.Players._HTML5Player = Class.extend({

	/**
	 * Initializes the player by registering its event
	 * listeners.
	 * @param {Object} options Additional optional parameters.
	 * @memberOf HTML5Player
	 */
	init : function(options)
	{
		MainController.init(options);

		MainController.ePlayerLoaded.addListener(this._onPlayerLoaded, this);
		MainController.ePlayerRendered.addListener(this._onPlayerRendered, this);
		MainController.eContentBegin.addListener(this._onContentBegin, this);
		MainController.eContentPlay.addListener(this._onContentPlay, this);
		MainController.eContentCompleted.addListener(this._onContentCompleted, this);

		MainController.eAdStarted.addListener(this._onAdStarted, this);
		MainController.eAdFinished.addListener(this._onAdFinished, this);
		MainController.eAdError.addListener(this._onAdError, this);

		this.ePlayerLoaded = new Event();
		this.ePlayerReady = new Event();
		this.eContentBegin = new Event();
		this.eContentPlay = new Event();
		this.eContentCompleted = new Event();

		this.eAdStarted = new Event();
		this.eAdFinished = new Event();
		this.eAdError = new Event();
	},

	/**
	 * Renders a player element to the page.
	 * @param {Object} containerElement The object to render.
	 * @memberOf HTML5Player
	 */
	render : function(containerElement)
	{
		MainController.render(containerElement);
	},

	/**
	 * Plays the content based on it's id.
	 * @param {String} id The content's unique string identifier.
	 * @param {Object} options Additional optional parameters.
	 * @memberOf HTML5Player
	 */
	play : function(id, options)
	{
		MainController.playContentWithId(id, options);
	},

	/**
	 * Adds the content to the queue.
	 * @param {String} id The content's unique string identifier.
	 * @param {Object} options Additional optional parameters.
	 * @memberOf HTML5Player
	 */
	queue : function(id, options)
	{
		MainController.queueContentWithId(id, options);
	},

	/**
	 * Pauses the current content.
	 * @memberOf HTML5Player
	 */
	pause : function()
	{
		MainController.pause();
	},

	/**
	 * Resumes the current content from pause.
	 * @memberOf HTML5Player
	 */
	resume : function()
	{
		MainController.resume();
	},

	/**
	 * Set the current content's volume.
	 * @param {float} v The value to set the volume to.
	 * @memberOf HTML5Player
	 */
	setVolume : function(v)
	{
		MainController.setVolume(v);
	},

	/**
	 * Returns the current content's volume.
	 * @returns The current volume.
	 * @type float
	 * @memberOf HTML5Player
	 */
	getVolume : function()
	{
		return MainController.getVolume();
	},

	/**
	 * Mutes the current content's volume.
	 * @memberOf HTML5Player
	 */
	mute : function()
	{
		MainController.mute();
	},

	/**
	 * Un-mutes the current content's volume.
	 * @memberOf HTML5Player
	 */
	unmute : function()
	{
		MainController.unmute();
	},

	/**
	 * Retrieve's the current content entry based on the
	 * provided id.
	 * @param {String} id The content's unique identifier.
	 * @returns The content's entry.
	 * @type Object
	 * @memberOf HTML5Player
	 */
	getContentEntry:function(id)
	{
		return MainController.getContentEntry(id);
	},

	_onPlayerLoaded : function()
	{
		this.ePlayerLoaded.dispatch();
	},

	_onPlayerRendered : function()
	{
		this.ePlayerReady.dispatch();
	},

	_onContentBegin : function()
	{
		this.eContentBegin.dispatch(arguments[0]);
	},

	_onContentPlay : function()
	{
		this.eContentPlay.dispatch(arguments[0]);
	},

	_onContentCompleted : function()
	{
		this.eContentCompleted.dispatch(arguments[0]);
	},

	_onAdStarted : function()
	{
		this.eAdStarted.dispatch();
	},

	_onAdFinished : function()
	{
		this.eAdFinished.dispatch();
	},

	_onAdError : function()
	{
		this.eAdError.dispatch();
	}
});

var _containerInfo = {

};

var _configInfo = {
	ads : {
		attr : {
			type : "NONE"
		}
	},
	omniture : {},
	share : {},
	embed : {}
};

})(window);

						
					

	
	
	
	
				
	
				
	
				
	
				
	
				
	
				
	
				
	
				
	
				
	
				
	
				
	
				
	
				
	
				
	
				
	
				
	
				
	
	
	
		
			
			
			
				
				
			
			
			
			
			
			
				
					
						
					
			
			
						
				
					
				
			
			
				
					
				
				
				
				
				
				
					
				
				
				
					
					
						
														
						
						
						
											
				
				
document.writeln("<style>#sivideo_content { height:162px;padding:8px 7px; } #sivideo_iframe H4 { display:block;font-size:12px;height:auto; } #sivideo_iframe P { display:block;font-size:12px;line-height:16px;margin:0; }</style>");
document.writeln("<div id=\"sivideo_iframe\" class=\"box_outer clearfix module\">");
document.writeln("<div class=\"box_top clearfix\"><span class=\"box_corner_tl\"></span><span class=\"box_corner_tr\"></span></div>");
document.writeln("<div class=\"box_inner clearfix\"><h3><a href=\"http://sportsillustrated.cnn.com/video\" title=\"SI Video\">Sports Illustrated Video</a></h3>");
document.writeln("<div id=\"sivideo_content\"><div id=\"cvpPlayerArea\"></div></div>");
document.writeln("<h4><div id=\"cvpHeadline\">The Press: Long-term affect of losing a big game</div></h4>");
document.writeln("<p><span id=\"cvpBlurb\">SI.com's Jon Wertheim, Mark Mravic and Maggie Gray discuss whether the negative effects of losing the big game are greather than the positive effects of winning it.</span></p>");
document.writeln("</div>");
document.writeln("<div class=\"box_bottom clearfix\"><span class=\"box_corner_bl\"></span><span class=\"box_corner_br\"></span></div>");
document.writeln("</div>");

var cvpCurrentId = "si_video/2012/02/09/the_press_losing_effects";
var cvpQed = false;
		
	
	
var cvpPlaylist = [
	
	
		
			
			
			
			
				
				
						
			
			
				
					
				
				
			
			
			
				
			
			
			
				
				
					
													
					
					
					
										
			
			
			["nhl/2012/02/12/021112.nhl-highlights.was.nyr", "Callahan stays hot as Rangers slip past Capitals"]
		
	
		
			
			
			
			
				
				
						
			
			
			
			
				
			
			
			
				
				
					
													
					
					
					
										
			
			, 
			["ncaab.video/2012/02/11/021112.cbb_michst_ohiost", "No. 12 Michigan State overpowers No. 3 Ohio St."]
		
	
		
			
			
			
			
				
				
						
			
			
			
			
				
			
			
			
				
				
					
													
					
					
					
										
			
			, 
			["ncaab.video/2012/02/11/021112.SI_CBB_KENT_VANDY", "No. 1 UK survives Vanderbilt's upset bid"]
		
	
		
			
			
			
			
				
				
						
			
			
			
			
				
			
			
			
				
				
					
													
					
					
					
										
			
			, 
			["ncaab.video/2012/02/11/021112.CBB_OKST_KANSAS", "Withey, Robinson lead Kansas' rout of Okie State"]
		
	
		
			
			
			
			
				
				
						
			
			
				
					
				
				
			
			
			
				
			
			
			
				
				
					
													
					
					
					
										
			
			, 
			["ncaab.video/2012/02/11/021112.CBB_BU_MIZ", "No. 4 Mizzou makes it a sweep of No. 6 Baylor"]
		
	
		
			
			
			
			
				
				
						
			
			
			
			
				
			
			
			
				
				
					
													
					
					
					
										
			
			, 
			["si_video/2012/02/09/the_press_allstar_games", "The Press: Are All-Star games still relevant?"]
		
	
		
			
			
			
			
				
				
						
			
			
			
			
				
			
			
			
				
				
					
													
					
					
					
										
			
			, 
			["nba/2012/02/10/021012.pablo_torre_jeremy_lin", "Pablo Torre: How Lin is dealing with new stardom"]
		
	
		
			
			
			
			
				
				
						
			
			
			
			
				
			
			
			
				
				
					
													
					
					
					
										
			
			, 
			["nhl/2012/02/10/021012.dater_contender_pretender", "Adrian Dater: NHL's contenders and pretenders"]
		
	
		
			
			
			
			
				
				
						
			
			
				
				
			
			
			
				
			
			
			
				
				
					
													
					
					
					
										
			
			, 
			["nba/2012/02/12/0021100404_nyk_min_short_recap", "Lin leads Knicks to fifth consecutive victory"]
		
	
		
			
			
			
			
				
				
						
			
			
			
			
				
			
			
			
				
				
					
													
					
					
					
										
			
			, 
			["nfl/2012/02/09/020912.btm_crisphil_hbo", "Which team should appear on 'Hard Knocks' next?"]
		
	
		
			
			
			
			
				
				
						
			
			
			
			
				
			
			
			
				
				
					
													
					
					
					
										
			
			, 
			["ncaab.video/2012/02/09/020912.btm_anthony_conf_rank", "Greg Anthony: ACC not the best hoops conference"]
		
	
		
			
			
			
			
				
				
						
			
			
			
			
				
			
			
			
				
				
					
													
					
					
					
										
			
			, 
			["nfl/2012/02/09/020912.btm_crisphil_probowl", "Should the NFL's eliminate the Pro Bowl?"]
		
	
		
			
			
			
			
				
				
						
			
			
				
				
			
			
			
				
			
			
			
				
				
					
													
					
					
					
										
			
			, 
			["nfl/2012/02/08/superbowl_photogs", "SI's inside look: Photographing the Super Bowl"]
		
	
		
			
			
			
			
				
				
						
			
			
			
			
				
			
			
			
				
				
					
													
					
					
					
										
			
			, 
			["nba/2012/02/08/mccallum_nba_veterans", "Jack McCallum: NBA vets stealing the spotlight"]
		
	
		
			
			
			
			
				
				
						
			
			
			
			
				
			
			
			
				
				
					
													
					
					
					
										
			
			, 
			["ncaaf_video/2012/02/07/020712.btm_danielson_urban", "Gary Danielson: Big Ten has to adapt to Meyer"]
		
	
		
			
			
			
			
				
				
						
			
			
			
			
				
			
			
			
				
				
					
													
					
					
					
										
			
			, 
			["ncaaf_video/2012/02/07/020712.btm_danielson_kiel", "Gary Danielson: Don't overreact to Miles' remarks"]
		
	
];
						
							
							
						 	
								/* This file is considered LIVE on sipreview! */
/* This file gets pulled into fn_video_rr.js during HP publish */
var cvpPlayers = new Array();

var cvpFNRR = new CVP({
	id : 'cvp_2',
	width : '288',
	height : '162',
	//onContentPlay : function(videoId) {
	//	onVideoPlayerPlay(videoId);
	//},
	flashVars : {
		contentId : cvpCurrentId,
		context : 'FN_rightrail',
		configUrl : '/.element/swf/cfg/config.xml',
		containerUrl : '/.element/swf/cfg/container.xml'
	},
	embed : {
		containerSwf : 'http://i.cdn.turner.com/si/.element/swf/4.1/global/si_video.swf',
		expressInstallSwf : 'http://i.cdn.turner.com/si/.e1d/swf/4.0/global/expressInstall.swf',
		options : {
			quality : 'high',
			wmode: 'transparent',
			bgcolor : '#000000',
			allowFullScreen : 'true',
			allowScriptAccess : 'always'
		}
	}
});
cvpFNRR.embedSWF("cvpPlayerArea");
cvpPlayers.push(cvpFNRR);
var hasPlayed = false;

function cnnSendComscoreBeacon(videoId,contentFlag) {
	try {
		var c1 = '1';
		var c2 = '8586808';
		var c3 = '00004';
		var c4 = '8586812';
		var c5 = '010000';  // default code for ad content
		if (contentFlag == 1) { c5 = '020000';} // checks to see if player is showing content or an ad	            
		var beaconImage = new Image();
		beaconImage.src = 'http://b.scorecardresearch.com/p?c1='+c1+'&c2='+c2+'&c3='+c3+'&c4='+c4+'&c5='+c5+'';
  } catch(err) {}
}

/* Video Analytics  */
/* These variables are necessary for vidPlay, vidFiftyPercent, vidSeek to operate properly */
var hasScrubbed = false;
var isAuto = false;
var isHalf = false;
var isBuffering = false;
var isPaused = false;
var vidObj;
var videoPage = (location.pathname.indexOf('/video') === 0) ? 'main' :
		(location.pathname.indexOf('/swimsuit') === 0 || location.pathname.indexOf('_swimsuit') === 5) ? 'swimsuit' : 'other';

if(typeof console != 'undefined'){
	console.log('videoPage: ' + videoPage );
}

function onVideoPlayerBegin(videoId) {
	for(var i=0; i<cvpPlayers.length; i++) {
		var cvpData = cvpPlayers[i].getContentEntry(videoId);
		var cvpObject = window.JSON.parse(cvpData);
		if (cvpObject.id == videoId) {
			if (cvpObject.source.toLowerCase() == 'nba') {
				cvpPlayers[i].setTrackingContext("nba");
			} else {
				cvpPlayers[i].setTrackingContext("si_default");
			}
		}
		if (!cvpQed) {
			for( var i=0; i < cvpPlaylist.length; i++ ) {
				if( cvpCurrentId != cvpPlaylist[i][0] ) {
					cvpFNRR.queue(cvpPlaylist[i][0]);
				}
			}
			cvpQed = true;
		}
	}
}

function onVideoPlayerPlay(videoId) {
	for(var i=0; i<cvpPlayers.length; i++) {
		try {
			var cvpData = cvpPlayers[i].getContentEntry(videoId);
			var cvpObject = window.JSON.parse(cvpData);
			if (hasPlayed) {
				if (document.getElementById('cvpHeadline')) {document.getElementById('cvpHeadline').innerHTML = cvpObject.headline;}
			}
			if (document.getElementById('cvpBlurb')) {document.getElementById('cvpBlurb').innerHTML = cvpObject.description;}
			if (cvpObject.id == videoId) {
				var path = window.location.pathname.substring(1);
				var path_array = path.split("/");
				var yearPattern = /\d+/;
				var swimsuitYear;
				var swimRes;
				if(path_array[0].indexOf("swimsuit") > -1){
					swimsuitYear = yearPattern.exec(path_array[0]);
					swimRes = (swimsuitYear != null ? swimsuitYear + "_swimsuit" : "swimsuit");
				}
				if((path_array[0] == "video" && path_array[1] == "") ||
				   (path_array[0] == swimRes && path_array[1] == "") ||
				   (window.location.hostname.indexOf("fannation.com") > -1)){
					isAuto = true;
				}
				if(isAuto != null && isAuto == false){
					trackMetrics({
						type: "video-start",
						data: {
							video: {
								title: cvpObject.headline,
								id: cvpObject.id,
								category: cvpObject.category,
								subcategory: cvpObject.subcategory,
								source: cvpObject.source
							}
						}
					});
					isAuto = true;
				} else {
					trackMetrics({
						type: "video-autostart",
						data: {
							video: {
								title: cvpObject.headline,
								id: cvpObject.id,
								category: cvpObject.category,
								subcategory: cvpObject.subcategory,
								source: cvpObject.source
							}
						}
					});
				}
			}			
		} catch(e) { };
	}
	hasPlayed = true;
}

function onAdStarted(token, videoId) {
	for(var i=0; i<cvpPlayers.length; i++) {
		try {
			var cvpData = cvpPlayers[i].getContentEntry(videoId);
			var cvpObject = window.JSON.parse(cvpData);
			trackMetrics({
				type: "video-preroll",
				data: {
					video: {
						title: cvpObject.headline,
						id: cvpObject.id,
						category: cvpObject.category,
						subcategory: cvpObject.subcategory,
						source: cvpObject.source
					}
				}
			});
		} catch(e) { };
	}
}

function onVideoTrackingAdCountdown(seconds) { }

function onVideoPlayerPlayHead(videoId, playheadTime, totalDuration) {
	for(var i=0; i<cvpPlayers.length; i++) {
		if(hasScrubbed != true){
			while((playheadTime > (totalDuration / 2)) && isHalf == false){
			 	try {
					var cvpData = cvpPlayers[i].getContentEntry(videoId);
					var cvpObject = window.JSON.parse(cvpData);
					if (cvpObject.id == videoId) {
						trackMetrics({
							type: "video-fifty_percent",
							data: {
								video : {
									title: cvpObject.headline,
									id: cvpObject.id,
									category: cvpObject.category,
									subcategory: cvpObject.subcategory,
									source: cvpObject.source
								}
							}
						});
					}
				} catch(e){ };
				isHalf = true;
				break;
			};
		}
	}
} 

function onVideoPlayerCompleted(videoId) {
	for(var i=0; i<cvpPlayers.length; i++) {
		try {
			var cvpData = cvpPlayers[i].getContentEntry(videoId);
			var cvpObject = window.JSON.parse(cvpData);
			trackMetrics({
				type: "video-complete",
				data: {
					video: {
						title: cvpObject.headline,
						id: cvpObject.id,
						category: cvpObject.category,
						subcategory: cvpObject.subcategory,
						source: cvpObject.source
					}
				}
			});
			isHalf = false;
			isBuffering = false;
			isPaused = false;
			hasScrubbed = false;
		} catch(e) { };
	}
}

function onVideoPlayerPause(videoId, paused) {
	if(isBuffering == false){
		try {
			trackMetrics({
				type: "video-pause",
				data: {}
			});
		} 
		catch(e) { };
	}	
	if(isPaused == false){
		isPaused = true;
	} else {
		isPaused = false;
	}
}

function onVideoPlayerBuffering(videoId, buffering){
	if(isPaused == false){
		try {
			trackMetrics({
				type: "video-pause",
				data: {}
			});
		} 
		catch(e) { };	
	}	
	if(isBuffering == false){
		isBuffering = true;
	} else {
		isBuffering = false;
	}
}

function onVideoTrackingSeek() {
	hasScrubbed = true;
}

							
						

					
