/**
 * YTV - YouTube video player with playlist and repeat options
 * @version		1.0.0
 * @MooTools version 1.2
 * @author Constantin Boiangiu <constantin.b [at] gmail.com>
 * @copyright Constantin Boiangiu
 */

var YTV = new Class({
	Implements: [Options],
	
	options: {
		videos: null, // CSS selector for video links. Use it as .class
		videoSize: {
			width:640, // video width
			height:360 // video height; try to keep these values at a 1.2 ratio ( width/height ~ 1.23 )
		},
		playerConfig: {
			showRelated: 0, // youtube player can display related videos, search or info when video ends. Set any of these variables to 1 to display 
			showSearch: 0,
			showInfo: 0
		},
		smoothScroll: false,
		videoContainer: null, // id for video container div. Player will be injected inside this element 
		playlist:null, // id for playlist container
		loadLists: null, // css class for links loading playlists
		clickStart: true, // when video from playlist is clicked, movie starts; you can set this individually for every video using paused:1|0
		volume: 30, // default volume; you can set this for every video using volume:1-100
		infoPanel: null, // id for element displaying the video state ( buffering, playing, paused... )
		togglePlaylist:null, // id for element toggling the playlist
		toggleRepeat: null, // id for element toggling playlist repeat
		repeatPlaylist: false // if true, when playing video ends, the next one start automatically if video isn't set specifically to repeat itself ( end:1 )
	},
	
	initialize: function(options){
		
		this.setOptions(options);		
		this.videos = $(this.options.playlist).getElements(this.options.videos);
		this.playlists = $(this.options.playlist).getElements(this.options.loadLists);
		this.container = $(this.options.videoContainer);		
		this.container.setStyles(this.options.videoSize);
		this.playlistState = -1;
		this.currentVideo = 0;
		
		/* tooltips for playlist toggle and repeat playlist */
		new Tips('.tooltiped', {className : 'YTV_tips'});
		/* playlist scroll */
		if(this.options.smoothScroll)
			this.playlistScroll();
		/* playlist show/hide */
		this.togglePlaylist();
		
		/* playlist repeat */
		if( this.options.repeatPlaylist ){
			$(this.options.toggleRepeat).addClass('playlist_repeat_on');
		}
		$(this.options.toggleRepeat).addEvent('click', function(event){
			event.preventDefault();
			if( this.options.repeatPlaylist ){
				this.options.repeatPlaylist = false;
				$(this.options.toggleRepeat).removeClass('playlist_repeat_on');
			}else{
				this.options.repeatPlaylist = true;
				$(this.options.toggleRepeat).addClass('playlist_repeat_on');
			}
			
		}.bind(this));
		
		this.playlists.each(function(playlist, i){
			playlist.addEvent('click', function(event){
				if(event)
					event.preventDefault();
				if( playlist.retrieve('loaded') ) return;
				var data = JSON.decode(playlist.get('rel'));
				var loader = new Element('div',{
					'class':'loading'
				}).injectAfter(playlist);
				new Request.JSONP({
					url: 'http://gdata.youtube.com/feeds/api/playlists/'+data.playlistId+'/?alt=json-in-script&v=2',
					callBackKey : 'YTV',
					onComplete: function(response){
						/* in JSON, videos are stored on node entry - type array */
						var videos = response.feed.entry;
						loader.dispose();
						playlist.addClass('open');
						this.addVideos(videos, playlist);
						playlist.store('loaded',1);
						
					}.bind(this) // end of JSONP request complete method
					
				}).send();
				
			}.bind(this))			
		}.bind(this));
		
		if( this.videos.length == 0 ){
			this.playlists[0].fireEvent('click').addClass('open');
		}
		
		this.setVideos( this.videos );			
	},
	
	addVideos: function(videoFeed, addAfter){
		var list = new Element('ul').injectAfter(addAfter);
		
		videoFeed.each(function(v, i){
			var title = v.title.$t;
			var vId = v.media$group.yt$videoid.$t;
			var videoData = {};
			videoData.vidId = vId;
			videoData.title = title;
			
			var pLink = new Element('a',{
				'href':"#",
				'rel': "{'vidId':'"+vId+"'}",
				'text':title,
				'title':title,
				'class':'YTV_video',
				'events':{
					'click': this.playVideo.pass([videoData, this.videos.length], this)
				}
			});
			
			this.videos.include(pLink);
			var repeat = new Element('a',{
				'class':'repeat tooltiped'+(videoData.end==1 ? ' repeat_on':''),
				'href':'#',
				'title':'toggle video repeat',
				'events':{
					'click':function(event){
						event.preventDefault();
						if( videoData.end ){
							this.removeClass('repeat_on');
							pLink.removeClass('link_repeat');
						}
						else{
							this.addClass('repeat_on');
							pLink.addClass('link_repeat');
						}
						
						videoData.end = videoData.end ? 0 : 1;						
					}
				}
			});
			
			new Element('li').adopt(pLink, repeat).injectInside(list);
			if(!$defined(this.swfObj)){
				this.playVideo(videoData, this.videos.length-1);
				if( this.playlistState == -1 ){
					this.playlistFx.start({'left':0});
					this.playlistState = 1;
					$(this.options.togglePlaylist).addClass('playlist_on');
				}
			}	
			
		}.bind(this));
		if(this.options.smoothScroll)
			this.playlistScroll.toElement(this.videos.getLast());
		
		var listFx = new Fx.Slide(list);
		addAfter.addEvent('click', function(event){
			listFx.toggle().chain(function(){
				if(listFx.open)
					addAfter.addClass('open');
				else
					addAfter.removeClass('open');
			});
		})
		
	},
	
	setVideos: function(videos){
		/* click events for playlist videos */
		videos.each(function(elem, i){
			
			var video = JSON.decode(elem.get('rel'));
			if( video.end ){
				elem.addClass('link_repeat');
			}
			
			new Element('a',{
				'class':'repeat tooltiped'+(video.end==1 ? ' repeat_on':''),
				'href':'#',
				'title':'toggle video repeat',
				'events':{
					'click':function(event){
						event.preventDefault();
						if( video.end ){
							this.removeClass('repeat_on');
							elem.removeClass('link_repeat');
						}
						else{
							this.addClass('repeat_on');
							elem.addClass('link_repeat');
						}
						
						video.end = video.end ? 0 : 1;						
					}
				}
			}).injectAfter(elem);
			
			video.title = elem.get('text');
			elem.addEvent('click', this.playVideo.pass([video, i], this));			
			if(!$defined(this.swfObj)){
				this.playVideo(video, i);
				if( this.playlistState == -1 ){
					this.playlistFx.start({'left':0});
					this.playlistState = 1;
					$(this.options.togglePlaylist).addClass('playlist_on');
				}
			}		
			
		}.bind(this));	
	},
	
	loadVideo: function(video){
		/* if YT player loaded, just load the movie */
		if($defined(this.swfObj)){			
			this.swfObj.cueVideoById(video.vidId);
			this.swfObj.setVolume(video.volume||this.options.volume);			
			
			if(video.end) this.swfObj.playVideo();	
			else if($defined(video.paused) && video.paused!==1) this.swfObj.playVideo();			
			else if( this.options.clickStart && !$defined(video.paused) ) this.swfObj.playVideo();
			
			return false;
		}
		/*
			chromless api player
			http://www.youtube.com/apiplayer?enablejsapi=1&playerapiid=YTV_videoPlayer			
		*/
		var playerURL = 'http://www.youtube.com/v/'+
						 video.vidId+
						 '&enablejsapi=1&playerapiid=YTV_videoPlayer&rel='+
						 this.options.playerConfig.showRelated+
						 '&showsearch='+
						 this.options.playerConfig.showSearch+
						 '&showinfo='+this.options.playerConfig.showInfo;
		
		this.swfObj = new Swiff(playerURL, {
			id: 'YTV_videoPlayer',
			container: this.container,
			width: this.options.videoSize.width,
			height: this.options.videoSize.height,
			params: {
				wmode: 'transparent',
				allowScriptAccess: 'always'
			}
		});
			
	},
	
	playVideo: function(video, key){	
		this.videoPlaying = video;
		this.currentVideo = key;
		this.loadVideo(video);
		if( this.playlistState == 1 ){
			this.playlistFx.start({'left':-650});
			this.playlistState = -1;
			$(this.options.togglePlaylist).removeClass('playlist_on');
		}
		this.highlightElement(key);
	},
	
	highlightElement: function(key){
		this.videos.removeClass('selected');
		this.videos[key].addClass('selected');
	},
	
	changeState: function(state){
		
		var message = '';
		switch(state){
			case -1: /* unstarted */
				message = 'Starting player';
			break;
			
			case 0: /* ended */
				message = this.videoPlaying.title+' - ended';
				
				if(this.videoPlaying.end==1){
					message = this.videoPlaying.title+' - replaying';
					this.swfObj.playVideo();
				}else if( this.options.repeatPlaylist ){
					var next = this.currentVideo+1 < this.videos.length ? this.currentVideo+1 : 0;
					var elem = this.videos[next];
					var video = JSON.decode(elem.get('rel'));
					video.title = elem.get('text');
					message = 'Loading next video <strong>'+video.title+'</strong>';
					this.playVideo(video, next);
				}
				
			break;
			
			case 1: /* playing */
				message = '<strong>' + this.videoPlaying.title + '</strong> - playing' + (this.videoPlaying.end ? ' ( repeat : on )' : '');
			break;
			
			case 2: case 5: /* paused and cued */
				message = '<em>'+this.videoPlaying.title+'</em>';
			break;
			
			case 3: /* buffering */
				message = 'Buffering video ... please wait';
			break;			
		}
		this.videoState = state;
		$(this.options.infoPanel).set({'html':message});
		
	},
	
	playlistScroll: function(){
		
		this.playlistScroll = new Fx.Scroll($(this.options.playlist),{ wait:false, duration:400, wheelStops:false});
		var currEl = this.currentVideo;
		
		$(this.options.playlist).addEvent('mousewheel', function(event){
			var event = new Event(event);
			currEl += -event.wheel;
			if( currEl < 0 ) currEl = 0;
			if( currEl >= this.videos.length ) currEl = this.videos.length-1;
			this.playlistScroll.toElement(this.videos[currEl]);
		}.bind(this));		
		
	},
	
	togglePlaylist: function(){
		/* Playlist */
		this.playlistFx = new Fx.Morph(this.options.playlist, {wait:false, duration:300});
		$(this.options.togglePlaylist).addEvent('click', function(event){
			event.preventDefault();
			var left = this.playlistState == -1 ? 0 : -650;
			if(!this.options.smoothScroll && $(this.options.playlist).getStyle('overflow')!=='hidden'){
				$(this.options.playlist).setStyle('overflow', 'hidden' );		
			}	
			
			this.playlistFx.start({'left':left}).chain(function(){
				if(!this.options.smoothScroll)												
					$(this.options.playlist).setStyle('overflow', 'auto' );
			}.bind(this));
			/* if playlist is closed, save the initial video state to make it play if playing when closing playlist */
			if( this.playlistState == -1 ){
				this.prevState = this.videoState;
				$(this.options.togglePlaylist).addClass('playlist_on');
			}else{
				$(this.options.togglePlaylist).removeClass('playlist_on');
			}
			/* change playlist state */
			this.playlistState*=-1;
			
			/* pause video when playlist opened */
			if( this.playlistState == 1 )
				this.swfObj.pauseVideo();
			/* if movie was playing when playlist was opened, start it */	
			else if( this.prevState == 1 )
				this.swfObj.playVideo();
			
		}.bind(this))
	}
})
/* function triggered by the player after it loads */
function onYouTubePlayerReady(){
	var obj = document.getElementById('YTV_videoPlayer');
	obj.addEventListener('onStateChange', 'YTVplayer.changeState');
	YTVplayer.swfObj = obj;
}

window.addEvent('load', function(){
	this.YTVplayer = new YTV( playerSettings );
}.bind(this));