/**
 * bam.FlvPlayer - Instantiatable Flash Video Player.
 *
 * @author Aleksandar Kolundzija
 * @version 3.3.0
 * - now triggers custom events (see bottom)
 * - now supports HTML5 video for iPad
 *
 * 3.3.1 update notes:
 * @author Jon Ferrer <jon.ferrer@mlb.com>
 * - update skinFadeDelay to 2 sec. SWF expects seconds not milliseconds
 *
 * @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){

    function hashKeys(hash) {
        var keys = [],
            key;

        for (key in hash) {
            if (hash.hasOwnProperty(key)) {
                keys.push(key);
            }
        }

        return keys;
    }
		
	// private members
	var _swfObj, // will store SWFObject for this FlvPlayer

            FREEWHEEL_ID    = "fw",
            DOUBLECLICK_ID  = "dc",
            AUDITUDE_ID     = "auditude",

            _auditudeZones  = {
                mlb : 50389,
                milb : 51232,
                minorleaguebaseball : 51232,
				venue365: 52920,
				webbyawards: 52920,
                theabl : 51231,
                yesnetwork : 51233,
                sny : 51234,
                tigerwoods : 51235,
                icenetwork : 51236,
				// gbtv : 104599
               // external : 51237
			   placeholder : null
            },

            _auditudeSites  = hashKeys(_auditudeZones), // domains which support Auditude

			_fwSites        = [/*"sny","yesnetwork","tigerwoods","theabl"*/], // domains which support FreeWheel

            // create unique instance reference that SWF for JS access
            _selfName       = "flvplayer_" + new Date().valueOf(),
            _publicSelfName = "bam.FlvPlayer.instances." + _selfName,

			_self           = bam.FlvPlayer.instances[_selfName] = this,
			
			// iPad support vars
            _isHTMLVideoDevice = (bam.env && bam.env.client && (bam.env.client.isIPhone || bam.env.client.isIPad || bam.env.client.isXoom)),
			_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("."),
            comPos  = $.inArray("com", hostArr);
        (comPos > 0 && comPos!==hostArr.length-1) && hostArr.pop(); // if .com is followed by anything, remove that thing
		return hostArr[hostArr.length-2] || "mlb";
	}
	
	
	/**
	 * Private method for retrieving ad network  based a on domain lookup.
	 * @return string "fw" or "dc"
	 */
	function _getAdNetwork(){
        var domain = _getDomain(),
            adNetworkID = DOUBLECLICK_ID;

		if ($.inArray(domain, _fwSites)>-1) { 
            adNetworkID = FREEWHEEL_ID; 
        } else if ($.inArray(domain, _auditudeSites)>-1) { 
            adNetworkID = AUDITUDE_ID; 
        }

        return adNetworkID;
	}
	
	
	/** 
	 * 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_v4.swf?v=6",
		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     : 7,
		beginPosterPath   : null,
		endPosterPath     : null,
		stageVideoEnabled : false,
		menu              : "false",
		wmode             : "transparent",
		skin              : "/flash/video/y2009/skins/mlb_media_landing.swf",
		skinConfigURL     : "/shared/flash/video/skins/skin_config.xml", // default skin configuration
		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()===FREEWHEEL_ID),
        
        // Auditude Config
		isAuditudeSite    : (_getAdNetwork()===AUDITUDE_ID),
        auditudeZoneId    : _auditudeZones[_getDomain()],   
        auditudeVersion   : "mlb-2.0",
        auditudeDomain    : "auditude.com",
        auditudeSwfDomain : "auditude.com",
		
		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

    // override self property with public reference to instance of bam.FlvPlayer
    _swfProps.self = _publicSelfName;
	
	
	// 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.publicInstanceName = _swfProps.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.companionAd        = props.showCompanionAd || null;		

    if (props.showDefaultCompanionAd) {
        this.showDefaultCompanionAd = $.proxy(props.showDefaultCompanionAd, this);
    }

	this.debugMode          = props.debugMode    || false;	
	this.playerLoaded       = false;
	
	this.onPlayerLoaded = function(){
		_self.trigger("playerReady");
		var callback = props.onPlayerLoaded || function(){};
		callback();
	};
	
	this.onPlaylistBegin = 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;
	
    // global preroll switch (auditude/fw/dc)
    if (_swfProps.isAuditudeSite) {
        this.adPlatform = AUDITUDE_ID;
    } else if (_swfProps.isFreeWheelSite) {
        this.adPlatform = FREEWHEEL_ID;
    } else {
        this.adPlatform = DOUBLECLICK_ID;
    }


//	// 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;
//	}

	// html5 video support
	if (_isHTMLVideoDevice){
		this.setPlaylist = function(playlistArray){
			if (playlistArray.length){
				var videoTag = 	"<video id='vPlayer' width='"+_swfProps.width+"' height='"+_swfProps.height+"' controls='controls' autoplay='true' poster='" + _swfProps.beginPosterPath + "'>" +
												"<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);
        _swfObj.addVariable("instanceName",   _swfProps.self);
		
        // add Auditude flash vars
        if (_swfProps.isAuditudeSite) {
            _swfObj.addVariable("isAuditudeSite",    _swfProps.isAuditudeSite);
            _swfObj.addVariable("auditudeZoneId",    _swfProps.auditudeZoneId);
            _swfObj.addVariable("auditudeVersion",   _swfProps.auditudeVersion);
            _swfObj.addVariable("auditudeDomain",    _swfProps.auditudeDomain);  
            _swfObj.addVariable("auditudeSwfDomain", _swfProps.auditudeSwfDomain);
        }

		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.stageVideoEnabled !== null){   _swfObj.addVariable("stageVideoEnabled",   _swfProps.stageVideoEnabled); }		
		if (_swfProps.skin !== null){            _swfObj.addVariable("skin",            _getVersionSkin(_swfProps.skin)); }
		if (_swfProps.skinConfigURL !== null){   _swfObj.addVariable("skinConfigURL",   _swfProps.skinConfigURL); }
		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); }

        // league for MiLB supprot
		if (_swfProps.league !== null){  _swfObj.addVariable("league",  _swfProps.league); }

		// 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.");
	}
	
};

bam.FlvPlayer.instances = {};


/* public static methods */
bam.FlvPlayer.prototype = {
	
    // auditude default companion ad override
    showDefaultCompanionAd : function() {

        bam.loadSync(bam.homePath + "bam.url.js");

        var 
        location = bam.url.Location(window.location),
        club = (location.getParam("c_id")) ? location.getParam("c_id") : "mlb",
        clubAdPrefix = {
            mlb : 'mlb',
            ana : 'angels',
            hou : 'astros',
            oak : 'athletics',
            tor : 'bluejays',
            atl : 'braves',
            mil : 'brewers',
            stl : 'cardinals',
            chc : 'cubs',
            ari : 'diamondbacks',
            la : 'dodgers',
            sf : 'giants',
            cle : 'indians',
            sea : 'mariners',
           // fla : 'marlins',
			mia : 'marlins',
            nym : 'mets',
            was : 'nationals',
            bal : 'orioles',
            sd : 'padres',
            phi : 'phillies',
            pit : 'pirates',
            tex : 'rangers',
            tb : 'rays',
            cin : 'reds',
            bos : 'redsox',
            col : 'rockies',
            kc  : 'royals',
            det : 'tigers',
            min : 'twins',
            cws : 'whitesox',
            nyy : 'yankees'
        },
        adURL = "http://ad.doubleclick.net/adi/" + clubAdPrefix[club] + ".mlb/multimedia;sz=300x250;ord=" + (Math.random() * 1000000000000);
        width = 300;
        height = 250;
        iframeHTML = '<iframe src="' + adURL + '" frameborder="0" scrolling="0" style="width:' + width + 'px;height:' + height + 'px;"></iframe>';
        
        this.showCompanionAd([{
            data : iframeHTML,
            width : width,
            height : height
        }]);
    },

	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");

