jQuery.fn.vote = function(config) 
{
	config = config || {};

	var defaults = 
	{
		url: '/bookess-v2/trunk/book/rate/',
		params: {},
		enabled: true,	
		className : 'rate',
		normalClass : 'rate-normal',
		hoverClass : 'rate-hover',
		statusClass : 'rate-status',
		loadingClass : 'rate-loading',
		callback: function(rate){},
		showStatus: true,
		duration: 150,
		maxScore : 5,
		average: 5,
		onError: function(){},
		messages : 
		{
			rateNow: 'Clique para votar.',
			ratedAs: '{0}', 
			loading : 'Carregando',
			rate : ['Não avaliado', 'Ruim.', 'Nada de especial.', 'Vale a pena.', 'Muito legal.', 'Fantástico!']
		}
	};

	config = jQuery.extend(defaults, config);
	
	return $(this).each(function()
	{
		var $elm = $(this);
		var self = this;
	
		var $container = $('<div />').attr('className', config.className);
		var $status = config.showStatus ? $('<div />').appendTo($container) : null;
		var $buttons = null;
		var average = Math.round(config.average);
	
		this.init = function() 
		{
			for ( var i = 0, num = config.maxScore; i < num; ++i) 
			{
				$('<div />').attr('className', config.normalClass).prependTo($container);
			}
	
			$buttons = $('.' + config.normalClass, $container);
	
			if($status)
			$status.attr('className', config.statusClass);
			$elm.append($container);
			
			this.showLoading();
	
			this.onInit();
		};
	
		this.onInit = function(avg) 
		{
			//average = avg;
			self.showRate(average);
			self.hideLoading();					
		};
		
		this.showRate = function(num) 
		{
			num = Math.round(num);
			$buttons.removeClass(config.hoverClass).filter(':lt(' + (num) + ')').addClass(config.hoverClass);
		};
		
		this.showLoading = function()
		{
			$buttons.fadeTo(0, 0.5);
			if($status)
				$status.addClass(config.loadingClass).text(config.messages['loading']);
			$buttons.unbind();
		};
		
		this.hideLoading = function()
		{
			$buttons.fadeTo(0, 1);
		
			if($status)
				$status.removeClass(config.loadingClass);
			
			if(config.enabled)
			{
				$buttons.hover(this.onMouseOver, this.onMouseOut).click(this.onMouseDown);
				if($status)
					$status.text(config.messages.rateNow);
				$buttons.attr('title', config.messages.ratenow);
			}
			else
			{
				var message = config.messages.ratedAs.replace(/\{0}/, config.messages['rate'][average]);
				if($status)
					$status.text(message);
				$buttons.attr('title', message);
			}
		};
	
		this.onMouseDown = function() 
		{
			var $button = $(this);
			var index = $buttons.index(this);
			
			self.onMouseOver.apply(this);
			self.showLoading();	
			
			config.params.vote = index + 1;
			
			$.ajax
	        ({
	            type: 'POST',
	            data: config.params,
	            dataType: 'json',
	            url: config.url,
	            success: function(response)
	            {
	        		average = Math.round(response.average);
	        		config.callback.apply(self, [response.average]);
	        		
	        		self.hideLoading();

					if(average < index)
					{
						self.effectOut.apply($button);
					}
					else
					{
						self.effectIn.apply($button);
					}
	            },
	            error: config.onError
	        });
		};
	
		this.onMouseOver = function() 
		{
			$buttons.removeClass(config.hoverClass).each(function()
			{
				$(':animated', this).stop().remove();
			});
	
			var index = $buttons.index(this);
			$buttons.filter(':lt(' + (index + 1) + ')').addClass(config.hoverClass);
			
			if($status)
				$status.text(config.messages['rate'][index + 1]);		
		};
	
		this.onMouseOut = function() 
		{
			if($status)
				$status.text(config.messages.rateNow);
			
			var index = $buttons.index(this);
			
			if(index < average)
			{
				self.effectIn.apply(this);	
			}
			else
			{
				self.effectOut.apply(this);	
			}
		};
		
		this.effectOut = function()
		{
			var index = $buttons.index(this);
			
			if(index < average)
			{
				return false;
			}
			
			var $button = $(this);
			var $c = $button.clone(false).appendTo($button);
			
			$button.removeClass(config.hoverClass).removeClass(config.hoverClass).addClass(config.normalClass);
			
			$c.animate({width: 0}, config.duration, null, function()
			{
				var $previous = $buttons.filter(':eq(' + (index-1) + ')');
				$button.removeClass(config.hoverClass);
				$(this).remove();
				
				self.effectOut.apply($previous);
			});
		};
		
		this.effectIn = function()
		{
			var index = $buttons.index(this);
			
			if(index >= average)
			{
				return false;
			}

			var $button = $(this);
			var $c = $button.clone(false).css('width', 0).removeClass(config.normalClass).addClass(config.hoverClass).appendTo($button);
					
			$c.animate({width: $button.width()}, config.duration, null, function()
			{
				var $next = $buttons.filter(':eq(' + (index+1) + ')');
				$button.addClass(config.hoverClass);
				$(this).remove();
				
				self.effectIn.apply($next);
			});
		};
	
		this.init();
	});
};

