/**
 * jQuery Raty - A Star Rating Plugin - http://wbotelhos.com/raty
 * --------------------------------------------------------------------------
 *
 * jQuery Raty is a plugin that generates a customizable star rating automatically.
 * 
 * Licensed under The MIT License
 * 
 * @version     0.5
 * @since       11.06.2010
 * @author      Washington Botelho dos Santos
 * @link        http://wbotelhos.com/raty
 * @twitter     http://twitter.com/wbotelhos
 * @license     http://www.opensource.org/licenses/mit-license.php MIT 
 * @package     jQuery Plugins
 * 
 * Usage (default values):
 * --------------------------------------------------------------------------
*	$('div#star').raty({
 *		cancelHint:   'cancel this rating!',                           // The hint information.
 *		cancelOff:    'cancel-off.png'                                 // The image of the off cancel.
 *		cancelOn:     'cancel-on.png'                                  // The image of the on cancel.
 *		cancelPlace:  'left',                                          // Position of the cancel button.
 *		hintList:     ['bad', 'poor', 'regular', 'good', 'gorgeous'],  // A hint information for default 5 stars.
 *		number:       5,                                               // Number of star.
 *		path:         'img,                                            // Path of images.
 *		readOnly:     false,                                           // read-only or not.
 *		scoreName:    'score',                                         // The name of target score.
 *		showCancel:   false,                                           // If will be showed a button to cancel the rating.
 *		showHalf:     false,                                           // Active the half star.
 *		starHalf:     'star-half.png',                                 // The image of the half star.
 *		start:        0,                                               // Start with a score value.
 *		starOff:      'star-off.png',                                  // The image of the off star.
 *		starOn:       'star-on.png'                                    // The image of the on star.
 *      //onClick:    function() { alert('clicked!'); }                // A default function can to be setted here.
 *	});
 *  
 *  <div id="star"></div>
 *
 * Public functions:
 * --------------------------------------------------------------------------
 *  $.fn.raty.start(3);                                              // Starting the rating with 3 stars later.
 *  $.fn.raty.readOnly(true);                                        // Adjusts the rating for read-only later.
 *  $.fn.raty.click(2);                                              // Click in a star later.
 *
 *  Should come after the current raty and before the anothers one. Because it takes the last called raty.
 *
 */

(function($) {

	// TODO: How to handle a particular container from a public function?
	var Raty=function($this){
		this.$this=$this;
	};
	Raty.prototype.readOnly= function(boo) {
		if (boo) {
			$('img.' + $(this.$this).attr('id')).die();
			$(this.$this).css('cursor', 'default').die();
		} else { 
			this.liveEnter();
			this.liveLeave();
			this.liveClick();
			$(this.$this).css('cursor', 'pointer');
		}
		return this;
	};
	Raty.prototype.start = function(start) {
		this.initialize(start);
		return this;
	};
	Raty.prototype.click = function(score) {
		var star = (score >= this.$this.options.number) ? this.$this.options.number : score;
		this.initialize(star);
		if (this.$this.options.onClick) {
			this.$this.options.onClick(star);
		} else {
			debug('You should add the "onClick: function() {}" option.');
		}
		return this;
	};
	Raty.prototype.liveEnter = function() {
		var id = $(this.$this).attr('id');
		var images=$('img.' + id);
		for(var i=0;i<images.length;i++)
				images[i].options=this.$this.options;
		$('img.' + id).live('mouseenter', function() {
			var id = $(this).attr('id').replace(/^(.+)-\d$/,"$1");
			var qtyStar = $('img.' + id).length;

			for (var i = 1; i <= qtyStar; i++) {
				if (i <= this.alt) {
					$('img#' + id + '-' + i).attr('src', this.options.path + this.options.starOn);
				} else {
					$('img#' + id + '-' + i).attr('src', this.options.path + this.options.starOff);
				}
				if (this.options.onFocus) { 
					this.options.onFocus(this.alt);
			    }
			}
		});
	};
		
	Raty.prototype.liveLeave= function() {
		
		$(this.$this).live('mouseleave', function() {
			var id  =$(this).attr('id').replace(/^(.+)-\d$/,"$1");
			var qtyStar = $('img.' + id).length;
			var score = $('input#' + id + '-score').val();

			for (var i = 1; i <= qtyStar; i++) {
				if (i <= score) {
					$('img#' + id + '-' + i).attr('src', this.options.path + this.options.starOn);
				} else {
					$('img#' + id + '-' + i).attr('src', this.options.path + this.options.starOff);
				}
				if (this.options.onBlur) { 
					this.options.onBlur(this.alt);
			    }
			}
		});		
	};
	
	Raty.prototype.liveClick = function() {
		var id = $(this.$this).attr('id');
		$('img.' + id).live('click', function() {
			$('input#' + id + '-score').val(this.alt);
			if (this.options.onClick) { 
				this.options.onClick(this.alt);
		    }
		});
	};
	
	Raty.prototype.initialize = function(start) {
		var id = $(this.$this).attr('id'),
			qtyStar = $('img.' + id).length;
		$('input#' + id + '-score').val(start);

		for (var i = 1; i <= qtyStar; i++) {
			if (i <= start) {
				$('img#' + id + '-' + i).attr('src', this.$this.options.path + this.$this.options.starOn);
			} else {
				$('img#' + id + '-' + i).attr('src', this.$this.options.path + this.$this.options.starOff);
			}
		}
	};
		
	Raty.prototype.debug=function(message) {
		if (window.console && window.console.log) {
			window.console.log(message);
		}
	};
	
	$.fn.raty= function(settings) {
				options = $.extend({}, $.fn.raty.defaults, settings);
				if (this.attr('id') === undefined) {
					debug('Invalid selector!'); return;
				}

				var $this = $(this);
				$this[0].options=options;
				if (options.number > 20) {
					options.number = 20;
				}

				if (options.path.substring(options.path.length - 1, options.path.length) != '/') {
					options.path += '/';
				}

				// TODO: Using var for values that will be used into a function later (live/bind), to keep the current value and not the last one. Why, Mr. Anderson? Why? 
				var containerId = $this.attr('id'),
					path = options.path,
					cancelOff = options.cancelOff,
					cancelOn = options.cancelOn,
					showHalf = options.showHalf,
					starHalf = options.starHalf,
					starOff = options.starOff,
					starOn = options.starOn,
					onClick = options.onClick,
					onFocus = options.onFocus,
					onBlur = options.onBlur,
					start = 0,
					hint = '';

				if (!isNaN(options.start) && options.start > 0) {
					start = (options.start > options.number) ? options.number : options.start;
				}

				for (var i = 1; i <= options.number; i++) {
					hint = (options.number <= options.hintList.length && options.hintList[i - 1] !== null) ? options.hintList[i - 1] : i;	// Avoids a nonexistent index (undefined) and ensures that the hint will be applied, it means different from null. Otherwise applies the current number.

					starFile = (start >= i) ? starOn : starOff;

					$this
					.append('<img id="' + containerId + '-' + i + '" src="' + path + starFile + '" alt="' + i + '" title="' + hint + '" class="' + containerId + '"/>')
					.append((i < options.number) ? '&nbsp;' : '');
				}

				$this.append('<input id="' + containerId + '-score" type="hidden" name="' + options.scoreName + '"/>');

				$('#' + containerId + '-score').val(start);

				if (showHalf) {
					var score = $('input#' + containerId + '-score').val(),																	// [x ... x.25] || [x.26 ... x.75] || [x.76 ... (x + 1)]
						rounded = Math.ceil(score),																							// (x + 1)
						diff = (rounded - score).toFixed(1);																				// [0.9 ... 0.8] || [0.7 ... 0.3] || [0.2 ... 0]

					if (diff >= 0.3 && diff <= 0.7) {																						// 3.5			In the center interval the score is with a next star.
						rounded = rounded - 0.5;																							// 3 . half
						$('img#' + containerId + '-' + Math.ceil(rounded)).attr('src', path + starHalf);									// 				The next star is the half star.
					} else if (diff >= 0.8) {																								// 3			In the bottom interval the score is rounded down.
						rounded--;																											// 3 . --
					} else {																												// 4 . --		In the top interval the score is the same rounded top.
						$('img#' + containerId + '-' + rounded).attr('src', path + starOn);
					}
				}

				if (!options.readOnly) {
					if (options.showCancel) {
						var cancel = '<img src="' + path + options.cancelOff + '" alt="x" title="' + options.cancelHint + '" class="button-cancel"/>'; 

						if (options.cancelPlace == 'left') {
							$this.prepend(cancel + '&nbsp;');
						} else {
							$this.append('&nbsp;').append(cancel);
						}

						$this.css('width', options.number * 20 + 20);

						$('#' + containerId + ' img.button-cancel')
						.live('mouseenter', function() {
							$(this).attr('src', path + cancelOn);
							$('img.' + containerId).attr('src', path + starOff);
						})
						.live('mouseleave', function() {
							$(this).attr('src', path + cancelOff);
							$('img.' + containerId).trigger('mouseout');
						})
						.live('click', function() {
							$('input#' + containerId + '-score').val(0);
							if (onClick) { 
					          onClick(0);
					        }
						});
					} else {
						$this.css('width', options.number * 20);
					}

					$('img.' + containerId)
					.live('mouseenter', function() {
						var qtyStar = $('img.' + containerId).length;

						for (var i = 1; i <= qtyStar; i++) {
							if (i <= this.alt) {
								$('img#' + containerId + '-' + i).attr('src', path + starOn);
							} else {
								$('img#' + containerId + '-' + i).attr('src', path + starOff);
							}
						}
						if (onFocus) {
							onFocus(this.alt);
						} 
					})
					.live('click', function() {
						$('input#' + containerId + '-score').val(this.alt);
						if (onClick) { 
				          onClick(this.alt);
				        }
					});

					$this.live('mouseleave', function() {
						var id = $(this).attr('id'), qtyStar = $('img.' + id).length, score = $('input#' + id + '-score').val();

						for (var i = 1; i <= qtyStar; i++) {
							if (i <= score) {
								$('img#' + id + '-' + i).attr('src', path + starOn);
							} else {
								$('img#' + id + '-' + i).attr('src', path + starOff);
							}
						}

						if (showHalf) {
							var score = $('input#' + id + '-score').val(), rounded = Math.ceil(score), diff = (rounded - score).toFixed(1);

							if (diff >= 0.3 && diff <= 0.7) {
								rounded = rounded - 0.5;
								$('img#' + id + '-' + Math.ceil(rounded)).attr('src', path + starHalf);
							} else if (diff >= 0.8) {
								rounded--;
							} else {
								$('img#' + id + '-' + rounded).attr('src', path + starOn);
							}
						}
						if (onBlur) {
							onBlur(score);
						} 
					}).css('cursor', 'pointer');
				} else {
					$this.css('cursor', 'default');
				}

				this[0].raty=new Raty($this[0]);
				return this[0].raty;
		};
	$.fn.raty.defaults= {
			cancelHint:		'cancel this rating!',
			cancelOff:		'cancel-off.png',
			cancelOn:		'cancel-on.png',
			cancelPlace:	'left',
			hintList:		['bad', 'poor', 'regular', 'good', 'gorgeous'],
			number:			5,
			path:			'img/',
			readOnly:		false,
			scoreName:		'score',
			showCancel:		false,
			showHalf:		false,
			starHalf:		'star-half.png',
			start:			0,
			starOff:		'star-off.png',
			starOn:			'star-on.png'
			//onClick:		function() { alert('clicked!'); }
		}
})(jQuery);
