;(function($) {
// Provide user-controlled star ratings
$.fn.Stars = function(options) {
  var opts = $.extend({}, $.fn.Stars.defaults, options);

  return this.each(function() {
    var $this = $(this);

    // A major shortcoming of jQuery: no clean way to add methods to
    // specific UI elements.  Do so here by merging an instance
    // dictionary -- variables and methods -- from a prototype.
    $.extend(this, $.fn.Stars.prototype);
    this._init(opts);
  });

  // private function for debugging
  function debug($obj) {
    if (window.console && window.console.log) {
      window.console.log($obj);
    }
  }
};

$.fn.Stars.prototype = {
    // Protected ivars:
    _x: 0,
    _y: 0,

    /**
     * Constructor
     * @param {Object} options
     */
    _init: function(opts) {
        this._initialized = false;

        // Save a copy of options.
        // Support for the Metadata Plugin.
        var o = $.meta ? $.extend({}, opts, $this.data()) : opts;
    
        this.options = $.extend({}, o);
        
        this.locked = this.options.locked ? true : false;
        /**
         * Image sources for hover and user-set state ratings
         */
        this._starSrc = {
            empty: this.options.imagePath + "star-empty.gif",
            full: this.options.imagePath + "star.gif",
            half: this.options.imagePath + "star-half.gif"
        };
        /**
         * Preload images
         * TODO:  preload only once, for all instances
         */
        for(var x in this._starSrc)
        {
            var y = $("<img/>");
            y.attr("src", this._starSrc[x]);
        }

        /**
         * Images to show for pre-set values, changes when hovered, if not locked.
         */
        this._setStarSrc = {
            empty: this.options.imagePath + "star-ps-empty.gif",
            full: this.options.imagePath + "star-ps.gif",
            half: this.options.imagePath + "star-ps-half.gif"
        };

        /**
         * Preload images
         */
        for(var x in this._setStarSrc)
        {
            var y = $("<img/>");
            y.attr("src", this._setStarSrc[x]);
        }

        this.value = -1;
        this.stars = [];
        this._clicked = false;


        if(this.options.container)
        {
            this._container = $(this.options.container);
            this.id = this._container.id;
        }
        else
        {
            this.id = 'starsContainer.' + Math.random(0, 100000);
            this._container = $('<span></span>');
            this._container.attr('id', this.id);
            $(document).append(this._container);
        }
        this._display();
        this.setValue(this.options.value);
        this._initialized = true;
    },
    _display: function()
    {
        for(var i = 0; i < this.options.maxRating; i++)
        {
            var star = $("<img/>");
            star.src = this.locked ? this._starSrc.empty : this._setStarSrc.empty;
            star.css('cursor', 'pointer');
            star.attr('title', 'Rate as ' + (i + 1));
            star.data("star.value", (i + 1));
            
            var that = this;
            !this.locked && star.mouseover(function(e) {
                that._starHover(e);
            });
            !this.locked && star.click(function(e) {
                that._starClick(e);
            });
            !this.locked && star.mouseout(function(e) {
                that._starClear(e);
            });
            this.stars.push(star);
            this._container.append(star);
        }
    },
    _starHover: function(e)
    {
        if(this.locked) return;
        var star = $(e.target);
        var value = star.data("star.value");

        var greater = false;
        for (var i = 0; i < this.stars.length; i++) {
            var s = this.stars[i];
            var greater = (s.data("star.value") > value);
            s.attr('src', greater ? this._starSrc.empty : this._starSrc.full);
        }
    },
    _starClick: function(e)
    {
        if(this.locked) return;
        var star = $(e.target);
        this.setValue(star.data("star.value"));
        this._clicked = true;
    },
    _starClear: function(e)
    {
        if(this.locked && this._initialized) return;

        for (var i = 0; i < this.stars.length; i++) {
            var greater = (i > this.value);

            if((this._initialized && this._clicked) || this.value == -1) {
                this.stars[i].attr('src', greater ? (this.value + .5 == i) ? this._starSrc.half : this._starSrc.empty : this._starSrc.full);
            } else {
                this.stars[i].attr('src',  greater ? (this.value + .5 == i) ? this._setStarSrc.half : this._setStarSrc.empty : this._setStarSrc.full);
            }
        }
    },
    setValue: function(val)
    {
        if(this.locked && this._initialized) return;
        this.value = val - 1;
        if(this.options.bindField) {
            $(this.options.bindField).val(val);
        }
        if(this._initialized)
        {
            if(this.options.actionURL) {
                $.get(this.options.actionURL + val, this.options['callback']);
            } else {
                if(this.options.callback) {
                    this.options['callback'](val);
                }
            }
        }
        this._starClear();
    }
};

// default options
$.fn.Stars.defaults = {
    _x: 0,
    _y: 0,
    bindField: null,            // Form Field to bind the value to
    maxRating: 5,               // Maximum rating, determines number of stars
    container: null,            // Container of stars
    imagePath: 'images/',       // Path to star images
    callback: null,             // Callback function, fires when the stars are clicked
    actionURL: null,            // URL to call when clicked. The rating will be appended to the end of the URL (eg: /rate.php?id=5&rating=)
    value: 0,                   // Initial Value
    locked: false
};

})(jQuery);

