/**
 * 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 1.3.2
 * @since 06.11.2010
 * @author Washington Botelho dos Santos
 * @documentation http://wbotelhos.com/raty
 * @twitter http://twitter.com/wbotelhos
 * @license http://opensource.org/licenses/mit-license.php
 * @package jQuery Plugins
 * 
 * Usage with default values:
 * ---------------------------------------------------------------------------------
 * $('#star').raty();
 * 
 * <div id="star"></div>
 * 
 * 
 * $('.group').raty();
 * 
 * <div class="group"></div> <div class="group"></div> <div class="group"></div>
 * 
 */

;
(function($) {

	$.fn.raty = function(settings) {
		
		options = $.extend({}, $.fn.raty.defaults, settings);

		if (this.length == 0) {
			debug('Selector invalid or missing!');
			return;
		} else if (this.length > 1) {
			return this.each(function() {
				$.fn.raty.apply($(this), [ settings ]);
			});
		}

		if (options.number > 20) {
			options.number = 20;
		} else if (options.number < 0) {
			options.number = 0;
		}

		if (options.path
				.substring(options.path.length - 1, options.path.length) != '/') {
			options.path += '/';
		}

		$global = $(this);

		$global.data('options', options);

		var id = this.attr('id'), start = 0, starFile = options.starOn, hint = '', width = (options.width) ? options.width
				: (options.number * options.size + options.number * 4);

		if (id == '') {
			id = 'raty-' + $global.index();
			$global.attr('id', id);
		}

		if (!isNaN(options.start) && options.start > 0) {
			start = (options.start > options.number) ? options.number
					: options.start;
		}

		for ( var i = 1; i <= options.number; i++) {
			starFile = (start >= i) ? options.starOn : options.starOff;

			hint = (i <= options.hintList.length && options.hintList[i - 1] !== null) ? options.hintList[i - 1]
					: i;

			$global.append('<img id="' + id + '-' + i + '" src="'
					+ options.path + starFile + '" alt="' + i + '" title="'
					+ hint + '" class="' + id + '" onclick="checkNotSure(\''+id+'\',\'off\');" />');
		}

		$('<input/>', {
			id : id + '-score',
			type : 'hidden',
			name : options.scoreName
		}).appendTo($global).val(start);

		if (options.half) {
			splitStar($global, $('input#' + id + '-score').val(), options);
		}

		if (!options.readOnly) {
			if (options.cancel) {
				var star = $('img.' + id), cancel = '<img src="' + options.path
						+ options.cancelOff + '" alt="x" title="'
						+ options.cancelHint + '" class="button-cancel"/>', opt = options, $this = $global;

				if (opt.cancelPlace == 'left') {
					$global.prepend(cancel + '&nbsp;');
				} else {
					$global.append('&nbsp;').append(cancel);
				}

				$('#' + id + ' img.button-cancel').mouseenter(function() {
					$(this).attr('src', opt.path + opt.cancelOn);
					star.attr('src', opt.path + opt.starOff);
					if (opt.mouseenter) {
						opt.mouseenter.apply($this, [ 0 ]);
					}
				}).mouseleave(function() {
					$(this).attr('src', opt.path + opt.cancelOff);
					star.mouseout();
					if (opt.mouseleave) {
						opt.mouseleave.apply($this, [ 0 ]);
					}
				}).click(function() {
					$('input#' + id + '-score').val(0);
					if (opt.click) {
						opt.click.apply($this, [ 0 ]);
					}
				});

				$global.css('width', width + options.size + 4);
			} else {
				$global.css('width', width);
			}

			$global.css('cursor', 'pointer');
			bindAll($global, options);
		} else {
			$global.css('cursor', 'default');
			fixHint($global, start, options);
		}

		return $global;
	};

	function bindAll(context, options) {
		var id = context.attr('id'), score = $('input#' + id + '-score'), qtyStar = $('img.'
				+ id).length;

		// context.
		$('#' + id).mouseleave(function() {
			initialize(context, score.val(), options);
			if (options.mouseleave) {
				options.mouseleave.apply(context, [ score.val() ]);
			}
		});

		$('img.' + id)
				.mousemove(
						function(e) {
							fillStar(id, this.alt, options);

							if (options.half) {
								var percent = parseFloat(((e.pageX - $(this)
										.offset().left) / options.size)
										.toFixed(1));
								percent = (percent >= 0 && percent < 0.5) ? 0.5
										: 1;

								context.data('score', parseFloat(this.alt)
										+ percent - 1);

								splitStar(context, context.data('score'),
										options);
							} else {
								fillStar(id, this.alt, options);
							}
							if (options.mouseenter) {
								options.mouseenter.apply(context, [ this.alt ]);
							}
						}).click(function() {

					score.val(options.half ? context.data('score') : this.alt);

					if (options.click) {
						options.click.apply(context, [ score.val() ]);
					}

					use_id = id;
					if (use_id != 'main-rating' && use_id != 'rating-country') {
						use_id = "extra_review_" + use_id;
					}
					if (!$("#errors-" + use_id).hasClass('solved')) {
						solveUnsolve(use_id, "solve");
					}

				});
	}
	;

	function getContext(value, idOrClass, name) {
		var context = $global;

		if (idOrClass) {
			if (idOrClass.indexOf('.') >= 0) {
				var idEach;

				return $(idOrClass).each(function() {
					idEach = '#' + $(this).attr('id');

					if (name == 'start') {
						$.fn.raty.start(value, idEach);
					} else if (name == 'click') {
						$.fn.raty.click(value, idEach);
					} else if (name == 'readOnly') {
						$.fn.raty.readOnly(value, idEach);
					}
				});
			}

			context = $(idOrClass);

			if (!context.length) {
				debug('"'
						+ idOrClass
						+ '" is a invalid identifier for the public funtion $.fn.raty.'
						+ name + '().');
				return;
			}
		}

		return context;
	}
	;

	function debug(message) {
		if (console && console.log) {
			console.log(message);
		}
	}
	;

	function fillStar(id, score, options) {
		var qtyStar = $('img.' + id).length, item = 0, range = 0, star, starOn;

		for ( var i = 1; i <= qtyStar; i++) {
			star = $('img#' + id + '-' + i);

			if (i <= score) {
				if (options.iconRange && options.iconRange.length > item) {

					starOn = options.iconRange[item][0];
					range = options.iconRange[item][1];

					if (i <= range) {
						star.attr('src', options.path + starOn);
					}

					if (i == range) {
						item++;
					}
				} else {
					star.attr('src', options.path + options.starOn);
				}
			} else {
				star.attr('src', options.path + options.starOff);
			}
		}
	}
	;

	function fixHint(context, score, options) {
		if (score != 0) {
			score = parseInt(score);
			hint = (score > 0 && options.number <= options.hintList.length && options.hintList[score - 1] !== null) ? options.hintList[score - 1]
					: score;
		} else {
			hint = options.noRatedMsg;
		}

		$('#' + context.attr('id')).attr('title', hint).children('img').attr(
				'title', hint);
	}
	;

	function initialize(context, score, options) {
		var id = context.attr('id');

		if (score < 0 || isNaN(score)) {
			score = 0;
		} else if (score > options.number) {
			score = options.number;
		}

		$('input#' + id + '-score').val(score);

		fillStar(id, score, options);

		if (options.half) {
			splitStar(context, score, options);
		}

		if (options.readOnly || context.css('cursor') == 'default') {
			fixHint(context, score, options);
		}
	}
	;

	function splitStar(context, score, options) {
		var id = context.attr('id'), 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',
					options.path + options.starHalf);
		} else if (diff >= 0.8) {
			rounded--;
		} else {
			$('img#' + id + '-' + rounded).attr('src',
					options.path + options.starOn);
		}
	}
	;

	$.fn.raty.click = function(score, idOrClass) {
		var context = getContext(score, idOrClass, 'click'), options = $(
				idOrClass).data('options');

		initialize(context, score, options);

		if (options.click) {
			options.click.apply(context, [ score ]);
		} else {
			debug('You must add the "click: function(score) { }" callback.');
		}

		return $.fn.raty;
	};

	$.fn.raty.mouseenter = function(score, idOrClass) {
		var context = getContext(score, idOrClass, 'click'), options = $(
				idOrClass).data('options');

		initialize(context, score, options);

		if (options.mouseenter) {
			options.mouseenter.apply(context, [ score ]);
		} else {
			debug('You must add the "click: function(score) { }" callback.');
		}

		return $.fn.raty;
	};

	$.fn.raty.mouseleave = function(score, idOrClass) {
		var context = getContext(score, idOrClass, 'click'), options = $(
				idOrClass).data('options');

		initialize(context, score, options);

		if (options.mouseleave) {
			options.mouseleave.apply(context, [ score ]);
		} else {
			debug('You must add the "click: function(score) { }" callback.');
		}

		return $.fn.raty;
	};

	$.fn.raty.readOnly = function(boo, idOrClass) {
		var context = getContext(boo, idOrClass, 'readOnly'), cancel = context
				.children('img.button-cancel'), options = $(idOrClass).data(
				'options');

		if (cancel[0]) {
			(boo) ? cancel.hide() : cancel.show();
		}

		if (boo) {
			$('img.' + context.attr('id')).unbind();
			context.css('cursor', 'default').unbind();
		} else {
			bindAll(context, options);
			context.css('cursor', 'pointer');
		}

		return $.fn.raty;
	};

	$.fn.raty.start = function(score, idOrClass) {
		var context = getContext(score, idOrClass, 'start'), options = $(
				idOrClass).data('options');

		initialize(context, score, options);

		return $.fn.raty;
	};

	$.fn.raty.defaults = {
		cancel : false,
		cancelHint : 'cancel this rating!',
		cancelOff : 'cancel-off.png',
		cancelOn : 'cancel-on.png',
		cancelPlace : 'left',
		click : null,
		half : false,
		hintList : [ 'bad', 'poor', 'regular', 'good', 'gorgeous' ],
		noRatedMsg : 'not rated yet',
		number : 5,
		path : 'img/',
		iconRange : [],
		readOnly : false,
		scoreName : 'score',
		size : 16,
		starHalf : 'star-half.png',
		starOff : 'star-off.png',
		starOn : 'star-on.png',
		start : 0,
		width : null
	};

})(jQuery);
