/**
 * 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?

    $.fn.raty = function (settings) {
    
        options = $.extend({}, $.fn.raty.defaults, settings);
        
        if (this.attr('id') === undefined) {
            debug('Invalid selector!'); return;
        }
        
        $this = $(this);
        
        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,
			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 + '"/>');
        //$this.parent().append('<div style="float: right">' + start + '</div>');
        
        $('#' + 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);
			        }
			    }
			})
			.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);
                    }
                }
            }).css('cursor', 'pointer');
        } else {
            $this.css('cursor', 'default');
        }
        
        return $this;
    };
    
    $.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!'); }
    };

    $.fn.raty.readOnly = function (boo) {
        if (boo) {
            $('img.' + $this.attr('id')).die();
            $this.css('cursor', 'default').die();
        } else {
            liveEnter();
            liveLeave();
            liveClick();
            $this.css('cursor', 'pointer');
        }
        return $.fn.raty;
    };

    $.fn.raty.start = function (start) {
        initialize(start);
        return $.fn.raty;
    };
    
    $.fn.raty.click = function (score) {
        var star = (score >= options.number) ? options.number : score;
        initialize(star);
        if (options.onClick) {
            options.onClick(star);
        } else {
            debug('You should add the "onClick: function() {}" option.');
        }
        return $.fn.raty;
    };
    
    // TODO: Repeated on purpose for now! Because options.x here works as current value, unlike in the function body. Why, Mr. Anderson? Why?
    function liveEnter() {
        var id = $this.attr('id');
        $('img.' + id).live('mouseenter', function () {
            var qtyStar = $('img.' + id).length;

            for (var i = 1; i <= qtyStar; i++) {
                if (i <= this.alt) {
                    $('img#' + id + '-' + i).attr('src', options.path + options.starOn);
                } else {
                    $('img#' + id + '-' + i).attr('src', options.path + options.starOff);
                }
            }
        });
    };
    
    function liveLeave() {
        $this.live('mouseleave', function () {
            var id = $(this).attr('id');
            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', options.path + options.starOn);
                } else {
                    $('img#' + id + '-' + i).attr('src', options.path + options.starOff);
                }
            }
        });
    };
    
    function liveClick() {
        var id = $this.attr('id');
        $('img.' + id).live('click', function () {
            $('input#' + id + '-score').val(this.alt);
        });
    };

    function initialize(start) {
        var id = $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', options.path + options.starOn);
            } else {
                $('img#' + id + '-' + i).attr('src', options.path + options.starOff);
            }
        }
    };
    
    function debug(message) {
        if (window.console && window.console.log) {
            window.console.log(message);
        }
    };
    
})(jQuery);
