/**
 * Class: CW.Player
 * Main controller class for CW overlay player and ad playing
 */
MN.CWPlayer = MN.Class(MN.EventSource);
_cw = MN.CWPlayer.prototype;

/**
  * Function: initialize
  * Initializes the static variables and starts the player event listeners. Loads up top-level catalog
  * listing for metadata reads and sets the volume based on saved or default value.
  *
  * Parameter:
  * player:MN.Player - Object holding main reference to controls and player wrapper object
  * topLevelId:number - ID of the top level folder in Publish containing the show's folders
  */
_cw.initialize = function(player, topLevelId)
{
	MN.EventSource.prototype.initialize.apply(this);
	
	this.publishHost = "bac0ae93.cdn.cms.movenetworks.com"; // Publish server domain
	
	this.player = player;
	this.DEFAULT_AD_KEY = "default";
	this.INHOUSE_AD_KEY = "inhouse";
	this.curInhouseKey = this.INHOUSE_AD_KEY;
	this.curInhouseRand = Math.ceil(Math.random()*4);
	this.PREROLL_KEY = "preroll";
	this.VIDEOEXTRA_AD_KEY = "videoextra";
	this.INHOUSE_TRACKER_KEY = "inhouse-tracker";
	this.NUM_MIDROLLS_KEY = "num_midrolls";
	this.DEFAULT_NUM_MIDROLLS = 2;
	this.FULL_EPISODE = "Full Episode";
	this.flashMotif = MN.$('flashMotif'); // Holds the flash ad object
	this.catalogPath = "http://%s/cms/publish3/folder/catalog/%s.json";
	this.guidePath = "http://%s/cms/publish3/folder/guide/%s.json";
	this.folderPath = "http://%s/cms/publish3/folder/qvt/%s.qvt";
	this.assetPath = "http://%s/cms/publish3/folder/assetqvt/%s/%s.qvt";
	
	this.nielsenTrackerURL = "http://secure-us.imrworldwide.com/cgi-bin/m?ci=us-800560&cg=%s&tl=dav0-%s&c6=vc,b01&cc=1&rnd=%s";
	this.nielsenEpisodeParam = "c8=pv1,1";
	this.comscoreTrackerURL = "http://b.scorecardresearch.com/b?C1=1&C2=3000017&C3=3000013&C4=3000017&C5=%s&C6=%s&rn=%s";
	
	this.Reset();
	
	MN.Event.Observe(this.player.p, "TimelineLoaded", this.OnTimelineLoaded);
	MN.Event.Observe(this.player.p, 'PlayStateChanged', this.OnPlayStateChanged);
	MN.Event.Observe(this.player.p, "NextClip", this.OnNextClip);
	MN.Event.Observe(this.player.p, "UIStateChanged", this.OnUIStateChanged);
	MN.Event.Observe(this.player.p, 'VolumeChanged', this.OnVolumeChanged);
	
	var savedVolume = MN.Cookie.Get("move_player_volume");
	if(savedVolume != null) {
		this.player.controls.volume.setVolume(savedVolume);
	} else {
		this.player.controls.volume.setVolume(75);
	}
	
	this.catalog = null;
	this.LoadCatalog(topLevelId);
}

/**
  * Function: Rest
  * Before each episode is requested to be played, the variables for playback are reset
  */
_cw.Reset = function()
{
	this.qvt = null;
	this.folder = null;
	this.categoryId = null;
	this.episodeId = null;
	this.playingAd = false;
	this.isAdEnabled = false;
	this.curAsset = null;
	this.curEpisodeTitle = '';
	this.curEpisodeNumber = '';
	this.curSeasonNumber = '';
	this.curSeriesCode = '';
	this.curContentType = '';
	this.series = null;
	this.seriesId = 0;
	this.curSeriesTitle = "";
	this.midrollsPlayed = 0;
	this.midrollsToPlay = 1;
	this.currentSegment = -1;
	this.adURL = null;
	this.savedFullscreen = null; // for returning to full screen after an ad
	this.fullscreen = false;
	this.savedClip = null; // Used to recover after ad playback
	this.savedStart = null; // Facilitates prerolls with S2F
	this.savedStop = null;
	this.isPostroll = false;
	
	this.player.controls.timeline.clearAdMarkers();
}
/**
  * Function: LoadCatalog
  * Load the top-level catalog metadata values
  */
_cw.LoadCatalog = function(topLevelId)
{
	log("PAGE: Loading catalog");
	MN.QVT.LoadQVT(this.guidePath.format(this.publishHost, topLevelId),MN.MakeBound(this,
	function (url, response, headers)
	{
		var catalog = MN.EvalJSON(response);
		if (catalog && catalog.type && catalog.type == "folder")
		{
			this.catalog = catalog;
		}
	}));
}

/**
  * Function: SetEpisode
  * Set the episode to play based on the category and episode IDs. Metadata is loaded and interface initialized,
  * after which the appropriate ad logic determines if and what ad pre-roll to play prior to starting the episode.
  *
  * Parameters:
  * categoryId:Number - Category or folder ID which contains episode asset
  * episodeId:Number - Episode ID to load and play
  * start:Number - When in the episode to begin playback
  * stop:Number - When in the episode to stop playback
  */
_cw.SetEpisode = function(categoryId,episodeId,start,stop)
{
	this.Reset();
	
	this.categoryId = categoryId;
	
	this.savedStart = start;
	this.savedStop = stop;
	
	log("PAGE: Setting episode %s category %s".format(episodeId,categoryId));
	MN.QVT.LoadQVT(this.guidePath.format(this.publishHost, categoryId),MN.MakeBound(this,
	function (url, response, headers)
	{
		var guide = MN.EvalJSON(response);
		if (guide && guide.assets && guide.assets.length > 0)
		{
			var asset = null;
			for (var x=0; x < guide.assets.length; x++)
			{
				if (guide.assets[x].id == episodeId)
				{
					asset = guide.assets[x];
					break;
				}
			}
			
			if (asset != null)
			{
				this.episode = asset;
				this.curEpisodeTitle = this.episode.title;
				this.curEpisodeNumber = this.episode.metadata.episode;
				this.curSeasonNumber = this.episode.metadata.season;
				this.curSeriesCode = this.episode.metadata.series;
				this.curContentType = this.episode.metadata.contentType;
				this.isAdEnabled = (this.episode.metadata.advertisement && this.episode.metadata.advertisement == "true");
		
				if ( this.curEpisodeTitle == undefined )
					this.curEpisodeTitle = '';
				if ( this.curEpisodeNumber == undefined )
					this.curEpisodeNumber = '0';
				if ( this.curSeasonNumber == undefined )
					this.curSeasonNumber = '0';
				
				this.LoadSeriesData(guide.parent_id, MN.MakeBound(this, function()
				{
					// Tierra
					ClipLoadComplete(this, categoryId, episodeId);
				
					this.PlayEpisode(true,start,stop);
	
					var title = "%s / %s".format(this.curEpisodeTitle, this.curSeriesTitle);
					this.player.controls.titledisplay.update(this.htmlDecode(title));
				}));
			}
		}
	}));
}

_cw.LoadSeriesData = function(categoryId, cb)
{
	if (categoryId)
	{
		MN.QVT.LoadQVT(this.guidePath.format(this.publishHost, categoryId),MN.MakeBound(this,
		function (url, response, headers)
		{
			var folder = MN.EvalJSON(response);
			if (folder && folder.parent_id)
			{
				this.folder = folder;
				
				MN.QVT.LoadQVT(this.guidePath.format(this.publishHost, folder.parent_id),MN.MakeBound(this,
				function (url, response, headers)
				{
					var seriesfolder = MN.EvalJSON(response);
					if (seriesfolder && seriesfolder.title)
					{
						this.series = seriesfolder;
						this.seriesId = seriesfolder.id;
						this.curSeriesTitle = seriesfolder.title;
						this.midrollsToPlay = this.FindMetadataValue(this.NUM_MIDROLLS_KEY) || this.DEFAULT_NUM_MIDROLLS;
						
						cb();
					}
				}));
			}
		}));
	}
}

_cw.PlayEpisode = function(preroll,start,stop)
{
	var url = this.assetPath.format(this.publishHost, this.categoryId, this.episode.id);
	log("PAGE: PlayEpisode ", this.episode.id, url);
	preroll = (preroll == null) ? true : preroll;
	
	if(this.savedStart != null && start == null)
	{
		start = this.savedStart;
		stop = this.savedStop;
	}
	
	this.savedStart = start;
	this.savedStop = stop;
		
	if(preroll && this.isAdEnabled)
	{
		this.PlayPreroll();
	}
	else
	{
		this.player.controls.hide(false);
		this.player.play(url,start,stop);
	}
}

_cw.PlayPreroll = function()
{
	log("PAGE: Playing preroll for episode ", this.episode.id);
	var prerollURL = this.GetPrerollURL();
	if(prerollURL)
	{	
		this.PlayAd(null, prerollURL, true);
	}
	else
	{
		logError("PAGE: Preroll failed, will begin episode now");
		this.PlayEpisode(false);
	}
}

_cw.isSkippable = function(clip)
{
	var isSkippable = false;
	if(!this.isAd(clip)) // Content
		isSkippable = true;
	else if(clip.ad_semantics=="ad_pagedecides") // Video extra ad
		isSkippable = true;
	
	return isSkippable;
}

_cw.OnTimelineLoaded = function(newQvt)
{
	if(!this.playingAd){
		log("PAGE: Timeline loaded");
		this.qvt = newQvt;
		
		var clips = this.qvt.Metadata("clips");
		
		//init the shows
		if(!this.qvt.inited){
			for(var i = 0; i < this.qvt.shows.length; i++){
				clips.played = false;
			}
			this.qvt.inited = true;
		}
		
		// OnNextClip does not fire for first clip
		if(this.isAd(clips[0]))
			this.PlayAd(clips[0]);
	}
}

_cw.OnNextClip = function(clipNum)
{
	log("PAGE: Next clip ", clipNum);
		
	this.CheckTracking(clipNum);
	this.ProcessClip(clipNum);
}

// Returns the first ad clip found, begining from the current clip and moving backwards
// If there are adjacent ad clips the first one (relative to start of timeline) in the series is returned.
_cw.GetAdClip = function(clipNum)
{
	var clips = this.qvt.Metadata("clips");
	var clip = clips[clipNum];
	var adClip = null;
	
	if(this.isAd(clip))
	{
		adClip = clip;
	}
	else
	{
		for(var i=clipNum; i>=0; --i)
		{
			if(adClip && !this.isAd(clips[i]))
			{
				break;
			}
			if(this.isAd(clips[i]))
			{
				adClip = clips[i];
			}
		}
	}
	
	return adClip;
}

_cw.HasAdPlayed = function(clipNum)
{
	var adClip = this.GetAdClip(clipNum);
	
	if(!adClip || adClip.played)
		return true;
	
	return false;
}

_cw.SetAdPlayed = function(clipNum,played)
{
	log("Setting ad played for clipNum: ", clipNum);
	var adClip = this.GetAdClip(clipNum);
	played = (played == null) ? true : played;
	adClip.played = played;
	
	return adClip.played;
}

_cw.GetClipNum = function(clip)
{
	var clips = this.qvt.Metadata("clips");
	
	for(var i=0; i<clips.length; i++)
		if(clip == clips[i])
			return i;
	
	return -1;
}

_cw.GetAdURL = function(clip)
{
	log("PAGE: GetAdURL" );
	if(!this.isAd(clip))
		return null;
	var url = clip.ad_url;
	if(!url || url == "Default")
	{
		// Video Extra
		if(clip.ad_semantics == "ad_pagedecides"){
			log("PAGE: GetAdURL: Looking for a video extra ad url");
			url = this.FindMetadataValue(this.VIDEOEXTRA_AD_KEY);
		}
		else {
			log("PAGE: GetAdURL: Looking for a default ad url");
			url = this.FindMetadataValue(this.DEFAULT_AD_KEY);
			if(!url)
			{
				log("PAGE: Couldn't find an ad url, will try to get an inhouse ad url");
				url = this.GetInHouseAdURL();
			}
		}
	}
	
	log("PAGE: final ad url: ", url);

	return url;	
}

_cw.GetPrerollURL = function()
{
	var url = this.FindMetadataValue(this.PREROLL_KEY);
	
	if(url == "none") // special indicator to not play a preroll
		url = null;
		
	log("PAGE: preroll url ", url);
	return url;
}

_cw.FindMetadataValue = function(key)
{
	var val = null;
	
	log("PAGE: FindMetadataValue key:%s clip id:%s".format(key, this.episode.id));
	
	if(this.episode && this.episode.metadata && this.episode.metadata[key])
	{
		val = this.episode.metadata[key];
		log("PAGE: episode level metadata %s::%s".format(key,val));
	}
	
	if(val == null && this.folder && this.folder.metadata && this.folder.metadata[key])
	{
		val = this.folder.metadata[key];
		log("PAGE: folder level metadata %s::%s".format(key,val));
	}
		
	if(val == null && this.series && this.series.metadata && this.series.metadata[key])
	{
		val = this.series.metadata[key];
		log("PAGE: series level metadata %s::%s".format(key,val));
	}
		
	if(val == null && this.catalog && this.catalog.metadata && this.catalog.metadata[key])
	{
		val = this.catalog.metadata[key];
		log("PAGE: catalog level metadata %s::%s".format(key,val));
	}
	
	return val;
}

_cw.GetInHouseAdURL = function()
{
	var url = this.FindMetadataValue(this.curInhouseKey);
	log("PAGE: in house ad URL ", url);
	return url;
}

_cw.PlayAd = function(clip, adURL, preroll)
{
	if (adURL === undefined && clip) this.SavePosition(clip);
	
	adURL = (adURL === undefined) ? this.GetAdURL(clip) : adURL;
	this.adURL = adURL;
	if(clip) 
		log("PAGE: PlayAd ad clip (%s,%s) %s %s playing".format(clip.tlStartTime, clip.tlStopTime, clip.ad_type, adURL));
	else
		log("PAGE: PlayAd ad %s playing (no associated clip)".format(adURL));
	this.player.p.Paused(true); // Pause playback
	this.playingAd = true;
	
	if(adURL) 
	{
		// Track in house ad calls		
		if(adURL == this.GetInHouseAdURL())
			this.TrackInHouseAd();
			
		//if(clip && this.isSkippable(clip)) {
			// MN.CSS.AddClass($('cont_center'), "videoextra");
			// $('posDur').style.visibility = 'visible';
		//}
		
		if(adURL.indexOf(".qmx") != -1) // ad is a Move qmx file
		{
			log("PAGE: ad is qmx: " + adURL);
			if(this.savedFullscreen == null) this.savedFullscreen = this.fullscreen;
			this.NormalMode();
			//MN.Event.Observe(this.player.p, 'TimelineLoaded', this.StartCountdown);
			MN.Event.Observe(this.player.p, 'PlayStateChanged', this.RecoverPositionAfterMoveAd);
			this.player.controls.hide(true);
			this.player.p.PlayClip(adURL, '_ad', 0);
		}
		else if (adURL.indexOf(".qvt") != -1) // ad is a Move qvt file
		{
			log("PAGE: ad is qvt: " + adURL);
			if(this.savedFullscreen == null) this.savedFullscreen = this.fullscreen;
			this.NormalMode();
			//MN.Event.Observe(this.player.p, 'TimelineLoaded', this.StartCountdown);
			MN.Event.Observe(this.player.p, 'PlayStateChanged', this.RecoverPositionAfterMoveAd);
			this.player.controls.hide(true);
			this.player.p.Play(adURL);
		}
		else if(adURL.indexOf("doubleclick") != -1) // ad is a Doubleclick flash file
		{
			log("PAGE: ad is doubleclick: " + adURL);
			if(this.savedFullscreen == null) this.savedFullscreen = this.fullscreen;
			this.NormalMode();
			this.ShowAdPlayer(true);
			this.PlayAdWhenLoaded(preroll);
		}
		else // unknown ad type
		{
			logError("PAGE: ad is of unknown type: ", adURL);
			this.RecoverPosition();
		}
	}
	else // no ad url
	{
		logError("PAGE: could not find an ad url");
		this.RecoverPosition();
	}
}

_cw.TrackInHouseAd = function()
{
	if(this.GetInHouseAdURL())
	{
		var trackerURL = this.FindMetadataValue(this.INHOUSE_TRACKER_KEY);
		if(trackerURL) {
			var ord=Math.random()*10000000000000000; // cache busting
			trackerURL += ";ord=" + ord;
			log("PAGE: Tracking in house ad with url " + trackerURL);
			(new Image()).src = trackerURL;
		}
	}
}

_cw.PlayAdWhenLoaded = function(preroll)
{
	if(this.flashMotif && this.flashMotif.playAd) {
		log("PAGE: Doubleclick Flash Motif Object Loaded. Proceeding to attempt ad playback using flashMotif.playAd()");
		this.flashMotif.playAd(this.adURL, (preroll===true)?1:(this.midrollsToPlay-this.midrollsPlayed));
	} else {
		log("PAGE: Doubleclick Flash Motif Object NOT Loaded. Cannot play ad. Will try again in 1 second...");
		setTimeout(this.PlayAdWhenLoaded, 1000);
	}
}

_cw.ShowAdPlayer = function(show)
{
	MN.$('mn_player').style.height = (show)?'1px':'';
	MN.$('mn_player').style.width = (show)?'1px':'';
	MN.$('mn_player').style.visibility = (show)?'hidden':'visible';
	MN.$('flash_container').style.visibility = (show)?'visible':'hidden';
}

_cw.SavePosition = function(clip)
{
	log("PAGE: Saving QVT position");
	this.savedClip = clip;
}

_cw.RecoverPositionAfterMoveAd = function(oldS, newS)
{
	if(newS == MN.QMP.PS.MediaEnded)
	{
		log("PAGE: Recovering after Move Ad");
		MN.Event.StopObserving(this.player.p, 'PlayStateChanged', this.RecoverPositionAfterMoveAd);
		
		if(this.isPostroll)
		{
			this.NotifyOfCompletion();
			return;
		}
		
		//Get next random clip
		//Setup random inhouse ad
		var tmp = this.curInhouseRand;
		while(tmp == this.curInhouseRand)
		{ //Randomly get new inhouse thats not the previous one
			this.curInhouseRand = Math.ceil(Math.random()*4);
		}
		if(this.curInhouseRand != 1)
		{
			this.curInhouseKey = this.INHOUSE_AD_KEY + this.curInhouseRand;
		}
		else
		{
			this.curInhouseKey = this.INHOUSE_AD_KEY;
		}
		
		log("PAGE: *** Next inhouse ad will be: " + this.curInhouseKey);
		if(this.savedClip)
		{ // midroll ad, so let's play as many as specified
			this.midrollsPlayed++;
			//this.midrollsToPlay = this.FindMetadataValue(this.NUM_MIDROLLS_KEY) || this.DEFAULT_NUM_MIDROLLS;
			if(this.midrollsPlayed < this.midrollsToPlay)
			{
				log("PAGE: Play another midroll. midrollsPlayed: %s; midrollsToPlay: %s".format(this.midrollsPlayed, this.midrollsToPlay));
				setTimeout(MN.MakeBound(this,function(){this.PlayAd(this.savedClip);}), 1000);
			}
			else{
				
				log("PAGE: Done playing midrolls. midrollsPlayed: %s; midrollsToPlay: %s".format(this.midrollsPlayed, this.midrollsToPlay));
				this.midrollsPlayed = 0; // specified num midrolls reached; reset counter
				this.RecoverPosition();
			}
		}
		else
		{
			this.RecoverPosition();
		}
	}
}

_cw.RecoverPosition = function()
{
	log("PAGE: Recovering position after ad");
	this.playingAd = false;
	this.ShowAdPlayer(false);
		
	if(this.isPostroll)
	{
		this.NotifyOfCompletion();
		return;
	}
	
	if(this.savedClip)
	{
		this.SetAdPlayed(this.GetClipNum(this.savedClip));	
		var nextClip = this.qvt.Metadata("clips")[this.GetClipNum(this.savedClip) + 1];
		this.savedClip = null;
		if(nextClip && this.isAd(nextClip)) // don't attempt to play the episode if we know there's just another ad coming up next.
		{
			this.ProcessClip(this.GetClipNum(nextClip));
		}
		else if(nextClip)
		{
			this.player.controls.hide(false);
			this.player.play(this.qvt, (nextClip.tlStartTime + 0.01)); // Added 0.01 seconds to start time to fix bug with the SDK notifying that this time was inside the ad break clip
			
			setTimeout(this.player.controls.timeline.drawAdBreaks, 1000);
			
			if(this.savedFullscreen){
				this.savedFullscreen = null;
				if (QI.os=="win")
				{
					setTimeout(MN.MakeBound(this,function(){this.Fullscreen()}),250);
				}
				else
				{
					this.Fullscreen();
				}
				log("PAGE: Going back to fullscreen after ad break");
			}
			else{
				this.savedFullscreen = null;
			}
		}
		else
		{
			this.NormalMode();
			this.savedFullscreen = null;
			this.player.p.Stop();
		}
	}
	else // was a preroll
	{
		if(this.savedFullscreen){
			this.savedFullscreen = null;
			this.Fullscreen();
		}
		else{
			this.savedFullscreen = null;
		}
		this.PlayEpisode(false);
	}
}

_cw.Fullscreen = function()
{
	if(this.player.p.fullScreenSupported() && !this.fullscreen)
	{
		this.player.controls.fullScreen.onClickFullScreen();
	}
}

_cw.NormalMode = function()
{
	if(this.player.p.fullScreenSupported() && this.fullscreen)
	{
		this.player.controls.fullScreen.onClickNormalScreen();
	}
}

_cw.StopPlayback = function()
{
	if(this.player)
	{
		this.player.p.Stop();
	}
}

_cw.adDone = function(success, played)
{
	if(!success) {
		logError("PAGE: Flash ad failed, will try inhouse ad");
		this.ShowAdPlayer(false);
		this.PlayAd(null,this.GetInHouseAdURL());
	} else {
		log("PAGE: Flash ad succeeded");
		if(this.savedClip){ // midroll ad, so let's play as many as specified
			this.midrollsPlayed += played;
			//this.midrollsToPlay = this.FindMetadataValue(this.NUM_MIDROLLS_KEY) || this.DEFAULT_NUM_MIDROLLS;
			if(!isNaN(this.midrollsToPlay) && this.midrollsPlayed < this.midrollsToPlay){
				//log("PAGE: Play another midroll. midrollsPlayed: %s; midrollsToPlay: %s".format(this.midrollsPlayed, this.midrollsToPlay));
				//setTimeout(MN.MakeBound(this,function(){this.PlayAd(this.savedClip);}), 1000);
				this.ShowAdPlayer(false);
				this.PlayAd(null,this.GetInHouseAdURL());
			}
			else{
				log("PAGE: Done playing midrolls. midrollsPlayed: %s; midrollsToPlay: %s".format(this.midrollsPlayed, this.midrollsToPlay));
				this.midrollsPlayed = 0; // specified num midrolls reached; reset counter
				this.RecoverPosition();
			}
		}
		else{
			this.RecoverPosition();
		}
	}
}
function adDone(success, played)
{
	cwPlayer.adDone(success, played);
}

_cw.isAd = function(clip)
{
	var isAd = false;
	if(clip.isGap && clip.type && clip.type=='ad_dynamic')
		isAd = true;
		
	return isAd;
}

_cw.ProcessClip = function(clipNum)
{
	if (!this.isAdEnabled) return;
	
	var clips = this.qvt.Metadata("clips");
	var clip = clips[clipNum];
	
	log("PAGE: Processing Clip Num: ", clipNum, this.savedStart, this.savedStop);
	if(!this.HasAdPlayed(clipNum)) // Play ad for this clip
	{
		log("PAGE: Ad Has Not Played for Clip Num: ", clipNum);
		// End tracking
		if(this.currentSegment != -1){
			this.currentSegment = -1;
		}
		this.PlayAd(this.GetAdClip(clipNum));
	}
	else if(this.isAd(clip)) // Skip the ad clip that's already played
	{
		log("PAGE: Ad At Clip Num: ", clipNum);
		if(clipNum+1 < clips.length)
		{
			this.player.p.Paused(true);
			this.player.play(this.qvt, (clips[clipNum+1].tlStartTime + 0.01));
		}
		else
		{
			this.player.p.Stop();
		}
	}
	else
	{
		// move to a saved position
		if(this.savedStart != null && this.savedStart > this.player.CurrentPosition())
		{
			this.player.play(this.qvt, this.savedStart, this.savedStop);
			
		}
		this.savedStart = null;
		this.savedStop = null;
	}
}

_cw.OnPlayStateChanged = function(oldPS, newPS)
{
	log("PAGE: OnPlayStateChanged - " + oldPS + " - " + newPS);
	if (newPS==MN.QMP.PS.Error)
	{
		if (this.playingAd)
		{
			log("PAGE: Recovering from ERROR state returned by player");
			this.RecoverPosition();
		}
		else
		{
			this.player.controls.titledisplay.update("Error occurred in playback, reload to try again");
		}
		return;
	}
	
	if(!this.playingAd){
		if(newPS == MN.QMP.PS.Playing){
			var clipNum = this.player.p.CurrentClip();
			this.CheckTracking(clipNum);
			this.ProcessClip(clipNum);
		}
		else if (newPS == MN.QMP.PS.MediaEnded){
			this.NormalMode();
			
			if (this.curContentType != this.FULL_EPISODE)
			{
				log("PAGE: Playing postroll for episode ", this.episode.id);
				var postrollURL = false;//this.GetPrerollURL();
				if(postrollURL)
				{
					this.isPostroll = true;
					this.PlayAd(null, postrollURL);
				}
				else
				{
					this.NotifyOfCompletion();
				}
			}
			else
			{
				this.NotifyOfCompletion();
			}
		}
	}
}

_cw.CheckTracking = function(clipNum)
{
	if (clipNum < 0) return;
	
	//Episode QVT Clip Change
	log('Clip changed to ' + clipNum);
	var clips = this.qvt.Metadata("clips");
	var clip = clips[clipNum];
	var segment = 1;
	for(var i=0; i<clipNum; i++)
	{
		if(!this.isAd(clips[i]))
		{
			segment++;
		}
	}
	if(!this.isAd(clip))
	{
		//Content clip
		log("Seg ", segment, "vs curSeg", this.currentSegment);
		if(segment != this.currentSegment && this.currentSegment == -1)
		{
			if(clipNum == 0 || this.HasAdPlayed(clipNum-1))
			{
				this.HandleTrackingCall(segment);
				this.currentSegment = segment;
			}
		}
	}
}

_cw.HandleTrackingCall = function(segment)
{
	var randNum = Math.floor(Math.random()*10000000);

	var title = escape(this.curSeriesCode);
	var tl = "%s-Season%s-Episode%s-Segment%s";
	tl = tl.format(title, this.curSeasonNumber, this.curEpisodeNumber, segment);
	var adUrl = this.nielsenTrackerURL.format(title, tl, randNum);
	if(segment == 1 && this.curContentType == this.FULL_EPISODE)
	{
		adUrl += "&" + this.nielsenEpisodeParam; //Unique episode tracker
	}
	log('sendNielsenCall: ', adUrl);
	this.SendTrackingCall(adUrl);

	if(segment == 1 && this.qvt.comscoreSent != true){ // Only send the tracker once per episode. Flag is so it doesn't get sent if a user scrubs back to segment one from another segment
		var cbid = "%s-SN%s-EP%s-ET%s";
		cbid = cbid.format(this.curSeriesCode, ((this.curSeasonNumber=="0")?"":this.curSeasonNumber), 
			((this.curEpisodeNumber=="0")?"":this.curEpisodeNumber), this.curEpisodeTitle);
		var cgid = (this.curContentType == this.FULL_EPISODE)?"030000":"020000";
		adUrl = this.comscoreTrackerURL.format(cgid, escape(cbid), randNum);
		log('sendComscoreCall: ', adUrl);
		this.qvt.comscoreSent = true;
		this.SendComscoreTrackingCall(adUrl);
	}
}

var _trackingImage = null;
_cw.SendTrackingCall = function(url)
{
	_trackingImage = new Image(1,1);
	setTimeout(function() { _trackingImage.src = url; }, 1);
}

var _trackingImageComscore = null;
_cw.SendComscoreTrackingCall = function(url)
{
	_trackingImageComscore = new Image(1,1);
	setTimeout(function() { _trackingImageComscore.src = url; }, 1);
}

/**
  * Function: onUIStateChanged
  * 
  */
_cw.OnUIStateChanged = function(state)
{
	if (state == "2")
	{
		this.fullscreen = true;
	}
	else if (state == "3")
	{
		this.fullscreen = false;
	}
}

_cw.OnVolumeChanged = function(newVol)
{
	MN.Cookie.Set("move_player_volume", newVol);    // Create session cookie
}

_cw.NotifyOfCompletion = function()
{
	this.isPostroll = false;
	
	this.PostEvent("PlayoutComplete", this);
}

_cw.htmlDecode = function(string)
{
	string = string.replace(/\&gt;/g, ">");
	string = string.replace(/\&lt;/g, "<");
	string = string.replace(/\&quot;/g, "\"");
	string = string.replace(/\&#039;/g, "'");
	string = string.replace(/\&#39;/g, "'");
	string = string.replace(/\&apos;/g, "'");
	string = string.replace(/\&amp;/g, "&");

	return string;
}

function loadBanner(adTag) {
	log('PAGE: Attempting to load banner ad');
	var frames = MN.$('ad_728x90').getElementsByTagName('iframe');
	if(frames && frames[0] != null)
		frames[0].src = adTag;
	else{
		log("PAGE: Creating iframe for banner ad");
		MN.$("ad_728x90").innerHTML = '<iframe width="728" height="90" marginwidth="0" marginheight="0" hspace="0" vspace="0" frameborder="0" scrolling="no" ></iframe>';
		MN.$('ad_728x90').getElementsByTagName('iframe')[0].src = adTag;
	}
}

function loadCompanion(adTag) {
	log("PAGE: Attempting to load companion ad");
	var frames = MN.$('ad_300x250').getElementsByTagName('iframe');
	if(frames && frames[0] != null)
		frames[0].src = adTag;
	else{
		log("PAGE: Creating iframe for companion ad");
		MN.$("ad_300x250").innerHTML = '<iframe width="300" height="250" marginwidth="0" marginheight="0" hspace="0" vspace="0" frameborder="0" scrolling="no" ></iframe>';
		MN.$('ad_300x250').getElementsByTagName('iframe')[0].src = adTag;
	}
}

function getPlayerVolume()
{
	//method to allow the ad player to get the plugin volume
	return movePlayer.p.Volume();
}