/* Create setup_player as a jQuery plugin. */ 
jQuery(function($) {
	$.setup_player = function(conf){
		
		// Make sure we have a conf
		if (typeof conf == 'undefined'){ return false; }
		
		/*	Overriding defaults: any of the values in "urls" or "defaults" can be easily 
			overriden by extending the conf object that we pass to this function. 
			Check the GeckoPlayer demo page for samples. */
				
		// Setup URLs		
		if (!conf.urls.base) { conf.urls.base = '/'; }
		var skin_station = conf.urls.base + "App_Skins/" + conf.urls.stationCode + "/";
		var skin_global = conf.urls.base + "App_Skins/Global/";
		urls = {
			swf: skin_global + "Flash/flowplayer.commercial-3.1.5.swf",
			skinless: skin_global + "Flash/flowplayer.controls-skinless-3.1.5.swf",
			logo: skin_station + "Flash/logo.swf",
			skin: skin_station + "Flash/skin.swf",
			play: skin_station + "Images/btn/" + conf.size + "_play_over.png",
			tracking: conf.urls.base + "Video/RegisterVideoImpression.ashx",
			image: $('#' + conf.div + ' img:first').attr('src'),
            content: skin_global + "Flash/flowplayer.content-3.2.0.swf"
		}
		// Merge default and custom URLs
		conf.urls = $.extend(urls, conf.urls);

		// Define all our defaults. Quite a few. 
		var defaults = {};
		defaults.autoStart = false;
		defaults.options = {

			key: '#@620efe6a9137a1360b5', // Defaults to *.tipit.net for dev.
			
			contextMenu: [conf.urls.stationCode + ' Media Player 1.0'],
			
			plugins: {                 
				controls: {
					url: conf.urls.skinless,
					skin: 'customskin',
					autoHide:'always',
					hideDelay: 1500,
					zIndex: 2
				},
				customskin: {
					 url: conf.urls.skin, 
					 type: "classLibrary" 
				},
				/* 	We're using a custom logo plugin, instead of the built-in one. 
					The later was doing too much 'magic' and was showing up in crazy places. */
				nLogo: {
					url: conf.urls.logo,
					zIndex: 1,
					fs_top: '12%',	// Since the fullscreen size and aspect ratio is impossible to predict,
					fs_left: '92%'	// we lock it to the top right. 		
				},
                content: { 
                    url: conf.urls.content,
                    display: 'none', // plugin is initially hidden
                    backgroundGradient: 'none',
					backgroundColor: 'transparent',
					border: 0,  
                    bottom: 0,
					left: 0,
					zIndex: 1,
					borderRadius: 0,
					width: '100%',
					padding: [0,0,0,0],
                    style: {
                    "body": {marginLeft: -10}
                    }					
                } 				
			},

			play: { 
				url: conf.urls.play, 
				opacity: 1, 
				fadeSpeed: 500, 
				rotateSpeed: 50				 
			},
		
			playlist: conf.playlist,
			
			removeAdsOnFinish: true,
			
			clip: {	// Global settings that apply to all playlist items.
				autoBuffering: false,
				scaling: "fit"
				/* ,duration: 5 // Useful for testing */
			}			
		};

		// Cleanup video titles and summaries.
		// This needs to happen before FlowPlayer is instantiated.
		conf.playlist = stripPlaylist(conf.playlist, ['title','summary']);	

		// Merge defaults and custom confs
		conf = $.extend(true, defaults, conf);
		
		// Store URLs as options, we'll need them later for plugins
		conf.options.urls = conf.urls;
		
		// Instantiate FlowPlayer
		$f(conf.div, {src: conf.urls.swf, version: [9,115]}, conf.options);
		
		// Setup NewsGecko Plugin
		$f(conf.div).newsgecko(conf);
		
		// Custom no-flash / no-js fallback
		$f(conf.div).customFallback();
		
		// Add vizvid tracking
		$f(conf.div).vizvid();

		// Add a nice big play button to the splash image
		$("#"+conf.div).hover(function() {
			$(".playButton", this).addClass('playButtonOver');
		}, function() {
			$(".playButton", this).removeClass('playButtonOver');
		}) 
		// And a sweet hack to preload the rollover images		
		.find(".playButton").html('<span class="playButtonOver" />');
	
		// Start playback if required
		if (conf.autoStart){
			$f(conf.div).play();
		}
		
		return $f(conf.div);
	}
	

	// NEWSGECKO PLUGIN
	$f.addPlugin("newsgecko", function(conf) { 
		// Adds all the magic required to keep the lizard happy. 
		// - Station's logo conditional display and positioning
		//   (4:3, 16:9, fullscreen, hide if playing an ad)
		// - Tracking for stories and ads
		// - Prevent skipping (scrub forward) of ads
		// - Remove ads from playlist when playback is over.
		
		// self points to current Player instance
		var player = this; 
		
		// LOAD
		// Successful installation of the Flowplayer Flash component in the container.
		player.onLoad(function(clip){
			// Hide the logo. We'll manage it on a per-clip basis.			
			player.getPlugin("nLogo").css({opacity: 0});			
			// Identify and label each clip as video or ad
			$.each(player.getPlaylist(), function(){		
				this.is_ad = !!(this.videoAdId); // we use !! to turn any value (undefined, zero, null) into bool
				this.is_story = !!(this.videoId);
				this.summary = this.summary;
				this.infobox = this.infobox;
			});
		});
		
		// BEGIN
		// The first event to fire during the 'lifecyle' of a clip. Playback hasn't started.
		player.onBegin(function(clip){			
			if (clip.is_ad) {player.enableControls(false);}
			else if (clip.is_story){
			    conf.OnBegin(clip.summary,clip.infobox);
			    player.enableControls(true);
			}	
            player.registerImpression(clip);		
			
		});	
		
		// START
		// Playback has started, and clip metadata is available.
		player.onStart(function(clip){
			clip.is_wide = (clip.metaData.width / clip.metaData.height > 1.5);

			player.logo_reposition(clip);
			
			try {
				var content = player.getPlugin("content");
				if (typeof clip.videoAdId != 'undefined'){
					content.setHtml("<a target='_blank' href='" + clip.videoAdTargetUrl + "'><img src='" + clip.videoAdImageUrl + "'/></a>");
					content.css({height:(clip.videoAdImageHeight + 10), padding: 0}).fadeIn(500);
				} else {
					content.hide();  			
				}
				
				omniture_onClipStart(this.getClip().url,this.getClip().duration, this.getVersion()[5]); 
			} catch(e){ /* Plugins not loaded. */ }
		});			

		// RESUME
		// Playback is resumed after having been paused.
		player.onResume(function(clip){
			if (clip.is_ad) {player.enableControls(false);}
		});	
		
		// FINISH
		// The clip reaches the end.
		player.onFinish(function(clip){ 
			if (player.getConfig().removeAdsOnFinish){
				// When we finish playing the last clip...
				var playlist = player.getPlaylist();
				if (clip.index == playlist.length - 1){
					/* Remove ads from the playlist. 
					   First we store a list of indexes to remove, then we remove them. */ 
					var rm = [];
					$.each(playlist, function(){
						if (this.is_ad){ 
							rm.push(this.index);
						}
					});
					var i = 0; // Since splice changes the indexes, "i" keeps track of removed elements.
					$.each(rm, function(){
						playlist.splice(this + i--, 1);
					});
					// Add the splash image to the playlist, and load it. 
					playlist.push({"url": player.getConfig().urls.image, "duration": 0});
					player.setPlaylist(playlist);
					player.play(playlist.length-1);
					// Hide the content plugin containing the ad overlay
					try {
						player.getPlugin("content").hide();
					} catch(e){ /* Plugin not loaded */ }
				}
			}
		});	

		// FULLSCREEN
		// Going in and out of fullscreen.
		player.onFullscreen(function(clip){
			player.logo_delayed_reposition();
		});		
		player.onFullscreenExit(function(clip){
			player.logo_delayed_reposition();
		});

		
		/* 
		UTILITY FUNCTIONS
		* * * * * * * * */
		
		/* 	A slight delay is needed before repositioning, to allow 
			the player to catch its breath and recalc its dimensions. 
			Otherwise the logo ends up in silly places. */
		player.logo_delayed_reposition = function(){
			clearTimeout(player.fst);
			logo = player.getPlugin("nLogo"); 
			logo.css({opacity: 0});
			player.fst = setTimeout(function(){	
				player.logo_reposition();
			},1000);				
		}
		
		/*	Displays the logo at the proper place, according to:
			- the clip's aspect ratio, 
			- fullscreen status, 
			- story (show logo) vs ad (hide it), 
			- and display settings (don't show the logo at all for the small player). 
		*/
		player.logo_reposition = function(clip){
			
			clip = clip || player.getClip();
												            									
			logo = player.getPlugin("nLogo");
			logoConf = player.getConfig().plugins.nLogo;

			if (clip.is_story && logoConf.display != 'none'){
				if (player.isFullscreen()){
					logo.css({
						width: logoConf.fs_width,
						height: logoConf.fs_height,
						top: logoConf.fs_top,
						left: logoConf.fs_left
					});					
				} else {
					logo.css({
						width: logoConf.width,
						height: logoConf.height,
						top: logoConf.top,
						left: clip.is_wide ? logoConf.left_wide : logoConf.left
					});
				}
				logo.fadeIn(1500);
			} else { 
				logo.css({opacity: 0});
			}	
		}

		
		player.enableControls = function(status){
			player.getControls().enable({scrubber: status});
		}

				
		player.registerImpression = function(clip){
			var randomnumber = Math.floor(Math.random() * 1000001);
			var tracking = player.getConfig().urls.tracking + "?ticks=" + randomnumber;
			if (tracking == "false"){ tracking = false;}
			// Avoid tracking if no tracking URL was provided,
			// avoid tracking the final static image (or anything else w/o ID)
			if (!tracking || !(clip.videoId || clip.videoAdId)) { return false; }
			// We send 'undefined', because RegisterVideoImpression actually considers 
			// any non-integer value to be null.
			jQuery.get(tracking, {
				VIDEOID: clip.videoId || "undefined",
				VIDEOADID: clip.videoAdId || "undefined", 
				VERSIONID: clip.versionId || "undefined" 
			})
			return true;
		}

		// Return self (the player object). Useful for chaining. 
		return player; 
	 
	});
	


	// CUSTOM FALLBACK PLUGIN
	$f.addPlugin("customFallback", function() { 
		// We roll our own Flash version detection, instead of the Flowplayer one. 
		// See http://flowplayer.org/forum/8/18754 for rationale.
		// This relies heavily on HTML hooks and contextual CSS.
		$('body').addClass('jsEnabled');
		if (!flashembed.isSupported(this.getFlashParams().version)){
			$('body').addClass('badFlash');
			if (!flashembed.isSupported([6,65])){
				this.onBeforeLoad(function(){ 
					if (getFlash = $("#"+this.getConfig().playerId + " .missingFlash a").attr('href')){
						window.top.location.href = getFlash;
					}
					return false;
				})
			}
		}
		return this;
	});
	
	// STRIP HTML AND ESCAPES
	// from playlist title and summary attributes
	var stripPlaylist = function(playlist, fields){
		$.each(playlist, function(i, video){
			$.each(fields, function(i, field){
				if (video[field]) { 
					video[field] = $("<i>" + video[field] + "</i>").text();
					video[field] = video[field].replace(/\\"/g,"");
				} 
			});
			playlist[i] = video;
		});
		return playlist;
	}
	
});	



/* murmurhash3_gc.js */
if (typeof jQuery.hash == 'undefined'){
	jQuery(function($){$.extend({hash:function(str){return murmurhash3_32_gc(str,33);}});});function murmurhash3_32_gc(key,seed){var remainder,bytes,h1,h1b,c1,c1b,c2,c2b,k1,i;remainder=key.length%4;bytes=key.length-remainder;h1=2535330683^seed;c1=2505324423;c2=718793509;i=0;while(i<bytes){k1=((key.charCodeAt(i)&255))|((key.charCodeAt(++i)&255)<<8)|((key.charCodeAt(++i)&255)<<16)|((key.charCodeAt(++i)&255)<<24);++i;k1=(((k1&65535)*c1)+((((k1>>>16)*c1)&65535)<<16));k1=(k1<<11)|(k1>>>21);k1=(((k1&65535)*c2)+((((k1>>>16)*c2)&65535)<<16));h1^=k1;h1b=(((h1&65535)*3)+((((h1>>>16)*3)&65535)<<16));h1=(((h1b&65535)+1390208809)+((((h1b>>>16)+1390208809)&65535)<<16));c1b=(((c1&65535)*5)+((((c1>>>16)*5)&65535)<<16));c1=(((c1b&65535)+2071795100)+((((c1b>>>16)+2071795100)&65535)<<16));c2b=(((c2&65535)*5)+((((c2>>>16)*5)&65535)<<16));c2=(((c2b&65535)+1808688022)+((((c2b>>>16)+1808688022)&65535)<<16));}k1=0;switch(remainder){case 3:k1^=(key.charCodeAt(i+2)&255)<<16;case 2:k1^=(key.charCodeAt(i+1)&255)<<8;case 1:k1^=(key.charCodeAt(i)&255);k1=(((k1&65535)*c1)+((((k1>>>16)*c1)&65535)<<16));k1=(k1<<11)|(k1>>>21);k1=(((k1&65535)*c2)+((((k1>>>16)*c2)&65535)<<16));h1^=k1;h1b=(((h1&65535)*3)+((((h1>>>16)*3)&65535)<<16));h1=(((h1b&65535)+1390208809)+((((h1b>>>16)+1390208809)&65535)<<16));}h1^=key.length;h1^=h1>>>16;h1=(((h1&65535)*2246822507)+((((h1>>>16)*2246822507)&65535)<<16));h1^=h1>>>13;h1=(((h1&65535)*3266489909)+((((h1>>>16)*3266489909)&65535)<<16));h1^=h1>>>16;return h1>>>0;}
}

/* jquery.cookie.js */
if (typeof jQuery.cookie == 'undefined'){
	jQuery.cookie=function(key,value,options){if(arguments.length>1&&String(value)!=="[object Object]"){options=jQuery.extend({},options);if(value===null||value===undefined){options.expires=-1;}if(typeof options.expires==="number"){var days=options.expires,t=options.expires=new Date();t.setDate(t.getDate()+days);}value=String(value);return(document.cookie=[encodeURIComponent(key),"=",options.raw?value:encodeURIComponent(value),options.expires?"; expires="+options.expires.toUTCString():"",options.path?"; path="+options.path:"",options.domain?"; domain="+options.domain:"",options.secure?"; secure":""].join(""));}options=value||{};var result,decode=options.raw?function(s){return s;}:decodeURIComponent;return(result=new RegExp("(?:^|; )"+encodeURIComponent(key)+"=([^;]*)").exec(document.cookie))?decode(result[1]):null;};
}
// Vizvid generic tracker
jQuery(function($) { 
	
	var _unique_id = (function() { 
		return $.hash(navigator.userAgent + (+new Date())); // FIXME Do we need something smarter?
	}());

	if (!$.cookie("session_id")){
		$.cookie("session_id", _unique_id, { path: '/' });
	}
	/* FIXME Unused params. Remove if confirmed useless.
	if (!$.cookie("daily_id")){
		// FIXME if we end up using this one, do we need to change it 
		// when the user keeps the browser open overnight?
		$.cookie("daily_id", _unique_id, { expires: 1, path: '/' });
	}
	if (!$.cookie("user_id")){ // monthly? yearly?
		$.cookie("user_id", _unique_id, { expires: 30, path: '/' });
	} */
	
	var _session_info = (function() { 
		return $.param({
			'session_id': $.cookie("session_id")
			/* FIXME Unused params, commented out for shorter pings
			, 'daily_id': $.cookie("daily_id")
			, 'user_id': $.cookie("user_id")*/
		});
	}());

	var track = function(evt, info){
	    // Check that we have all the data before tracking. 
	    // Rapidly switching videos on a playlist can cause metadata to fail.
	    if (!info ||
	    	info.duration == 0 || 
	        typeof info.title == 'undefined' ||
	        typeof info.url == 'undefined'){
	        return false;
	    }

		if (info.title == ''){
			info.title = info.url
						.split('/').pop()
						.split('.').shift() || 
						"Untitled";
		}
		info.title = $("<i>" + info.title + "</i>").text();
		
		if (typeof info.id == 'undefined'){
			delete info["id"];
		}

	    info.nocache = +new Date(); // cache busting

	    if (typeof VIZVID_SITE_ID != 'number'){ return false; }
	    info.site = VIZVID_SITE_ID;
		
		var img = document.createElement('img');
		// Trailing amp fixes IE7 bug. It doesn't track without it.
		img.src = '//ping.vizvid.com/track.gif?event=' + evt + '&' + _session_info + '&' + $.param(info) + '&';

	}
	
	// Expose public methods
	return vizvid = {
		track: track
	}	
	
});


// Vizvid Flowplayer plugin
jQuery(function($) { 
	$f.addPlugin("vizvid", function(conf) { 
		
		var player = this; // points to current Player instance

		// START
		// Playback has started, and metadata is available.
		player.onStart(function(clip){

			clip.title = vizvid.getClipTitle(clip);
			var cuepointInterval = 5; // In seconds. (FIXME make config)
			var cuepoints = [];
			for (var i=1, t=Math.floor(clip.duration / cuepointInterval)+1; i<t; i++){			
				cuepoints.push(i * cuepointInterval * 1000);
			}	
			
			if (cuepoints.length){
				clip.onCuepoint(cuepoints, function(clip, seconds){
					vizvid.track("Cuepoint", vizvid.eventInfo(this, clip, seconds/1000));
				});
			}
					
			vizvid.track("Play", vizvid.eventInfo(this, clip));
		});
		
		// PAUSE
		player.onPause(function(clip){
			vizvid.track("Pause", vizvid.eventInfo(this, clip));
		});

		// RESUME
		// Playback is resumed after having been paused.
		player.onResume(function(clip){
			vizvid.track("Resume", vizvid.eventInfo(this, clip));
		});
		
		// SEEK
		// Fires when the playhead is seeked. "Seconds" is the position
		// that the user intended to go to, and can be a bit different from
		// where the seek finally ends up (because of keyframe positions). 
		player.onBeforeSeek(function(clip, seconds){
			vizvid.track("Seek", vizvid.eventInfo(this, clip, seconds));
		});				
		
		// STOP
		player.onStop(function(clip){
			vizvid.track("Stop", vizvid.eventInfo(this, clip));
		});

		// FINISH
		// The clip reaches the end.
		player.onFinish(function(clip){
			vizvid.track("Finish", vizvid.eventInfo(this, clip));
		});
		
		return player;
	});
});	

/*	Get clip info and clip title.
    Individual sites will have to implement this function.
	Here we retrieve title based on the click URL.
	Could also be (if a single video page) the page's <title>,
	or a string rendered in the template by the server, etc.
	Same for the clip's info, each player will have to adapt 
	to its own API.
	*/
jQuery(function($) { 
	return vizvid = $.extend(true, {
		getClipTitle: function(clip){
			var title = clip.title;
			title = $.trim(title);
			if (title == ''){
				var title = $("h1.storyTitle").text();
				title = $.trim(title);
			}
			return title;
		},
		eventInfo: function(player, clip, seconds){
			// Return false to prevent tracking of ads
			if (clip.is_ad) { 
				return false; 
			}
			return {
				url: clip.completeUrl,
				seconds: Math.floor(seconds || parseInt(player.getTime())),
				duration: Math.floor(clip.duration),
				title: clip.title,
				id: clip.videoId
			}
		}
	}, vizvid);
	
});

