/**
 * CastFire Javascript player.
 * (c) CastFire.com 2009
 * @author Ivan Kirnev <ivan@castfire.com>
 */

var CastfirePlayer = { version: "1.0" };
// Extending CastfirePlayer
$J.extend(true, CastfirePlayer, {
	players: [],        // list of registered players

	// Creates new player instance
	createPlayer: function(conf) {
		var player = this.getPlayer(conf.playerID);
		if (!player) {
			player = new castfire_player(conf);
			// registering new player
			this.players.push(player);
			player.create();
		}
		return player;
	},

	releasePlayer: function(playerId) {
		var p = this.getPlayer(playerId);
		if (p) { this.players.remove(p); }
	},

	getPlayer: function(playerId) {
		for (var i = 0, len = this.players.length; i < len; i++) {
			if (this.players[i].id === playerId) { return this.players[i]; }
		}
		return null;
	}
});

// =============================================
// Player
// =============================================
/**
 * Constructor of player instance
 * @param conf configuration parameters
 */
function castfire_player(conf) {
	// private member: storing initial configuration values
	this.initConf = conf;
	// player id
	this.id = conf.playerID;
	this.guid = conf.playerGuid || this.playerGuid;
	this.scrollType = conf.scrollType || this.scrollType;
	this.scrollSpeed = conf.scrollSpeed || this.scrollSpeed;
	this.rows = conf.rows || this.rows;
	this.mediaTemplateURL = conf.mediaTemplateURL || this.mediaTemplateURL;
	this.queueCaption = this.queueCaption || "Queue";
	this.playerInstance = null;
	this.embedID = "castfire_player-" + this.id;
	this.embedSRC = "http://p.castfire.com/" + this.guid + "/video/unloaded";
	this.browseId = 'cfp-tabs-browse'; // div Id of player's browse button object
	this.queueId = 'cfp-tabs-queue'; // div Id of player's queue button object
	this.tabInfos = {};     // helper object for internal usage
	this.selectedTabIdx = 0;
	this.selectedRightTabIdx = 0;
	this.selectedRightTabName = null;
	this.playlists = {};
	this.queueData = { shows: [], sources: [] };		// creating an empty queue
	this.currentPlayList = null;
	this.currentShow = null;
	this.isInited = false;
};

// Extending castfire_player class with members and methods
$J.extend(true, castfire_player.prototype, {
	/**
	 * Shows player object
	 */
	show: function() {
		$J('#' + this.id).show();
	},

	/**
	 * Hides player object
	 */
	hide: function() {
		$J('#' + this.id).hide();
	},

	create: function() {
		var player = this;	
		// init callback
		castfire_videoComplete = function(url){player.onCompleteMedia(url)};
		
		this.hide();
		$J('#' + this.id).load(this.mediaTemplateURL + " #template-container", 
			(function(player) {
					return function() {
						player.init();
			}}) (this)
		);
	},
	
	init: function() {

		var player = this;	
		this.render();
		if(this.initConf.dropdown){
			$J("#" + this.id + " #myselectbox").selectbox();
		}
		$J("#" + this.id + " .__playlist-container .__playlist-template").hide();
		this.show();

		this.playerInstance = this.getPlayerInstance(this.embedID);
		
		this.leftTabsWidth = 20;
		var tabEls = $J("#" + this.id + " .__topnavigation li").each(function(i){
			var tabId = player.id + '-cfp-tabs-' + i;
			var tabEl = $J(this);
			tabEl.attr("id", tabId).hover(
				function () { if (!$J(this).hasClass("__active")) { $J(this).addClass("__hover"); } },
				function () { $J(this).removeClass("__hover"); }
			).click(
				(function(player, tabId) {
					return function() {
						if(player.initConf.dropdown){
							$J($J("#" + player.id + " #myselectbox"+"_container ul li")[0]).click();
						}
						player.onTabClicked(tabId); 
					}}) (player, tabId)
			);

			player.tabInfos[tabId] = {
				index: i, 
				width: tabEl.outerWidth(true), 
				cfg: player.initConf.tabs[i],
				_default: player.initConf.tabs[i]['default']
			};
			player.leftTabsWidth += tabEl.outerWidth(true);
		});

		if($J("#" + this.id + " .__scrollTabs").divScroll){
			var divScroll = $J("#" + this.id + " .__scrollTabs").divScroll({
				scrollType: "horizontal",
				//width: this.playerWidth, 
				scrollWidth: this.leftTabsWidth,
				scrollSpeed: this.scrollSpeed,
				scrollWrapper: "div.__scrollWrapper",
				scrollerBack: "div.__scrollLeft",
				scrollerForward: "div.__scrollRight",
				classScrollerDisabled: "__x-item-disabled",
				classScrollerBackHover: "",
				classScrollerForwardHover: ""
			});
		}
		if(this.initConf.dropdown){
			var selOts = $J("#" + this.id + " #myselectbox").change(
					(function(player) {
						return function() {
						if(this.value == "0") return;
						var tabId = player.id + '-cfp-tabs-' + this.value;
						player.onTabClicked(tabId); }}) (this)
				)[0].options;

			for (var i = 0, len = selOts.length; i < len; i++) {
				var tabId = this.id + '-cfp-tabs-' + (tabEls.length + i);
				var tabEl = $J(selOts[i]);
				// set an id
				tabEl.attr("id", tabId);
				
				this.tabInfos[tabId] = {
					index: tabEls.length + i, 
					width: 0, 
					cfg: this.initConf.dropdown[i]
				};
			}
		}
		// counting tabs total width to show/hide scrollers
		tabEls = $J("#" + this.id + " .__videonavigation li");
		for (var i = 0, len = tabEls.length; i < len; i++) {
			var tabEl = $J(tabEls.get(i));
			var tabId = tabEl.attr("id");
			tabEl.hover(
				function () { if (!$J(this).hasClass("__active")) { $J(this).addClass("__hover"); } },
				function () { $J(this).removeClass("__hover"); }
			).click(
				(function(player, tabId) {
					return function() { player.onRightTabClicked(tabId); }}) (this, tabId)
			);
			this.tabInfos[tabId] = { index: i, width: tabEl.width()};
		}
		
		// seting active tab
		this.onTabClicked(this.id + '-cfp-tabs-' + this.selectedTabIdx);
		this.selectedRightTabName = this.browseId;
		this.isInited = true;
	},

	render: function() {

		//fix for IE[7,8]
		var pcr = $J('#' + this.id + ' .__player-container');
		if(pcr[0]){
			pcr[0].innerHTML = pcr[0].innerHTML
				.replace(/{embed_id}/ig, this.embedID)
				.replace(/{embed_src}/ig, this.embedSRC)
				.replace(/%7Bembed_src%7D/ig, this.embedSRC);
		}
		/*$J('#' + this.id + ' .__player-container object').render({
			'embed_id': this.embedID,
			'embed_src': this.embedSRC
		});*/
		
		
		var tabs = this.initConf.tabs;
		var arrRender = new Array();
		for (var i = 0, len = tabs.length; i < len; i++) {
			if(!tabs[i] || !tabs[i].name || !tabs[i].feed) continue;
			var parts = /^([^ ]*) ?(.*)?$/i.exec( tabs[i].name );
			arrRender.push({
				'word1': parts[1],
				'word2': parts[2] || "",
				'class': tabs[i]['class'] || "_"
			});
			if (tabs[i]['default']) { this.selectedTabIdx = i; }
		}
		$J('#' + this.id + ' .__topnavigation li').render(arrRender, {clone:true});
		
		var dropdown = this.initConf.dropdown;
		if(dropdown){
			var selVal = 0;
			arrRender = [
				{
					'value': 0,
					'inner': "More Channels"
				}
			];
			for (var i = 0, len = dropdown.length; i < len; i++) {
				if(!dropdown[i] || !dropdown[i].name || !dropdown[i].feed) continue;
				arrRender.push({
					'value': (tabs.length + i),
					'inner': dropdown[i].name
				});
				if (dropdown[i]['default']) { 
					this.selectedTabIdx = tabs.length + i; 
					selVal = tabs.length + i;
				}
			}
			$J("#" + this.id + " #myselectbox option").render(arrRender, {clone:true})
				.parent().val(selVal);
		}
	},
	getPlayerInstance: function (id){	
		if(document.embeds[(id)])return document.embeds[id];
		if(window.document[(id)])return window.document[id];
		if(window[(id)])return window[id];
		if(document[(id)])return document[id];
		return null;
	},
	onTabClicked: function(tabId) {
		var tabObj = this.tabInfos[tabId];
		if (tabObj) {
			//if (tabObj.index === this.selectedTabIdx && this.isInited) { return; }
			var prevId = "#" + this.id + '-cfp-tabs-' + this.selectedTabIdx;
			$J(prevId).removeClass("__active");
			$J("#" + tabId).addClass("__active").removeClass("__hover");
			this.selectedTabIdx = tabObj.index;
			this.onRightTabClicked(this.browseId);

			if (this.currentPlayList) {
				var pl = this.playlists[this.currentPlayList];
				if (pl) { $J("#" + pl.divId).hide(); }
				
				pl = this.playlists[tabId];
				if (pl) { 
					$J("#" + pl.divId).show(); 
					this.currentPlayList = tabId;
					return;
				}
			}

			$J('#' + this.id + " .__playlist-container .__playlist-loading").fadeIn();
			var info = this.tabInfos[tabId];
			var feed = info.cfg.feed;
			if(this.itemsPerPage){
				feed = feed.replace(/(^.*\/json\/)\d+(\/.*$)/i, "$1" + this.itemsPerPage + "$2");
			}
			if (info) {
				var resp = $J.ajax({
					type: "GET", cache: false, async: false,
					url: feed + (info._default && this.initConf.sh ?"sh:"+ this.initConf.sh +"/":""),
					dataType: info.cfg.feed.indexOf(".json") != -1 ?  "json" : "jsonp",
					success: (function(player, tabId) { return function(data, status) {
						player.updatePlayList(tabId, data, "browse");}; }) (this, tabId)
				});
			}
		}
	},
	onRightTabClicked: function(tabId) {
		if (tabId === this.selectedRightTabName) { return; }
		var re = new RegExp("cfp-tabs-(.*)", "gi");
		var res = re.exec(tabId);	// res[1] - tabCommand
		if (res != null) {
			var cmd = res[1];
			if (cmd === "browse") {
				var browsePl = (!this.currentPlayList) ? null :
						this.playlists[this.currentPlayList];
				var pl = this.playlists[this.selectedRightTabName];
				if (browsePl) { $J("#" + browsePl.divId).show(); }
				if (pl) { $J("#" + pl.divId).hide(); }

			} else if (cmd === "queue") {
				if (!this.playlists[tabId]) {
					// create playlist for queue
					if (this.currentPlayList &&
						(!this.queueData || !this.queueData.shows || this.queueData.shows.length == 0)) {
						var divId = this.currentPlayList + "-playlist";
						var itemId = divId + "-" + this.currentShow.show_id;
						this.addToQueueClicked(itemId, this.currentShow);
						if (!this.isPlaying){ this.playMedia(this.currentShow); }
					}
					this.updatePlayList(tabId, this.queueData, "queue");
				}
				var browsePl = (!this.currentPlayList) ? null :
						this.playlists[this.currentPlayList];
				var pl = this.playlists[tabId];
				if (browsePl) { $J("#" + browsePl.divId).hide(); }
				if (pl) { $J("#" + pl.divId).show(); }
			} else {
				// unknown tab - quit
				return;
			}
			$J("#" + this.selectedRightTabName).removeClass("__active");
			$J("#" + tabId).addClass("__active");
			this.selectedRightTabName = tabId;
			this.selectItem(this.currentShow);
		}
	},
	updatePlayList: function(tabId, data, mode) {
		var divId = tabId + "-playlist";
		var divPL = $J("#" + this.id + " .__playlist-container .__playlist-template.__" + mode).clone()
			.attr("id", divId).removeClass("__playlist-template").removeClass("__browse").removeClass("__queue");
		$J('#' + this.id + " .__playlist-container").append(divPL);
		
		if (data.shows && data.shows.length > 0) {
			var arrRender = new Array();
			// iterating thru the show array
			for (var i = 0, len = data.shows.length; i < len; i++) {
				var show = data.shows[i];
				show.nextShow = data.shows[(i+1!=len)?i+1:0];
				show.nextShow.prevShow = show;
				arrRender.push(this.getItemForRender(divId, show, mode, i));
			}
			divPL.find("ul.__scrollWrapper li").render(arrRender, {clone:true});
		} else {
			divPL.find("ul.__scrollWrapper li").remove();
			divPL.append("<div class=\"__playlist-no-videos\" >No videos found.</div>");
		}
		divPL.show();
		$J('#' + this.id + " .__playlist-container .__playlist-loading").fadeOut();
		if($J('#' + divId).divScroll){
			var divScroll = $J('#' + divId).divScroll({
				scrollType: this.scrollType,
				scrollSpeed:this.scrollSpeed,
				rows: this.rows,
				scrollerBack: "div.__scroller-up",
				scrollerForward: "div.__scroller-down",
				classScrollerBackHover: "__scroller-up-hover",
				classScrollerForwardHover: "__scroller-down-hover",
				classScrollerDisabled: "__x-item-disabled",
				scrollWrapper: "ul.__scrollWrapper",
				callbackEndForward: (function(player, tabId) { return function() {
									player.loadNextPage(tabId);}; }) (this, tabId)
			});
			
			var pl = { divId: divId, data: data, divScroll: divScroll, topItem: 0,
				maxItem: (data.shows && data.shows.length > 0) ? data.shows.length - 1 : 0};
			this.playlists[tabId] = pl;
		}
		if (data.shows) {
			// binding events to buttons
			for (var i = 0, len = data.shows.length; i < len; i++) {
				var show = data.shows[i];
				var itemId = divId + "-" + show.show_id;
				if (mode === "browse") {
					$J("#" + itemId + " .__add").click(
						(function(player, itemId, show) { return function(ev) {
							ev.stopPropagation();
							player.addToQueueClicked(itemId, show); }; }) (this, itemId, show)
					);
					
					if( this.queueData && this.queueData.sources && this.queueData.sources[itemId] ) {
						$J("#" + itemId + " .__add").hide();
					} 
				}
				if (mode === "queue") {
					$J("#" + itemId + " .__remove").click(
						(function(player, itemId, show) { return function(ev) {
							ev.stopPropagation();
							player.removeFromQueueClicked(itemId, show); 
							}; }) (this, itemId, show)
					);
				}
				this.setPlayItem(itemId, show);
			}
		}
		if (mode === "browse") {
			this.currentPlayList = tabId;
		}
		
		if (!this.currentShow && data && data.shows && data.shows.length > 0 ){
			if(this.initConf.sh) {
				this.playMedia(this.initConf.show?this.initConf.show:data.shows[0]);
				castFirePlayerReady = (function(player, show, data) { return function() {
					player.playMedia(player.initConf.show?player.initConf.show:data.shows[0]);}; }) (this, show, data)
			} else {
				this.loadMedia(this.initConf.show?this.initConf.show:data.shows[0]);
				castFirePlayerReady = (function(player, show, data) { return function() {
					player.loadMedia(player.initConf.show?player.initConf.show:data.shows[0]);}; }) (this, show, data)
			}
			this.currentShow = data.shows[0];
		}
	},
	setPlayItem: function(itemId, show){
		$J("#" + itemId + " .__image").click(
			(function(player, show) { return function() {
				player.playMedia(show); }; }) (this, show)
		);
		$J("#" + itemId + " .__title").click(
			(function(player, show) { return function() {
				player.playMedia(show); }; }) (this, show)
		);
		$J("#" + itemId + " .__play_click").click(
			(function(player, show) { return function() {
				player.playMedia(show); }; }) (this, show)
		);
	},
	getItemForRender: function(divId, show, mode, i) {
		var itemId = divId + "-" + show.show_id;
		var date = new Date(show.pubdate);
		return {
			"item_id" : itemId,
			"item_class" : (i%2 == 1 ? "__bg1" : "__bg0"),
			"item_add_remove" : (mode !== "browse" ? "__remove" : "__add"),
			"_src_" : "src", // workaround for Remote Sources in IE
			"item_img_src" : (show.images && show.images.tmb ? show.images.tmb : "no_image.png" ),
			"item_date" : (date.format && date.format('D, M j, Y') || ""),
			"item_title" : show.title,
			"item_description" : show.description
		}
	},
	loadNextPage: function(tabId){
		if( this.loading||
			tabId == this.queueId || 
			tabId != this.currentPlayList ){ return; }

		var info = this.tabInfos[tabId];
		var pl = this.playlists[tabId];
		if ( !info || !pl || !pl.data || !pl.data.pagination || "" == pl.data.pagination.next /*|| !pl.data.shows*/ ) { return; }

		$J('#' + this.id + " .__playlist-container .__playlist-loading").fadeIn();
		this.loading = true;

		var feed = pl.data.pagination.next.replace(/(^.*\/json\/\d+:)\d+(\/.*$)/i, "$1" + (this.itemsPerPage || 10) + "$2");
		var resp = $J.ajax({
			type: "GET", cache: false, async: true,
			url: feed, //pl.data.pagination.next,
			dataType: info.cfg.feed.indexOf(".json") != -1 ?  "json" : "jsonp",
			success: (function(player, tabId) { return function(data, status) {
				player.loading = false;
				player.addNextPageToList(tabId,  data)}; }) (this, tabId)

		});
		
	},
	addNextPageToList: function(tabId,  data){//debugger;
		var pl = this.playlists[tabId];
		if (!pl || !pl.data || !pl.data.shows || !data || !data.shows) { return; }
		var divId = pl.divId;
		var htmlArr = [];

		var arrRender = new Array();
		// iterating thru the show array
		for (var i = 0, len = data.shows.length; i < len; i++) {
			var show = data.shows[i];
			var j = pl.data.shows.length;
			pl.data.shows[j] = show;
			show.nextShow = pl.data.shows[0];
			show.nextShow.prevShow = show;
			show.prevShow = pl.data.shows[j-1];
			show.prevShow.nextShow = show;
			
			arrRender.push(this.getItemForRender(divId, show, "browse", j));
		}

		var liItem = $J("#" + this.id + " .__playlist-container .__playlist-template.__queue .__scrollWrapper li").clone();
		pl.divScroll.append(liItem);
		liItem.hide().render(arrRender, {clone:true});
		
		//pl.divScroll.append(htmlArr.join(''));
		pl.maxItem = pl.data.shows.length - 1;
		pl.data.pagination = data.pagination;
		
		for (var i = 0, len = data.shows.length; i < len; i++) {
			var show = data.shows[i];
			var itemId = divId + "-" + show.show_id;
			$J("#" + itemId + " .__add").click(
				(function(player, itemId, show) { return function(ev) {
					ev.stopPropagation();
					player.addToQueueClicked(itemId, show); }; }) (this, itemId, show)
			);
			
			if( this.queueData && this.queueData.sources && this.queueData.sources[itemId] ) {
				$J("#" + itemId + " .__add").hide();
			}
			
			this.setPlayItem(itemId, show);
		}	
		var itemId = divId + "-" + data.shows[data.shows.length-1].show_id;
		$J("#" + itemId + " .tumb").ready(
			(function(player, pl, divId) { return function() {
				setTimeout(
					(function(player, pl, divId) { return function() {
						$J('#' + player.id + " .__playlist-container .__playlist-loading").fadeOut();
						pl.divScroll.show("li");
					}; }) (player, pl, divId)
				, 500)
			}; }) (this, pl, divId)
		);
	},
	addToQueueClicked: function(itemId, show) {
		this.queueData.shows.push(show);
		show.itemId = itemId;
		this.queueData.sources[itemId] = itemId;
		var tabId = "cfp-tabs-queue";
		var divId = tabId + "-playlist";
		$J("#" + itemId + " .__add").hide();
		$J("#" + tabId + " a").text(
				this.queueCaption + " (" + this.queueData.shows.length + ")");
		var pl = this.playlists[tabId];
		if (pl) {
			var liItem = $J("#" + this.id + " .__playlist-container .__playlist-template.__queue .__scrollWrapper li").clone();
			pl.divScroll.append(liItem);
			liItem.render(this.getItemForRender(divId, show, "queue", this.queueData.shows.length-1));
			pl.maxItem++;
			if (this.queueData.shows) {
				// iterating thru the show array
				for (var i = 0, len = this.queueData.shows.length; i < len; i++) {
					var show = this.queueData.shows[i];
					show.nextShow = this.queueData.shows[(i+1!=len)?i+1:0];
					show.nextShow.prevShow = show;
				}
			}
			
			var queueItemId = divId + "-" + show.show_id;
			$J("#" + queueItemId + " .__remove").click(
					(function(player, queueItemId, show) { return function(ev) {
						ev.stopPropagation();
						player.removeFromQueueClicked(queueItemId, show); 
						}; }) (this, queueItemId, show)
			);
			
			this.setPlayItem(queueItemId, show);
			this.selectItem(this.currentShow);
		}
	},
	removeFromQueueClicked: function(itemId, show){
		this.queueData.shows.remove(show);
		this.queueData.sources[show.itemId] = null;
		var tabId = "cfp-tabs-queue";
		var divId = tabId + "-playlist";
		$J("#" + show.itemId + " .__add").show();
		
		if (this.queueData.shows.length == 0){
			$J("#" + tabId + " a").text(this.queueCaption);
		}else{
			$J("#" + tabId + " a").text(
				this.queueCaption + " (" + this.queueData.shows.length + ")");
		}
		var pl = this.playlists[tabId];
		if (pl) {
			pl.maxItem--;
			pl.divScroll.remove("#" + itemId);
		}
		show.prevShow.nextShow = show.nextShow;
		show.nextShow.prevShow = show.prevShow;
		show = null;
	},
	playMedia: function(show, deep) {
		deep = deep?deep:0;
		if(deep>10) return;

		if (this.playerInstance) {
			if(typeof(show) != "string"){
				this.selectItem(show);
			}
			try{
				this.playerInstance.externalCastfirePlayVideo((typeof(show) == "string"?show:show.url));
				this.isPlaying = true;
			}catch(e){
				setTimeout(
				(function(player, show, deep) { return function() {
					player.playMedia(show,++deep); }; }) (this, show, deep)
				, 1000);
			}
		}
	},
	loadMedia: function(show, deep) {
		deep = deep?deep:0;
		if(deep>10) return;
		
		if (this.playerInstance) {
			if(typeof(show) != "string"){
				this.selectItem(show);
			}
			try{
				this.playerInstance.externalCastfireLoadVideo((typeof(show) == "string"?show:show.url));
				this.isPlaying = false;
			}catch(e){
				setTimeout(
				(function(player, show, deep) { return function() {
					player.loadMedia(show,++deep); }; }) (this, show, deep)
				, 1000);
			}
		}
	},
	onCompleteMedia: function(url){
		if(!this.currentShow) return;
		var tmpShow = this.currentShow;
		if(this.selectedRightTabName == this.queueId){
			this.removeFromQueueClicked(tmpShow.oDiv.attr("id"), tmpShow); 
			if( this.queueData.shows.length == 0 ){
				this.currentShow = null;
				return;
			}
		}
		this.playMedia(tmpShow.nextShow);

	},
	selectItem: function(show) {
		if(this.currentShow && this.currentShow.oDiv){
			this.currentShow.oDiv.removeClass("__playlist-item-selected");
		}
		if(show){
			var curPL = this.selectedRightTabName == this.queueId?this.queueId:this.currentPlayList;
			var	itemId = curPL + "-playlist-" + show.show_id;
			show.oDiv = $J("#" + itemId);
			show.oDiv.addClass("__playlist-item-selected");
			this.currentShow = show;
		}
	}
});

$J.extend(true, Array.prototype, {
	/**
	 * Checks whether or not the specified object exists in the array.
	 * @param {Object} o The object to check for
	 * @return {Number} The index of o in the array (or -1 if it is not found)
	 */
	indexOf : function(o){
		for (var i = 0, len = this.length; i < len; i++){
			if(this[i] == o) return i;
		}
		return -1;
	},

	/**
	 * Removes the specified object from the array.  If the object is not found nothing happens.
	 * @param {Object} o The object to remove
	 * @return {Array} this array
	 */
	remove : function(o) {
		var index = this.indexOf(o);
		if(index != -1) { this.splice(index, 1); }
		return this;
	}
});