/**
 * @fileoverview	newsday.com General Video Player JavaScript Controller
 * @author			Lenny Burdette <lburdette@schematic.com>
 * @version			1.0
 * @dependencies	jquery.js (v.1.3.x)
 *					swfobject.js
 *					global.js
 */

var XLI = window.XLI || {};

XLI.VideoPlayer = function() {
	
	/* --- CONSTANTS --- */
	
	var CONSTANTS = {
		
		// absolute path to the video player swf
		SWF_SOURCE : "/swf/exploreli/exploreLIVP.v.2.08.swf",
		
		// dom id prefix for any generated video players
		SWF_ID_PREFIX : "videoPlayer_",
		
		// swf should be contained in an element with dimensions
		SWF_WIDTH : "100%",
		
		SWF_HEIGHT : "100%",
		
		// minimum flash version, passed to swfobject
		FLASH_VERSION : "9.0.115",
		
		// absolute path to express install swf
		EXPRESS_INSTALL_URL : "/swf/exploreli/expressInstall.swf",
		
		// event handlers are stored on a publicly accessible array
		// use this prefix to send a string reference to the array
		EVENT_HANDLER_PREFIX : "XLI.VideoPlayer.eventHandlers",
		
		// alternate content is stored and hidden in a div with this class name
		ALT_CONTENT_CLASS : "playerAltContent",
		
		// event names
		START : "start",
		PLAYING_STATE_ENTERED : "playingStateEntered",
		PAUSED_STATE_ENTERED  : "pausedStateEntered",
		STOPPED_STATE_ENTERED : "stoppedStateEntered",
		COMPLETE : "complete",
		ERROR : "error",
		CLIP_READY : "clipReady",
		READY : "ready",
		INITIALIZE : "initialize",
		START_PREROLL : "startPreroll",
		END_PREROLL : "endPreroll",
		SHOW_HALF_LEADER : "showHalfLeader",
		RELATED_VIDEO_CLICK : "relatedVideoClick"
		
	};
	
	// shorthand reference
	var C = CONSTANTS;
	
	
	/* --- STATIC VARIABLES --- */
	
	var STATIC = {
		
		// stores the instances by id
		instances : {},
		
		// used to increment the player ids
		swfCounter : 0,
		
		// stores event handler functions
		eventHandlers : [],
		
		defaultFlashVars : {
			mode : "standard",
			autoPlay : "false"
		},
		
		defaultParams : {
			bgcolor : "#000000",
			allowfullscreen : "true",
			allowscriptaccess : "always",
			base : ".",
			wmode : "opaque"
		},
		
		defaultAttributes : {}
	};
	
	
	/* --- CONSTRUCTOR --- */
	
	var VideoPlayer = function($altContent, fv) {
		this.$altContent = $altContent;
		this.$container = this.$altContent.parent();
		this.$container.css("display", "block");
		
		this.initialized = false;
		
		this.vars = fv;
		this.params = {};
		this.attributes = {};
		this.callbacks = {};
		
		createFlash(this);
	};
	
	
	/* --- INSTANCE METHODS --- */
	
	VideoPlayer.prototype = {
		
		initialize : function() {
			this.swf = $("#" + this.id).get(0);
			if (! this.swf) {
				XLI.Debug.error("Flash player not found");
				return;
			}

			this.initialized = true;
			
			this.delegateEvent({ type : C.INITIALIZE });
			addEventListeners(this);
		},
		
		/* event handlers */
		
		addCallback : function(type, func, scope) {
			if (! this.callbacks[type]) {
				this.callbacks[type] = [];
			}
			this.callbacks[type].push([func, scope]);
		},
		
		delegateEvent : function(event) {
			XLI.Debug.log("Delegating Event [type]: "+ event.type);
			if (this.callbacks[event.type]) {
				var callbacks = this.callbacks[event.type];
				for (var i = 0, l = callbacks.length; i < l; i++) {
					try {
						callbacks[i][0].apply(callbacks[i][1], [event]);
					} catch(e) {
						XLI.Debug.error("callback failed for event", event.type, e.message);
					}
				}
			}
		},
		
		/* player methods */
		
		loadVideo : function() {
			if (this.swf && typeof this.swf.loadVideo === 'function') {
				return this.swf.loadVideo.apply(this.swf, arguments);
			}
		},
		
		play : function() {
			if (this.swf && typeof this.swf._play === 'function') {
				return this.swf._play();
			}
		},
		
		pause : function() {
			if (this.swf && typeof this.swf.pause === 'function') {
				return this.swf.pause();
			}
		},
		
		stop : function() {
			if (this.swf && typeof this.swf._stop === 'function') {
				return this.swf._stop();
			}
		},
		
		seek : function() {
			if (this.swf && typeof this.swf.seek === 'function') {
				return this.swf.seek.apply(this.swf, arguments);
			}
		},
		
		setAutoPlay : function() {
			if (this.swf && typeof this.swf.setAutoPlay === 'function') {
				return this.swf.setAutoPlay.apply(this.swf, arguments);
			}
		},
		
		getAutoPlay : function() {
			if (this.swf && typeof this.swf.getAutoPlay === 'function') {
				return this.swf.getAutoPlay();
			}
		},
		
                getCurrentVideoId : function() {
                        if (this.swf && typeof this.swf.getCurrentVideoId === 'function') {
                                return this.swf.getCurrentVideoId();
                        }
                },

		getPlayheadTime : function() {
			if (this.swf && typeof this.swf.getPlayheadTime === 'function') {
				return this.swf.getPlayheadTime();
			}
		},
		
		getDuration : function() {
			if (this.swf && typeof this.swf.getDuration === 'function') {
				return this.swf.getDuration();
			}
		},
		
		/* other methods */
		
		resize : function(options) {
			resize(this, options);
		},
		
		destroy : function() {
			this.callbacks = null;
			destroy(this);
		},


		/* for advertising */

		getCubeAd : function() {
			XLI.Debug.log("XLI.Video.getCubeAd() called");
			if (this.swf && typeof this.swf.getCubeAd === 'function') {
				var url = this.swf.getCubeAd();
				XLI.Debug.log("swf.getCubeAd() returned:" + url);
				return url;
			} else {
				return null;
			}
		},

		getHalfLeaderAd : function() {
			if (this.swf && typeof this.swf.getHalfLeaderAd === 'function') {
				var url = this.swf.getHalfLeaderAd();
				XLI.Debug.log("swf.getHalfLeaderAd() returned:" + url);
				return url;
			} else {
				XLI.Debug.error("swf.getHalfLeaderAd() is not a function.");
				return null;
			}
		},

		getClickedVideoID : function() {
			if (this.swf && typeof this.swf.getRelatedVideoId === 'function') {
				var id = this.swf.getRelatedVideoId();
				XLI.Debug.log("swf.getRelatedVideoId() returned:" + id);
				return id;
			} else {
				XLI.Debug.error("swf.getRelatedVideoId() is not a function.");
				return null;
			}
		}

	};
	
	
	/* --- PUBLIC CLASS METHODS --- */
	
	var publicMethods = {
		
		create : function($altContent, fv) {
			var player = new VideoPlayer($altContent, fv);
			self.instances[player.id] = player;
			return player;
		},
		
		playerIsReady : function(playerId) {
			if (playerId) {
				//XLI.Debug.log("Flash says the player is ready", playerId);
				attemptInitialize(playerId);
			}
		},

		startPreRoll : function(playerId) {
			var tmp = XLI.VideoPlayer.swfCounter-1;
			console.log(XLI.VideoPlayer.SWF_ID_PREFIX + "" +tmp);
			console.log(XLI.VideoPlayer.instances);
			XLI.VideoPlayer.instances[XLI.VideoPlayer.SWF_ID_PREFIX + "" + tmp].delegateEvent({ type : "startPreroll" }); 
		}
		
	};
	
	// combine public class methods and static variables on one object
	var self = $.extend(publicMethods, STATIC);
	
	// XLI = window.XLI || {
	// 	VideoPlayer : {
	// 		playerIsReady : self.playerIsReady
	// 	}
	// };
	
	
	/* --- PRIVATE METHODS --- */
	
	function createFlash(player) {
		player.id = C.SWF_ID_PREFIX + (self.swfCounter++);
		
		var altContent = $('<div class="' + C.ALT_CONTENT_CLASS + '"></div>').append(player.$altContent.clone());
		if (! player.$altContent.attr("id")) {
			player.$altContent.attr("id", "flashContainer_" + (self.swfCounter - 1));
		}
		
		var flashvars = $.extend({}, self.defaultFlashVars, player.vars, { playerId: player.id });
		var params = $.extend({}, self.defaultParams, player.params);
		var attributes = $.extend({}, self.defaultAttributes, player.attributes, { id: player.id });
		
		swfobject.embedSWF(C.SWF_SOURCE, player.$altContent.attr("id"), C.SWF_WIDTH, C.SWF_HEIGHT, C.FLASH_VERSION, C.EXPRESS_INSTALL_URL, flashvars, params, attributes);
		
		player.$container.append(altContent);
	};
	
	
	function attemptInitialize(id) {
		if (! self.instances[id]) {
			setTimeout(function() {
				attemptInitialize(id);
			}, 250);
			return;
		}
		
		self.instances[id].initialize();
	};
	

	function storeEventHandler(handler, player) {
		var index = self.eventHandlers.length;

		self.eventHandlers[index] = function() {
			handler.apply(player, arguments);
		};
		
		return C.EVENT_HANDLER_PREFIX + "[" + index + "]";
	};
	
	
	function addEventListeners(player) {
		XLI.Debug.log("VideoPlayer.addEventListeners");
		player.swf.addEventListener( C.START,					storeEventHandler(player.delegateEvent, player) );
		player.swf.addEventListener( C.PLAYING_STATE_ENTERED,	storeEventHandler(player.delegateEvent, player) );
		player.swf.addEventListener( C.PAUSED_STATE_ENTERED,	storeEventHandler(player.delegateEvent, player) );
		player.swf.addEventListener( C.STOPPED_STATE_ENTERED,	storeEventHandler(player.delegateEvent, player) );
		player.swf.addEventListener( C.COMPLETE,				storeEventHandler(player.delegateEvent, player) );
		player.swf.addEventListener( C.ERROR,					storeEventHandler(player.delegateEvent, player) );
		player.swf.addEventListener( C.CLIP_READY,				storeEventHandler(player.delegateEvent, player) );
		player.swf.addEventListener( C.READY,					storeEventHandler(player.delegateEvent, player) );
		player.swf.addEventListener( C.START_PREROLL,			storeEventHandler(player.delegateEvent, player) );
		player.swf.addEventListener( C.END_PREROLL,				storeEventHandler(player.delegateEvent, player) );
		player.swf.addEventListener( C.SHOW_HALF_LEADER,		storeEventHandler(player.delegateEvent, player) );
		player.swf.addEventListener( C.RELATED_VIDEO_CLICK,		storeEventHandler(player.delegateEvent, player) );
	};
	
	
	function resize(player, options) {
		options = $.extend({
			duration: 250,
			easing: "linear",
			animate: true
		}, options);
		
		// no animation
		if (! options.animate) {
			player.$container.css({
				width: options.width,
				height: options.height
			});
			return;
		}
		
		// set up animation parameters
		var container = player.$container;
		var begin = {
			width: container.width(),
			height: container.height()
		};
		var change = {
			width: options.width - begin.width,
			height: options.height - begin.height
		};
		var easing = jQuery.easing[options.easing] || jQuery.easing.linear;
		
		// run the animation
		var start = new Date().getTime();
		animate();
		
		// the working animation function
		function animate() {
			var t = new Date().getTime() - start;
			if (t < options.duration) {
				container.css({
					width: easing(null, t, begin.width, change.width, options.duration),
					height: easing(null, t, begin.height, change.height, options.duration)
				});
				setTimeout(animate, 0);
			} else {
				container.css({
					width: options.width,
					height: options.height
				});
			}
		};
	};
	
	
	function destroy(player) {
		self.instances[player.id] = null;
		var alt = player.$container.find("." + C.ALT_CONTENT_CLASS).removeClass(C.ALT_CONTENT_CLASS).html();
		player.$container.empty().append(alt);
	};
	
	// add the constants to the returned object so 
	// that they can be referenced outside of the class
	return $.extend(self, CONSTANTS);
}();

