(function( $ ){
	var registeredPlayers = new Array();
	
	/**************************************************\
	*  Constants
	\**************************************************/
	var DATA_KEY = 'youtube';
	
	/**************************************************\
	*  Helper functions
	\**************************************************/
	function registerPlayer(playerApiId, playerWrapper){
		registeredPlayers[playerApiId] = playerWrapper;
	}
	
	function getRegisteredPlayer(playerApiId){
		return registeredPlayers[playerApiId];
	}
	
	function setData(jqQueryElement, data){
		var oldData = jqQueryElement.data(DATA_KEY);
		jqQueryElement.data(DATA_KEY, $.extend(oldData, data));
	}
	
	function getData(jqQueryElement){
		return jqQueryElement.data(DATA_KEY);
	}
	
	/**************************************************\
	*  Define API object of methods for each current element
	\**************************************************/
	function Api(domElement){
		var $this = $(domElement);
		var _playerObject = null;
		
		// < Public API functions > 
		this.isReady = function (){
			return playerObject() != null;
		};
		
		this.loadVideoById = function (videoId){
			if (this.isReady()){
				playerObject().loadVideoById(videoId);
			}
		}

		this.stopVideo = function (){
			if (this.isReady()){
				playerObject().stopVideo();
			}
		}

		this.clearVideo = function (){
			if (this.isReady()){
				playerObject().clearVideo();
			}
		}
		//TODO: check if this can be achieved by simply using one of the animate() posibilities
		this.resize = function(options){
			var defaults = {
				width: $this.parent().width(),
				height: $this.parent().height(),
				resizer: function(options){
					$this.width(options.width);
					$this.height(options.height);
					options.callback();
				},
				callback: function(){}
			};
			
			var xoptions = $.extend({}, defaults, options);
			
			xoptions.resizer.apply(domElement, [xoptions]);
		}
		// </ Public API functions  >
		
		//< Private helper functions >
		function playerObject(){
			if (!_playerObject){
				var data = getData($this);
				_playerObject = (data  && data.playerObject) ? data.playerObject[0] : null;		
			}
			return _playerObject;
		};
		//</ Private helper functions >
	};
	
	var methods = {
		init : function( options ) {
			return this.each(function(){
				var $this = $(this);
				var data = null;
				var newData = null;
				var xoptions = $.extend({}, $.fn.youtube.defaults.global, options);
				
				if (!xoptions.videoId && !xoptions.playList){
					//No videos nor playlist to work on
					if (xoptions.throwExceptions){
						$.error( 'No videos nor playlist to work on' );
					}
					return;
				}
				
				//Hadle videoId according to its type
				var defaultVideoId = null;
				if(typeof xoptions.videoId === 'string'){
					defaultVideoId = xoptions.videoId;
				}
				
				if (!defaultVideoId){
					if (xoptions.throwExceptions){
						$.error( 'Cannot determine default video id' );
					}
					return;
				}
				
				//Check existance of swfobject, which help in embedding the youtube flash player
				if (!swfobject){
					if (xoptions.throwExceptions){
						$.error( "'swfobject' is not defined" );
					}
					return;
				}
			
				//Cre<ate youtube video player location element. This elememt will be replaced (completely deleted from  the DOM) by the youtube flash player 
				//once it loads. Do not asociate any data nor events that you mught need later.
				var ramdomIdNumber = Math.floor(Math.random() * 10000001);  
				var playerLocationId = 'ytPlayerLocation_' + ramdomIdNumber; //id necessary for the  swfobject.embedSWF(...) method
				var playerLocationHtml =	'<div id="' + playerLocationId + '">' +
												'<p>Por favor, actualice el plugin de Flash</p>' +
												'<p><a target="_blank" href="http://www.adobe.com/go/getflashplayer"><img src="http://www.adobe.com/images/shared/download_buttons/get_flash_player.gif" alt="Get Adobe Flash player" /></a></p>' +
											'</div>';				
				$this.append(playerLocationHtml);

				var playerId = 'ytPlayer_' + ramdomIdNumber;
				var playerApiId = playerId + '_ApiId';
				
				//Set element's data
				setData($this, {
					playerId: playerId,
					api: new Api(this)
				});
				
				//Bind default handler to execute on onYouTubePlayerReady() (youtube's player ready event). This hadler will store  a reference to the 
				//youtube player object in the current element data.
				$this.bind('playerready.' + playerApiId, function(){
					setData($this, {
						playerObject: $('#' + getData($this).playerId)
					});
				});
				
				//Bind user custom handler for the player ready event
				if(typeof xoptions.onReady === 'function'){
					//$this.bind('playerready.' + playerApiId, xoptions.onReady); 
					$this.bind('playerready', xoptions.onReady); 
				}
				//Register this player. This will allow later handling o events thrown by youtube player (like "player ready")
				registerPlayer(playerApiId, $this);
				
				//embed youtube flash player
				var params = { 
					allowScriptAccess: "always",
					allowFullScreen: true,
					wmode: "opaque"
				};				
				var atts = { id: playerId };

				swfobject.embedSWF("http://www.youtube.com/e/"+ defaultVideoId + "?version=3&enablejsapi=1&playerapiid=" + playerApiId + "&autohide=1", 
									playerLocationId , "100%", "100%", "8", null, null, params, atts);

				
			});	
		},
		destroy : function( ) {
			return this.each(function(){
			 //do stuff
			});
		},
		loadThumbnail: function(options){
			var xoptions = $.extend({}, $.fn.youtube.defaults.loadThumbnail, options ); //extended params
		
			return this.each(function(){
				var $this = $(this);
				//if current element is not an image, throw exception
				if (!$this.is('img')){
					if (xoptions.throwExceptions){
						$.error( 'Current element is not an <img>.' );
					}
					return;
					
				}
				var videoInfo = xoptions.videoInfoGetter.call($this);
				if (!videoInfo.videoId){
					if (xoptions.throwExceptions){
						$.error( 'Could not determine video id.' );
					}
					return;
				}
								
				$.getJSON("http://gdata.youtube.com/feeds/api/videos/" + videoInfo.videoId + "?v=2&alt=jsonc&callback=?",
					{},
					function(data, textStatus, jqXHR)
					{
						var video = data.data;
						var imageUrl = xoptions.quality == 'high' ? video.thumbnail.hqDefault : video.thumbnail.sqDefault;
						$this.attr("src", imageUrl);
					}
				);				
			});
		}
	};

	$.fn.youtube = function( method ) {
		if ( methods[method] ) {
		  return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
		} else if ( typeof method === 'object' || ! method ) {
		  return methods.init.apply( this, arguments );
		} else {
		  $.error( 'Method ' +  method + ' does not exist on jQuery.youtube' );
		}    
	};
	
	$.fn.youtube.defaults = {
		global: {
			videoId: null,
			playList: null,
			throwExceptions: false
		},
		loadThumbnail: {
			quality: 'low',
			videoInfoGetter: function(){
				var videoId = null;
				var elemData = this.data(DATA_KEY) || this.data();
				if (elemData && elemData.videoId){
					videoId = elemData.videoId;
				}
				else {
					videoId = this.attr('alt');
				}
				
				if (videoId.trim){
					videoId = videoId.trim();
					videoId = videoId == '' ? null : videoId;
				}
				return {videoId: videoId};
			}
		}
	};
	
	$.fn.youtube.playerEvents = {
		ready: {
			trigger: function(playerApiId, args){	
				var playerWrapper = getRegisteredPlayer(playerApiId);
				//playerWrapper.trigger('playerready.' + playerApiId, args);
				playerWrapper.trigger('playerready', args);
			}
		}
	};
	
	
})( jQuery );
