/* ______________________________________________________________________________
 *
 * jQuery StarRate Plugin
 * 
 * 	@version		- 0.2 - 14.06.2010
 * 	@author 		- VOID (www.void.pt)
 *	@dependencies 	- jQuery
 *
 * ------------------------------------------------------------------------------
 *	OPTIONS
 * ------------------------------------------------------------------------------
 *		- file (string) 		- php file that will store the vote and return the average.
 *		- average (number) 		- initial average.
 *		- enabled (boolean) 	- defines if the user can vote.
 *		- token (string) 		- optional verification token to prevent multiple votes.
 *		- item (number) 		- id number of the item.
 *		- change (function) 	- change event callback function.
 * ------------------------------------------------------------------------------
 *	USAGE
 * ------------------------------------------------------------------------------
 *		$('.rating').starrate({ file: 'starrate.php', average: 3.8, enabled: true, token: '', item: 1, change: function () {} });
 * ------------------------------------------------------------------------------
 *	METHODS
 * ------------------------------------------------------------------------------
 *		- enableRating ()
 *		- disableRating ()
 * ------------------------------------------------------------------------------
 *	TO-DO
 * ------------------------------------------------------------------------------
 *		
 * ___________________________________________________________________________ */

if (jQuery) (function ($) {
	
	var StarRate = function (element, settings) {
		
		/* SCOPE VARS -------------------------------------------------------- */
		
		var elem = $(element);
		var self = this;
		
		/* OPTIONS ----------------------------------------------------------- */
		
		var options = $.extend({
			file: '/jx.php?action=rate', 
			average: 0, 
			enabled: true, 
			token: '',
			item: null, 
			change: function () {}
		}, settings || {});
		
		/* VARIABLES --------------------------------------------------------- */
		
		var _stars;
		var _average;
		var _enabled;
		
		/* -------------------------------------------------------------------
		 * init
		 * 	Initiates the plugin with the default/initial values.
		 * ------------------------------------------------------------------- */
		 
		var init = function () {
			_stars = elem.children('li');
			_average = options.average;
			_enabled = options.enabled;
			
			showAverage();
		}
		
		/* -------------------------------------------------------------------
		 * bindEvents
		 * 	Binds the events of the select, caixabox and options.
		 * ------------------------------------------------------------------- */
		 
		var bindEvents = function () {
			_stars.mouseover(onStarHover);
			_stars.mouseout(onStarOut);
			_stars.click(onStarClick);
		}
		
		/* -------------------------------------------------------------------
		 * Event Handlers
		 * ------------------------------------------------------------------- */
		
		var onStarHover = function (evt) {
			if (_enabled) {
				var star = $(evt.target);
				resetRating();
				
				_stars.each(function () {
					if ($(this).attr('title') <= star.attr('title')) {
						$(this).addClass('hover');
					} else {
						$(this).removeClass('hover');
					}
				});
			}
		}
		
		var onStarOut = function () {
			showAverage();
		}
		
		var onStarClick = function (evt) {
			if (_enabled) {
				var star = $(evt.target);
				castVote(star.attr('title'));
			}
		}
		
		/* -------------------------------------------------------------------
		 * castVote
		 * 	Applies the needed styles to show the current rating.
		 * ------------------------------------------------------------------- */
		
		var castVote = function (rate) {
			$.post(options.file, { "rate": rate, "token": options.token, "item": options.item }, function (res) { voteResult(res); }, "json");
		}
		
		/* -------------------------------------------------------------------
		 * voteResult
		 * 	Receives the vote result from the php script.
		 * ------------------------------------------------------------------- */
		
		var voteResult = function (res) {
			if (res){
                            if (res.token) $('input[name=token]').val(res.token);
                            if  (res.rating && res.votes){
                                var rate;

                                if (parseFloat(res.rating) > 0) rate = res.rating;
                                else rate = 0;

                                if (rate > 0) _average = roundToHalf(rate);
                                _enabled = false;

                                showAverage();
                                $('#votesholder').html(res.votes);
                                options.change.call(this);
                            }
                        }
		}
		
		/* -------------------------------------------------------------------
		 * showAverage
		 * 	Applies the needed styles to show the current rating.
		 * ------------------------------------------------------------------- */
		 
		var showAverage = function () {
			resetRating();
			_stars.each(function () {
				if ($(this).attr('title') <= _average) {
					$(this).addClass('active');
				} else {
					if (Math.round(_average) == $(this).attr('title')) {
						$(this).addClass('halfactive');
					} else {
						$(this).removeClass('active').removeClass('halfactive');
					}
				}
			});
		}
		
		/* -------------------------------------------------------------------
		 * resetRating
		 * 	Removes all css styles from the stars.
		 * ------------------------------------------------------------------- */
		
		var resetRating = function () {
			_stars.removeClass('active').removeClass('halfactive').removeClass('hover');
		}
		
		/* -------------------------------------------------------------------
		 * roundToHalf
		 * 	Rounds a number to the nearest half integer.
		 * ------------------------------------------------------------------- */
		
		var roundToHalf = function (v) {
			var c = parseFloat(v);
		   	var d = (c - parseInt(c, 10));
		   	d = Math.round(d * 10);
		   	if (d == 5) return (parseInt(c, 10) + 0.5);
		   	if ((d < 3) || (d > 7)) {
			  	return Math.round(c);
		   	} else {
			  	return (parseInt(c, 10) + 0.5);
		   	}
		}
		
		/* -------------------------------------------------------------------
		 * enableRating
		 * 	Enables the voting.
		 * ------------------------------------------------------------------- */
		
		this.enableRating = function () {
			_enabled = true;
		}
		
		/* -------------------------------------------------------------------
		 * disableRating
		 * 	Disables the voting.
		 * ------------------------------------------------------------------- */
		
		this.disableRating = function () {
			_enabled = false;
		}
		
		/* INITIALIZATION ---------------------------------------------------- */
		
		init();
		bindEvents();
	};
	
	$.fn.starrate = function (settings) {
		return this.each(function () {
			var element = $(this);
			
			if (element.data('starrate')) return;
			
			var starrate = new StarRate(this, settings);
			
			element.data('starrate', starrate);
		});
	};

}) (jQuery);
