/*!
 * jQuery UI Stars v@VERSION@
 *
 * Copyright (c) @YEAR@ Orkan (orkans@gmail.com)
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 * $Rev: 32 $
 * $Date:: 2008-10-17 #$
 * $Build: @BUILD@ (@DATE@)
 *
 * Depends:
 *    ui.core.js
 *
 */
;(function($) {

    $.widget("ui.stars", {
        _init: function() {
            var self = this, o = this.options;
            o.isSelect = o.inputType == "select";

            this.$selec = o.isSelect ? $("select", this.element) : null;
            this.$rboxs = o.isSelect ? $("option", this.$selec) : $(":radio", this.element);

            // TODO : Add non-input star genrator
            this.$stars = this.$rboxs.map(function(i) {
                if(i==0) {
                    o.split = typeof o.split != "number" ? 0 : o.split;
                    o.val2id = [];
                    o.id2val = [];
                    o.id2title = [];
                    o.name = o.isSelect ? self.$selec.get(0).name : this.name;
                    o.disabled = o.disabled || (o.isSelect ? $(self.$selec).attr('disabled') : $(this).attr('disabled'));
                    o.items = 0;
                }
                o.items++;

                o.val2id[this.value] = i;
                o.id2val[i] = this.value;
                o.id2title[i] = (o.isSelect ? this.text : this.title) || this.value;

                if(o.selected==i || (o.selected==-1 && (o.isSelect ? this.defaultSelected : this.defaultChecked) )) {
                    o.checked = i;
                    o.value = o.id2val[i];
                    o.title = o.id2title[i];
                }

                var $s = $("<div/>").addClass(o.starClass);
                var $a = $('<a/>').attr("title", o.showTitles ? o.id2title[i] : "").text(this.value);

                // Prepare division settings
                if(o.split) {
                    var oddeven = (i % o.split);
                    var stwidth = Math.floor(o.starWidth / o.split);
                    $s.width(stwidth);
                    $a.css("margin-left", "-"+(oddeven*stwidth)+"px");
                }

                return $s.append($a).get(0);
            });

            this.$cancel = $("<div/>").addClass(o.cancelClass).append( $("<a/>").attr("title", o.showTitles ? o.cancelTitle : "").text(o.cancelValue) );
            this.$value = $('<input type="hidden" name="'+o.name+'" value="'+o.value+'" />');

            o.cancelShow &= !o.disabled && !o.oneVoteOnly;

            // Stars interface
            if(o.cancelShow) this.element.append(this.$cancel);
            this.element.append(this.$stars);
            this.element.append(this.$value);

            // Replace content
            o.isSelect ? this.$selec.remove() : this.$rboxs.remove();

            // Initial selection
            if(o.checked === undefined) {
                o.checked = -1;
                o.value = o.cancelValue;
                o.title = "";
                if(o.cancelShow) this._disableCancel();
            }
            else {
                fillTo(o.checked, false);
            }

            if(o.disabled) this.disable();


            // Clean up to avoid memory leaks in certain versions of IE 6
            $(window).bind("unload", function(){
                self.$cancel.unbind(".stars");
                self.$stars.unbind(".stars");
                self.$selec = self.$rboxs = self.$stars = self.$value = self.$cancel = null;
            });

            // Remove selection
            function fillNone() {
                self.$stars.removeClass([o.starOnClass, o.starHoverClass].join(' '));
                self._showCap("");
            }

            // Fill stars to the current index
            function fillTo(index, hover) {
                if(index != -1) {
                    var addClass = hover ? o.starHoverClass : o.starOnClass;
                    var remClass = hover ? o.starOnClass : o.starHoverClass;
                    self.$stars.eq(index).prevAll("."+o.starClass).andSelf().removeClass(remClass).addClass(addClass);
                    self.$stars.eq(index).nextAll("."+o.starClass).removeClass([o.starHoverClass, o.starOnClass].join(' '));
                    self._showCap(o.id2title[index]);
                }
                else fillNone();
            }

            // Attach star event handler
            this.$stars.bind("click.stars", function() {
                if(!o.forceSelect && o.disabled) return false;

                var i = self.$stars.index(this);
                o.checked = i;
                o.value = o.id2val[i];
                o.title = o.id2title[i];
                self.$value.attr({disabled: o.disabled ? "disabled" : "", value: o.value});

                fillTo(i, false);
                self._disableCancel();

                if(!o.forceSelect) {
                    //self.disable();
                    self.callback("star");
                }
            })
            .bind("mouseover.stars", function() {
                if(o.disabled) return false;
                var i = self.$stars.index(this);
                fillTo(i, true);
            })
            .bind("mouseout.stars", function() {
                if(o.disabled) return false;
                fillTo(self.options.checked, false);
            });

            this.$cancel.bind("click.stars", function() {
                if( !o.forceSelect && (o.disabled || (o.value == o.cancelValue)) ) return false;

                o.checked = -1;
                o.value = o.cancelValue;
                o.title = "";
                self.$value.attr({value: o.value, disabled: "disabled"});

                fillNone();
                self._disableCancel();

                if(!o.forceSelect) {
                    //self.disable();
                    self.callback("cancel");
                }
            })
            .bind("mouseover.stars", function() {
                if(self._disableCancel()) return false;
                self.$cancel.addClass(o.cancelHoverClass);
                fillNone();
                self._showCap(o.cancelTitle);
            })
            .bind("mouseout.stars", function() {
                if(self._disableCancel()) return false;
                self.$cancel.removeClass(o.cancelHoverClass);
                self.$stars.triggerHandler("mouseout.stars");
            });
        },
        select: function(val) {
            var o = this.options;
            o.forceSelect = true;
            if(val==o.cancelValue) this.$cancel.triggerHandler("click.stars");
            else                                     this.$stars.eq(o.val2id[val]).triggerHandler("click.stars");
            o.forceSelect = false;
        },
        selectID: function(id) {
            var o = this.options;
            o.forceSelect = true;
            if(id==-1)    this.$cancel.triggerHandler("click.stars");
            else                this.$stars.eq(id).triggerHandler("click.stars");
            o.forceSelect = false;
        },
        enable: function() {
            this.options.disabled = false;
            this._disableAll();
        },
        disable: function() {
            this.options.disabled = true;
            this._disableAll();
        },
        _disableCancel: function() {
            var o = this.options, disabled = o.disabled || o.oneVoteOnly || (o.value == o.cancelValue);
            if(disabled)    this.$cancel.removeClass(o.cancelHoverClass).addClass(o.cancelDisabledClass);
            else                    this.$cancel.removeClass(o.cancelDisabledClass);
            this.$cancel.css("opacity", disabled ? 0.5 : 1);
            return disabled;
        },
        _disableAll: function() {
            var o = this.options;
            this._disableCancel();
            if(o.disabled)    this.$stars.filter("div").addClass(o.starDisabledClass);
            else                        this.$stars.filter("div").removeClass(o.starDisabledClass);
        },
        _showCap: function(s) {
            var o = this.options;
            if(o.captionEl) o.captionEl.text(s);
        },
        destroy: function() {
            this.options.isSelect ? this.$selec.appendTo(this.element) : this.$rboxs.appendTo(this.element);
            this.$cancel.unbind('.stars').remove();
            this.$stars.unbind('.stars').remove();
            this.$value.remove();
            this.element.unbind('.stars').removeData('stars');
        },
        callback: function(type) {
            var o = this.options;
            o.callback(this, type, o.value);
            if(o.oneVoteOnly && !o.disabled) this.disable();
        }
    });


    $.ui.stars.defaults = {
        inputType: "radio", // radio|select
        split: 0,
        selected: -1,
        disabled: false,
        cancelTitle: "Cancel Rating",
        cancelValue: 0,
        cancelShow: true,
        oneVoteOnly: false,
        showTitles: false,
        captionEl: null,
        callback: function(el,type,value){},

        // CSS classes
        starWidth: 16,
        cancelClass: 'ui-stars-cancel',
        starClass: 'ui-stars-star',
        starOnClass: 'ui-stars-star-on',
        starHoverClass: 'ui-stars-star-hover',
        starDisabledClass: 'ui-stars-star-disabled',
        cancelHoverClass: 'ui-stars-cancel-hover',
        cancelDisabledClass: 'ui-stars-cancel-disabled'
    };

})(jQuery);
