/**
 * bam.FlvPlayer - Instantiatable Flash Video Player.
 *
 * @author Aleksandar Kolundzija
 * @version 3.1.0
 * - now triggers custom events (see bottom)
 * - now supports HTML5 video for iPad
 *
 * @TODO Resolve potential collisions between companion ads for multiple instances of the player (same ad #ids)
 * @TODO Make isPlaying a public static property
 */
 
bam.FlvPlayer = function(props){
		
	// private members
	var _swfObj, // will store SWFObject for this FlvPlayer
			_fwSites = ["mlb","sny","yesnetwork","tigerwoods","minorleaguebaseball"], // domains which support FreeWheel
			_self    = this,
			
			// iPad support vars
			_isIPad  = (bam.env && bam.env.client && bam.env.client.isIPad),
			_vPlayer; // html5 video tag, if used (currently iPad only)
	
	
	/**
	 * Private method for retrieving the domain using page URL, primarily for 
	 * non-MLB properties, as they don't have the "club" variable set. This method
	 * is called by _getDefaultSiteSectionArray when club value is unavailable.
	 * @return string
	 */
	function _getDomain(){
		var hostArr = document.location.hostname.toLowerCase().split("."), // for non-mlb properties which have no club var
				domain  = hostArr[hostArr.length-2] || "mlb";
		return domain;
	}
	
	
	/**
	 * Private method for retrieving ad network  based a on domain lookup.
	 * @return string "fw" or "dc"
	 */
	function _getAdNetwork(){
		return ($.inArray(_getDomain(), _fwSites)>-1) ? "fw" : "dc";
	}
	
	
	/** 
	 * Private method for generating default set of siteSection values. These values 
	 * are become joined with pageComponent value and passed to FlvPlayer as siteSection
	 * for use by the FreeWheel AdController. If values cannot be generated (result of 
	 * global variables not being available), a default string is returned.
	 * @return string
	 */
	function _getDefaultSiteSectionArray(){
		var sectionArr = [];
		sectionArr.push(window.club    ? club    : _getDomain());
		sectionArr.push(window.section ? section : "");
		sectionArr.push(window.page_id ? page_id : (window.pageid) ?  pageid : "");  // some sites use pageid instead of page_id
		return (sectionArr.length) ? sectionArr : "not_available";
	}
	
	
	/** 
	 * _makeContainer() is a private method for creating a div which will serve
	 * as the container for the SWF player.  It returns a referene to the created div.
	 * @param {string} containerId
	 */ 
	function _makeContainer(containerId){
		$("<div id='"+containerId+"'></div>").appendTo("body");
		return $("#"+containerId)[0];
	}
	
	
	/** 
	 * _getVersionSkin() is a private method for mapping the requested skin (path)
	 * to the equivalent skin that's compatible with this version of the player.  While
	 * hackish, this allows preserving existing references to skins while adding support
	 * for the new player and skins compatible with it.  Also allows easy rollbacks.
	 */
	function _getVersionSkin(skinUrl){
		var skinRoot = "/flash/video/y2009/skins/",
				skinMap  = {
					"/flash/video/y2008/skins/ads_countdown_skin.swf"   : skinRoot + "ad_countdown.swf",
					"/flash/video/y2008/skins/mlb_hpSkin.swf"           : skinRoot + "mlb_homepage.swf",
					"/flash/video/y2008/skins/mlb_mediaLandingSkin.swf" : skinRoot + "mlb_media_landing.swf",
					"/flash/video/y2008/skins/mlb_team_lookin.swf"      : skinRoot + "mlb_live_lookin.swf",
					"/flash/video/y2008/skins/mlb_teamHPmini.swf"       : skinRoot + "mlb_team_homepage.swf",
					
					"/flash/video/v2/skins/mlb_hpSkin.swf"              : skinRoot + "mlb_homepage.swf",
					"/flash/video/v2/skins/mlb_mediaLandingSkin.swf"    : skinRoot + "mlb_media_landing.swf",
					"/flash/video/v2/skins/mlb_teamHPmini.swf"          : skinRoot + "mlb_team_homepage.swf"
				},
				skin = skinMap[skinUrl] || _swfProps.skin; // use default if not in skinMap
		return skin;
	}


	var _swfProps = {
		// default props of SWFObject.
		file              : "/shared/flash/video/flvplayer_v3.swf",
		elemId            : "flvContainer_"+(new Date()).getTime(),  // generate unique ID
		width             : 512,
		height            : 384,
		flashVersion      : "9",
		versionControl    : "4.3", // flv player version (includes freewheel stuff)
		allowScriptAccess : "always",
		allowFullScreen   : "true",
		salign            : "TL",
		videoAlign        : "top",
		volume            : 70,
		autoPlay          : true,
		autoHideSkin      : false,
		skinFadeDelay     : 1000,
		beginPosterPath   : null,
		endPosterPath     : null,
		menu              : "false",
		wmode             : "transparent",
		skin              : "/flash/video/y2009/skins/mlb_media_landing.swf",
		fullscreenSkin    : null,		
		debugMode         : false,
		playlist          : [],
		self              : null,
		scale             : "noScale",
		adConfig          : "/shared/flash/video/ad_config.xml",  //runtime dart configuration class
		
		// freewheel config
		adManager           : "http://adm.fwmrm.net/p/mlb_live/AdManager.swf", // beta:"http://adm.fwmrm.net/p/mlb_test/AdManager.swf", prod:"http://adm.fwmrm.net/p/mlb_live/AdManager.swf", local:"/shared/flash/ads/video/freewheel/AdManager.swf"
		adRenderXML         : "/shared/flash/ads/video/freewheel/renderers.xml",
		adNetwork           : "",
		adServer            : "",
		adProfile           : "",
		siteSectionArray    : _getDefaultSiteSectionArray(),
		pageComponent       : "embed", // default pageComponent
		fwTestNetwork       : false, // (typeof isProd!=="undefined") ? !isProd : false, // if not prod, test network is true
		fallbackNetwork     : null,
		fallbackNetworkTest : null,
		isFreeWheelSite     : (_getAdNetwork()==="fw"),
		
		companionSize     : "",  //companion ad size. format: 300x250, 728x90, etc. leave "" if there is no companion ad
		autoRewind        :	true 
	};
	$.extend(_swfProps, props);  // override defaults with passed params
	
	
	// if siteSection wasn't set, set it
	if (!_swfProps.siteSection){
		_swfProps.siteSectionArray.push(_swfProps.pageComponent);
		_swfProps.siteSection = _swfProps.siteSectionArray.join("/");
	}

	
	/* priveledged methods */
	this.getPlaylist      = function(){ return _swfProps.playlist; };
	this.getDefaultVolume = function(){ return _swfProps.volume; };
	this.getStartObjSrc   = function(){ return this.startObjSrc; };
	this.getEndObjSrc     = function(){ return this.endObjSrc; };
	this.getSiteSection   = function(){ return _swfProps.siteSection; };  // for debuging
		

	/* public properties */
	this.swfElem         = null;  // DOM element containing SWF for this instance of FlvPlayer
	this.elemId          = _swfProps.elemId; // needed to expose this to public methods
	this.self            = props.self;
	this.container       = document.getElementById(props.containerId) || _makeContainer(props.containerId);
	this.startObjSrc     = props.startObjSrc  || null;
	this.endObjSrc       = props.endObjSrc    || null;
	this.hideControls    = props.hideControls || true;
	this.showCompanionAd = props.showCompanionAd || null;		
	this.debugMode       = props.debugMode    || false;	
	this.playerLoaded    = false;
	
	this.onPlayerLoaded = function(){
		_self.trigger("playerReady");
		var callback = props.onPlayerLoaded || function(){};
		callback();
	};
	
	this.playlistBegin = function(){
		_self.trigger("playlistBegin");
		var callback = props.onPlaylistBegin || function(){};
		callback();
	};
	
	this.contentStarted = function(){
		_self.trigger("contentStarted");
		var callback = props.contentStarted || function(){};
		callback();
	};
	
	this.onPlaylistComplete = function(){ 
		_self.trigger("playlistComplete");
		var callback = props.onPlaylistComplete || function(){};
		callback();
	};
	
	this.onCollapse = function(){
		_self.trigger("collapse");
		var callback = props.onCollapse || function(){};
		callback();
	};

	
	// ad playback events
	this.adPlaybackStart = props.adPlaybackStart || null;
	this.adPlaybackEnd   = props.adPlaybackEnd   || null;
	this.adOverlayStart  = props.adOverlayStart  || null;
	this.adOverlayEnd    = props.adOverlayEnd    || null;
	
	this.adPlatform = _swfProps.isFreeWheelSite ? "fw" : "dc"; // global preroll switch (fw/dc)


//	// iPad upsell handling
//	if	(bam.env && bam.env.client && bam.env.client.isIPad){
//		$(this.container)
//			.removeClass("collapsed")
//			.addClass("iPad") // for whatever
//			.css({"width":_swfProps.width+"px","height":_swfProps.height+"px"})
//			.html("<a href='/mobile/ipad/'>Click here to learn how you can watch video highlights on your iPad.</a>")
//			.find("a").css({"display":"block", "text-align":"center", "width":"180px", "text-decoration":"none","margin":(_swfProps.height/2-30)+"px auto 0 auto"});
//		return;
//	}

	// iPad html5 video
	if (_isIPad){
		this.setPlaylist = function(playlistArray){
			if (playlistArray.length){
				var videoTag = 	"<video id='vPlayer' width='"+_swfProps.width+"' height='"+_swfProps.height+"' controls='controls' autoplay='true'>" +
												"<source src='"+playlistArray[0].path+"' type='video/mp4'/>" + 
												"</video>",

                    containerHeight = _swfProps.height;

                // hack for video corner player controls
                if( _swfProps.pageComponent === "video_corner" ) {
                    containerHeight = parseInt( _swfProps.height, 10 ) + 25; // ipad controls are 25px high
                }

				$(this.container)
					.removeClass("collapsed")
					.css({"width":_swfProps.width+"px","height":containerHeight+"px"})
					.html(videoTag);
				_vPlayer = document.getElementById("vPlayer"); // $(this.container).find("video").get(0),
				_vPlayer.pause();
				_vPlayer.src = playlistArray[0].path;
				_vPlayer.load();
				$(_vPlayer).unbind("ended").bind("ended", function(){
					_self.onPlaylistComplete();
				});
				return true;
			}
			else {
				return false;
			}
		};
		
		this.startPlaylist = function(playlistArray){
			if (this.setPlaylist(playlistArray) && _vPlayer){
				_vPlayer.play();
			}
		};
		
		this.clearPlaylist  = function(){};
		this.exitFullScreen = function(){};		
		
		this.execute = function(){
			// @TODO implement this?
		}; 
		
		// force a delay to allow for instantiation of 
		setTimeout(this.onPlayerLoaded, 1000);
		return;
	}



	/* initialize SWFObject */
	try { 
		_swfObj = new SWFObject(_swfProps.file, _swfProps.elemId, _swfProps.width, _swfProps.height, _swfProps.flashVersion);
		// add params
		_swfObj.addParam("allowScriptAccess", _swfProps.allowScriptAccess);	
		_swfObj.addParam("allowFullScreen",   _swfProps.allowFullScreen);
		_swfObj.addParam("menu",              _swfProps.menu);
		_swfObj.addParam("wmode",             _swfProps.wmode);
		_swfObj.addParam("scale",             _swfProps.scale);
		_swfObj.addParam("align",             "top");
		
		/* add variables */
		_swfObj.addVariable("versionControl",  _swfProps.versionControl); // flv player version
		_swfObj.addVariable("isFreeWheelSite", _swfProps.isFreeWheelSite);
		
		if (_swfProps.salign !== null){          _swfObj.addVariable("salign",          _swfProps.salign); }
		if (_swfProps.videoAlign !== null){      _swfObj.addVariable("videoAlign",      _swfProps.videoAlign); }
		if (_swfProps.width !== null){           _swfObj.addVariable("matchWidth",      _swfProps.width); }
		if (_swfProps.height !== null){          _swfObj.addVariable("matchHeight",     _swfProps.height); }
		if (_swfProps.videoScaleMode !== null){  _swfObj.addVariable("videoScaleMode",  _swfProps.videoScaleMode); }
		if (_swfProps.volume !== null){          _swfObj.addVariable("volume",          _swfProps.volume); }
		if (_swfProps.autoPlay !== null){        _swfObj.addVariable("autoPlay",        _swfProps.autoPlay); }
		if (_swfProps.autoRewind !== null){      _swfObj.addVariable("autoRewind",      _swfProps.autoRewind); }
		if (_swfProps.autoHideSkin !== null){    _swfObj.addVariable("autoHideSkin",    _swfProps.autoHideSkin); }
		if (_swfProps.skinFadeDelay !== null){   _swfObj.addVariable("skinFadeDelay",   _swfProps.skinFadeDelay); }
		if (_swfProps.beginPosterPath !== null){ _swfObj.addVariable("beginPosterPath", _swfProps.beginPosterPath); }
		if (_swfProps.endPosterPath !== null){   _swfObj.addVariable("endPosterPath",   _swfProps.endPosterPath); }
		if (_swfProps.skin !== null){            _swfObj.addVariable("skin",            _getVersionSkin(_swfProps.skin)); }
		if (_swfProps.self !== null){            _swfObj.addVariable("instanceName",    _swfProps.self); }
		if (_swfProps.adConfig !== null){        _swfObj.addVariable("adConfigXML",     _swfProps.adConfig); }
		if (_swfProps.companionSize){            _swfObj.addVariable("companionSize",   _swfProps.companionSize); }
		if (_swfProps.fullscreenSkin !== null){  _swfObj.addVariable("fullscreenSkin",  _swfProps.fullscreenSkin); }

		// freewheel support.  pass if set.
		if (_swfProps.adManager){           _swfObj.addVariable("adManager",   _swfProps.adManager); }
		if (_swfProps.adNetwork){           _swfObj.addVariable("adNetwork",   _swfProps.adNetwork); }
		if (_swfProps.adServer){            _swfObj.addVariable("adServer",    _swfProps.adServer); }
		if (_swfProps.adProfile){           _swfObj.addVariable("adProfile",   _swfProps.adProfile); }
		if (_swfProps.siteSection){         _swfObj.addVariable("siteSection", _swfProps.siteSection); }

		if (_swfProps.fwTestNetwork){       _swfObj.addVariable("fwTestNetwork",       _swfProps.fwTestNetwork); }
		if (_swfProps.fallbackNetwork){     _swfObj.addVariable("fallbackNetwork",     _swfProps.fallbackNetwork); }
		if (_swfProps.fallbackNetworkTest){ _swfObj.addVariable("fallbackNetworkTest", _swfProps.fallbackNetworkTest); }
		
		_swfObj.write(this.container.id);
	}
	catch(e){ 
		throw new Error("SWFObject could not be instantiated.");
	}
	
};


/* public static methods */
bam.FlvPlayer.prototype = {
	
	logError: function(msg){
		if (this.debugMode){
			if (typeof console!="undefined"){ console.log(msg); }
			if (typeof flash_debugger!="undefined"){ flash_debugger.log(msg); }
		}		
	},
	
	getInstance: function(){
		this.logError("bam.FlvPlayer.getInstance: retrieving specific instance of flvplayer (elemId: " + this.elemId + ")");
		this.swfElem = document.getElementById(this.elemId);
	},
	
	
	/** 
	 * Generic handler for all supported swf (player) functions.
	 * Currently, the following functions are known to be supported:
	 * setPlaylist, startPlaylist, clearPlaylist, setPlaylistPostView, 
	 * addToPlaylist, removeFromPlaylist, setBeginPoster, setEndPoster
	 * @param {string} functionName
	 * @param {anything} params
	 */
	execute: function(functionName, params){
		this.logError("bam.FlvPlayer."+functionName+"() was called.");
		if (this.swfElem && this.swfElem[functionName]){
			if (typeof params !== "undefined"){
				this.swfElem[functionName](params);
			}
			else {
				this.swfElem[functionName]();
			}
		}
		else {
			throw new Error("bam.FlvPlayer.execute: Called with invalid function:" + functionName + ", or this.swfElem wasn't defined");
		}
	},

	
	/** 
	 * Provides backwards support for FlvPlayst 2.0 compatible playlist parameters.
	 * @param {array} playlist
	 */
	normalizePlaylist: function(playlist){
		this.logError("bam.FlvPlayer.normalizePlaylist()");
		var normalizedPlaylist = [],
				self = this;
		$.each(playlist, function(i, curItem){
			// skip newer playlist objects which shouldn't be normalized
			if (typeof curItem.stream!=="undefined" || typeof curItem.content_id!=="undefined"){ 
				self.logError("normalize added a stream or content_id equipped item.");
				normalizedPlaylist.push(curItem);
				return true; // if curItem was processed contine to avoid double processing
			}
			if (typeof curItem.prerollPath!=="undefined"){
				curItem.path = curItem.prerollPath;
			}
			if (typeof curItem.videoPath!=="undefined"){
				curItem.path = curItem.videoPath;
			}
			// do not normalize freewheelAd playlist items
			if ( (typeof curItem.type!=="undefined") && (curItem.type==="freewheelAd" || curItem.type==="video") ){
				self.logError("came accross freewheel ad or video. passing through.");				
				normalizedPlaylist.push(curItem);
				return true; // if curItem was processed contine to avoid double processing
			}
			else {
				self.logError("normalized current item.");
				normalizedPlaylist.push({type:curItem.type, path:curItem.path});
				return true; // if curItem was processed contine to avoid double processing
			}
		});
		return normalizedPlaylist;
	},


	/** execute method aliases **************************************/
	setPlaylist    : function(playlist){ this.execute("setPlaylist",   this.normalizePlaylist(playlist)); },
	startPlaylist  : function(playlist){ this.execute("startPlaylist", this.normalizePlaylist(playlist)); },
	stopPlaylist   : function()        { this.execute("stopPlaylist"); },
	clearPlaylist  : function()        { this.execute("clearPlaylist"); },
	
	setBeginPoster : function(path){ this.execute("setBeginPoster", path); },
	setEndPoster   : function(path){ this.execute("setEndPoster",   path); }
};


$.bindable(bam.FlvPlayer, "playerReady playlistBegin contentStarted playlistComplete collapse");
