/*
    Company    : Bionic Communications Ltd
    Document   : disneyj_videoHub.js
    Author     : geveritt
    Email      : geoff.everitt@bionic-comms.co.uk
    Description:
    Requirements: 
    	JQUERY-1.5
*/

/*
 * notes:
 * 
 */

/* ----------------------------------------------------------------
 * PACKAGE DEFINITION
 * ---------------------------------------------------------------*/

var namespace = function() {
	var a=arguments, o=null, i, j, d;
    for (i=0; i<a .length; i=i+1) {
        d=a[i].split(".");
        o=window;
 
        for (j=0; j<d.length; j=j+1) {
            o[d[j]]=o[d[j]] || {};
            o=o[d[j]];
        }
    }
    return o;
};

/* create global videoHub namespace */
namespace("com.bionic.disney.videohub");
namespace("com.bionic.disney.videohub.players");

/* ----------------------------------------------------------------
 * CLASSES
 * ---------------------------------------------------------------*/

/* ----------------------------------------------------------------
 * com.bionic.Logger
 * ---------------------------------------------------------------*/
com.bionic.Logger = function(){
	var __this__ = this;
	var logging = true;
	this.log = function(msg){
		try{
			console.log("[DEBUG] "+msg);
		}catch(e){
			return;
		}
	};
};

/* ----------------------------------------------------------------
 * com.bionic.disney.videohub.PlayerHelper
 * ---------------------------------------------------------------*/
com.bionic.disney.videohub.PlayerHelper = function(root){
	var __this__ = this;
	__this__.logger = new com.bionic.Logger();
	var logging = true;
	
	var applicationUrlRoot = root;
	var videoRelativeRoot = "/cms_res/disney-junior/video/";
	
	__this__.postProcessVideoPath = function(path){
		var finalPath = '';
		if (path){
			if (path.substring(0,1)=='/'){
				/* assume path is relative to web root already*/
				finalPath = applicationUrlRoot+path;
			}else if(path.substring(0,4)=='http'){
				/* assume path is a full url - do nothing */
				finalPath = path;
			}else{
				/* assume path is nothing more then the image name and extension,
					so generate relative path path
				*/
				if (path.substring(path.length-1,path.length)=='/'){
					path = path.substring(0,path.length-1);
				}
				if (applicationUrlRoot.substring(applicationUrlRoot.length-1,applicationUrlRoot.length)=='/'){
					applicationUrlRoot = applicationUrlRoot.substring(0,applicationUrlRoot.length-1);
				}
				finalPath = applicationUrlRoot+"/cms_res/disney-junior/video/"+path;
			}
		}
		return finalPath;
	}
	
}

/* ----------------------------------------------------------------
 * com.bionic.disney.videohub.Configuration
 * 	- properties used to create new instance of a 
 * 	com.bionic.disney.videohub.players implementation
 * ---------------------------------------------------------------*/
com.bionic.disney.videohub.Configuration = function(){
	var __this__ = this;
	/* properties */
	__this__.applicationRoot = '';
	__this__.vPaidXML = '';
	__this__.vPaidVideoPlayerName = '';
	__this__.htmlContainerName = '';
	__this__.firstVideoSource = '';
	__this__.skinXML = '';
	__this__.playerWidth = '';
	__this__.playerHeight = '';
	__this__.loop = false;
	__this__.autoplay = false;
	__this__.controlBarMode = 'docked';
	__this__.poster = null;
	__this__.poster = null;
	__this__.rtmpeServer = '';
	/* ---------- */
}


/* ----------------------------------------------------------------
 * com.bionic.disney.videohub.players.FlashPlayer
 * ---------------------------------------------------------------*/
com.bionic.disney.videohub.players.FlashPlayer = function(config, flashPlayerImplSwf, flashPlayerImplRoot){
	var __this__ = this;
	__this__.logger = new com.bionic.Logger();
	var logging = true;
	var events = new Array();
	__this__.config = config;
	
	/* called when flash tells us the player is alive via javascriptCallbackFunction (in flashvars) */
	__this__.javascriptBridgeCallback = function(playerId){
		if (__this__.livePlayer == null || __this__.livePlayer == 'undefined') {
			__this__.livePlayer = document.getElementById(playerId);
			if (__this__.livePlayer==null){return;}
			
			/* bind events */
			__this__.logger.log("com.bionic.disney.videohub.players.FlashPlayer::javascriptBridgeCallback() binding events...");
			for (var i in events) {
				__this__.logger.log("		addEventListener('"+i+"', '"+events[i]+"'])");
				__this__.livePlayer.addEventListener(i, events[i]);
			}
			
			/* trigger playerIsLive event */
			// FIXME I would like to actually trigger this event rather then call the handler but it isn't working correctly.
			window[events['playerIsLive']](__this__.livePlayer);
		}
	}
	
	var contructor = function(){
		__this__.playerHelper = new com.bionic.disney.videohub.PlayerHelper(__this__.config.applicationRoot);
		__this__.embedded = false;
		__this__.lastSetMediaResource = null;
		__this__.currentVideoOffset = null;
		__this__.currentVideoLength = null;
		__this__.videoPlaying = false;
		__this__.livePlayer = null;
		
		// create global onJavaScriptBridgeCreated callback...
		// FIXME this is destructive!
		window.onJavaScriptBridgeCreated = function(playerId){
			__this__.javascriptBridgeCallback(playerId);
		}
		
	}(); /* end constructor */
	
	
	__this__.registerGlobalEventCallback = function(callback, event){
		events[event] = callback;
	}
	
	__this__.embed = function(){
		
		if (__this__.embedded == true){
			__this__.logger.log("WARNING com.bionic.disney.videohub.players.FlashPlayer::embed() called when already embedded.");
			return;
		}
		
		var firstVideoSrc = config.firstVideoSource
		if (__this__.config.rtmpeServer=='' || __this__.config.rtmpeServer == null){
			firstVideoSrc = __this__.playerHelper.postProcessVideoPath(config.firstVideoSource);
		}
		__this__.logger.log("com.bionic.disney.videohub.players.FlashPlayer::embed() with source: '"+firstVideoSrc+"'");
		
		var flashvars = {
			src: firstVideoSrc,
			path: flashPlayerImplRoot,
			loop: __this__.config.loop,
			autoPlay: __this__.config.autoplay,
			controlBarMode: __this__.config.controlBarMode,
			controlBarAutoHide: true,
			/* this seems to need to be on the window object  */
			javascriptCallbackFunction: "onJavaScriptBridgeCreated",
			skin: config.skinXML,
			/* 12 May --- Martin */
			player_name: __this__.config.vPaidVideoPlayerName,
			adserver_xml:__this__.config.vPaidXML,
			rtmpe_server:__this__.config.rtmpeServer
		};
		
		if (__this__.config.poster != null){
			flashvars.push("poster",__this__.config.poster);
		}
		
		var params = {
			menu: "false",
			scale: "noScale",
			allowFullscreen: "true",
			allowScriptAccess: "always",
			bgcolor: "#FFFFFF",
			wmode: "opaque"
		};
		
		var attributes = {
			/* setting these ensures that the id id passed through to the js callback */
			id:config.htmlContainerName,
			name:config.htmlContainerName
		};
		
		/* swfobject embed call */
		__this__.logger.log("com.bionic.disney.videohub.players.FlashPlayer::embed() making swfobject.embedSWF call... ");
		swfobject.embedSWF(flashPlayerImplSwf, config.htmlContainerName, config.playerWidth+"px", config.playerHeight+"px", "10.1.0","/cms_inc/disney-junior/js/expressInstall.swf", flashvars, params, attributes);
		
		__this__.lastSetMediaResource = firstVideoSrc;
		__this__currentVideoOffset = 0;
		__this__.embedded = true;
	}
	
	__this__.playNewVideo = function(videoSource){
		var videoSrc = videoSource;
		if (__this__.config.rtmpeServer=='' || __this__.config.rtmpeServer == null){
			videoSrc = __this__.playerHelper.postProcessVideoPath(videoSource);
		}
		__this__.logger.log("com.bionic.disney.videohub.players.FlashPlayer::playNewVideo() with source: '"+videoSrc+"'");
		try{
			__this__.livePlayer.setMediaResourceURL(videoSrc);
			__this__.lastSetMediaResource = videoSrc;
		}catch(e){
			logger.log("com.bionic.disney.videohub.players.FlashPlayer::playNewVideo() ERROR! failed to update media player resource url");
		}
	}
	
	return;
}


/* ----------------------------------------------------------------
 * com.bionic.disney.videohub.players.Html5Player
 * ---------------------------------------------------------------*/
com.bionic.disney.videohub.players.Html5Player = function(config){
	
	var __this__ = this;
	__this__.logger = new com.bionic.Logger();
	var logging = true;
	__this__.config = config;
	var events = new Array();
	
	__this__.javascriptBridgeCallback = function(playerId){
		if (__this__.livePlayer == null || __this__.livePlayer == 'undefined') {
			
			
			__this__.livePlayer = document.getElementById(playerId);
			if (__this__.livePlayer==null){return;}
			
			// NOTE: possible ipad bugfix
			var src = $(__this__.livePlayer).attr('src');
			__this__.livePlayer.src = src;
			
			// add getState() method to __this__.livePlayer so we have a common interface (matching flash)
			__this__.livePlayer.getState = function(){
				var state = __this__.livePlayer.state;
				if (state=='undefined' || state==null){
					state = 'notset';
				}
				return state;
			}
			
			// add getMuted() method to __this__.livePlayer so we have a common interface (matching flash)
			__this__.livePlayer.getMuted = function(){
				var muted = false;
				if (__this__.livePlayer.muted == true || __this__.livePlayer.muted == false){
					muted = __this__.livePlayer.muted;
				}
				return muted;
			}
			// add play2 method to __this__.livePlayer so we have a common interface (matching flash)
			__this__.livePlayer.play2 = function(){
				__this__.livePlayer.play();
			}
			// add setMuted method to __this__.livePlayer so we have a common interface (matching flash)
			__this__.livePlayer.setMuted = function(state){
				__this__.livePlayer.muted = state;
			}
			
			
			/*
			 * -- FIXME ipad doesn't support native autoplay 
			 * and infact doing this seems to utterly break the player
			 * experiment with it later
			$(__this__.livePlayer).ready(function(){
		       	if (__this__.config.autoplay){
	            	__this__.livePlayer.load();
	            	__this__.livePlayer.play();
	        	}
			});
			*/
			
			// bind internal events
			// additionally create custom mediaPlayerStateChange event using native events: play and pause
			$(__this__.livePlayer).bind("play", function(){
				__this__.livePlayer.state = 'playing';
				$(__this__.livePlayer).trigger("mediaPlayerStateChange");
			});
			$(__this__.livePlayer).bind("pause", function(){
				__this__.livePlayer.state = 'paused';
				$(__this__.livePlayer).trigger("mediaPlayerStateChange");
			});
			
			// bind user events
			// NOTE: html5 event names are different to flash so they need re-mapping
			__this__.logger.log("com.bionic.disney.videohub.players.Html5Player::javascriptBridgeCallback() binding events...");
						
			
			/* 
			 * event mapping from flash to html5:
			 * 
			 * mediaPlayerStateChange => custom from play and pause
			 * complete => ended
			 * mutedChange => custom from volumechange
			 * currentTimeChange => timeupdate
			 * durationChange => durationchange
			 */
			
			for(var i=0; i<events.length; i++) {
				
				var eventWrapper = events[i];
				var event = eventWrapper.event;
				var handler = eventWrapper.handler;
				
				if (event=='mediaPlayerStateChange'){
					
					__this__.logger.log("		bind('mediaPlayerStateChange', '"+handler+"'])");
					
					$(__this__.livePlayer).bind("mediaPlayerStateChange",{handler:handler},function(e){
						window[e.data.handler](__this__.livePlayer.state);
					});
					
				}else if (event=='durationChange'){
					
					__this__.logger.log("		bind('durationchange', '"+handler+"'])");
					
					var eventData = jQuery.extend(true, {}, __this__.livePlayer); // deep copy
					eventData.handler = handler;
					$(__this__.livePlayer).bind("durationchange",eventData,function(e){
				        var duration = e.data.duration
				        var offset =  e.data.currentTime;
						window[e.data.handler](duration);
					});
					
				}else if (event=='complete'){

					__this__.logger.log("		bind('ended', '"+handler+"'])");
					
					var eventData = jQuery.extend(true, {}, __this__.livePlayer); // deep copy
					eventData.handler = handler;
					$(__this__.livePlayer).bind("ended",eventData,function(e){
						window[e.data.handler]();
					});
					
				}else if (event=='currentTimeChange'){

					__this__.logger.log("		bind('timeupdate', '"+handler+"'])");
					
					var eventData = jQuery.extend(true, {}, __this__.livePlayer); // deep copy
					eventData.handler = handler;
					$(__this__.livePlayer).bind("timeupdate",eventData,function(e){
					    if (e.data.sliding) {
					    	return;
				        }
				        var duration = e.data.duration
				        var offset =  e.data.currentTime;
						window[e.data.handler](offset);
					});
				}
				
				
				// NOTE muting does not work at all on IOS platforms, volume is read-only
				/*
				if (i=='mutedChange'){
					var event = i;
					var handler = events[i];
					__this__.logger.log("		bind('mutedChange', '"+events[i]+"'])");
					$(__this__.livePlayer).bind("mutedChange",function(){
						window[handler](__this__.livePlayer.state);
					});
					
					$(__this__.livePlayer).bind("volumechange", function(event){
						
			            if (event.data.player.muted) {
			            	// muted!
			            	window[handler](true);
			            }else{
			            	// not muted!
			            	window[handler](false);
			            }
					});
					continue;
				}
				*/
			}
			
			// trigger playerIsLive event 
			// FIXME I would like to actually trigger this event rather then call the handler but it isn't working correctly.
			for(var i=0; i<events.length; i++) {
				var eventWrapper = events[i];
				var event = eventWrapper.event;
				var handler = eventWrapper.handler;
				
				if (event=='playerIsLive'){
					window[handler](__this__.livePlayer);
					break;
				}
			}
		}
	}
	
	var contructor = function(){
		__this__.playerHelper = new com.bionic.disney.videohub.PlayerHelper(__this__.config.applicationRoot);
		__this__.embedded = false;
		__this__.lastSetMediaResource = null;
		__this__.currentVideoOffset = null;
		__this__.currentVideoLength = null;
		__this__.videoPlaying = false;
		__this__.livePlayer = null;
	}();
	
	__this__.registerGlobalEventCallback = function(callback, event){
		var eventWrapper = new Object();
		eventWrapper.event = event;
		eventWrapper.handler = callback;
		events.push(eventWrapper);
	}
	
	__this__.embed = function(){
		if (__this__.embedded == true){
			__this__.logger.log("WARNING com.bionic.disney.videohub.players.Html5Player::embed() called when already embedded.");
			return;
		}
		
		var firstVideoSrc = __this__.playerHelper.postProcessVideoPath(config.firstVideoSource);	
		__this__.logger.log("com.bionic.disney.videohub.players.Html5Player::embed() with source: '"+firstVideoSrc+"'");
		
		// embed html5 video element with attrs according to config
		var $video = $("<video></video>");
		$video.attr("id", "videoPlayer");
        //$video.attr("class", "smp_video");
        $video.attr("preload", "none");
        $video.attr("width", __this__.config.playerWidth);
        $video.attr("height", __this__.config.playerHeight);
        $video.attr("src", firstVideoSrc);
        $video.attr("type", "video/mp4");
		
		if (__this__.config.loop){
			$video.attr("loop", "loop");
		}
		if (__this__.config.autoplay){
			$video.attr("autoplay", "autoplay");
		}
		if (__this__.config.controlBarMode != "none"){
			$video.attr("controls", "controls");
		}
		if  (__this__.config.poster != ""){
			$video.attr("poster", __this__.config.poster);
		}
      
        $("#"+__this__.config.htmlContainerName).replaceWith($video);
        
        // FIXME is this required? whats the story with this?
        /*
        var $video_src = $("<source></source>");
        $video_src.attr("src", firstVideoSrc);
        $video_src.attr("type", "video/mp4");
        $("#videoPlayer").append($video_src);
        */
        
        // call __this__.javascriptBridgeCallback
        __this__.javascriptBridgeCallback("videoPlayer");
	}
	
	__this__.playNewVideo = function(videoSource){
		var videoSrc = __this__.playerHelper.postProcessVideoPath(videoSource);	
		__this__.logger.log("com.bionic.disney.videohub.players.Html5Player::playNewVideo() with source: '"+videoSrc+"'");
		try{
			$("#videoPlayer").attr("src",videoSrc);
        	__this__.livePlayer.load();
        	__this__.livePlayer.play();
			__this__.lastSetMediaResource = videoSrc;
		}catch(e){
			logger.log("com.bionic.disney.videohub.players.Html5Player::playNewVideo() ERROR! failed to update media player resource url");
		}
	}
}

/* ----------------------------------------------------------------
 * com.bionic.disney.videohub.Playlist
 * TODO
 * 	- for now this is just a wrapper around my cookie handling functions
 * ---------------------------------------------------------------*/
com.bionic.disney.videohub.Playlist = function(){
	var __this__ = this;
	__this__.logger = new com.bionic.Logger();
	__this__.cookieName = "disneyjPlaylist";
	__this__.cookieLife = "365"; // in days
	
	var logging = true;
	
	function createCookie(name,value,days) {
		value = encodeURIComponent(value);
		if (days) {
			var date = new Date();
			date.setTime(date.getTime()+(days*24*60*60*1000));
			var expires = "; expires="+date.toGMTString();
		}
		else var expires = "";
		document.cookie = name+"="+value+expires+"; path=/";
	}
	function readCookie(name) {
		var nameEQ = name + "=";
		var ca = document.cookie.split(';');
		for(var i=0;i < ca.length;i++) {
			var c = ca[i];
			while (c.charAt(0)==' ') c = c.substring(1,c.length);
			if (c.indexOf(nameEQ) == 0){
				var cookieString = c.substring(nameEQ.length,c.length);
				cookieString = decodeURIComponent(cookieString);
				return cookieString;
			}
		}
		return '';
	}
	function eraseCookie(name) {
		createCookie(name,"",-1);
	}
	
	/*
	 * - this does not prevent duplicates from being added
	 */
	this.addToPlaylistCookie = function(item_id){
		var existing_value = readCookie(this.cookieName);
		var new_value = null;
		if (existing_value!=null && existing_value!=''){
			new_value = existing_value+","+item_id;
		}else{
			new_value = item_id;
		}
		eraseCookie(this.cookieName);
		createCookie(this.cookieName,new_value,this.cookieLife);
		__this__.logger.log("disneyj_playlist cookie:["+new_value+"]");
		return;
	}
	
	/* returns an array containing each item name */
	this.getPlayList = function(){
		var cookieString = readCookie(this.cookieName);
		__this__.logger.log("getPlayList read raw cookie:["+cookieString+"]");
		
		if (cookieString==null || cookieString==''){
			return new Array();
		}
		
		// strip leading commas in cookieString
		if (cookieString.substring(0,1)==','){
			cookieString = cookieString.substring(1,cookieString.length);
		}
		// explode cookieString into array
		var playListArray = cookieString.split(",");
		__this__.logger.log("getPlayList returning:["+playListArray+"]");
		return playListArray;
	}
	
	
	this.deletePlaylist = function(){
		eraseCookie(this.cookieName);
	}
	

	this.deleteFromPlayListCookie = function(item_id){
		if (item_id==null || item_id ==''){
			__this__.logger.logger.log("warning: nothing passed to deleteFromPlayListCookie()");
			return;
		}
		var playlist = this.getPlayList();
		var newPlaylist = new Array();
		for (var i=0; i<playlist.length;i++){
			if (playlist[i]!=item_id){
				__this__.logger.log(playlist[i]+ " is not "+item_id);
				newPlaylist.push(playlist[i]);
			}
		}
		var value = newPlaylist.join(",");
		
		eraseCookie(this.cookieName);
		createCookie(this.cookieName,value,this.cookieLife);
		
		__this__.logger.log("disneyj_playlist cookie:["+value+"]");
		return;
	}

	this.rebuildPlaylist = function(newArray){
		this.deletePlaylist();
		for (var i=0;i<newArray.length;i++){
			this.addToPlaylistCookie(newArray[i]);
		}
	}
	
}


