(function($) {
    
  /**
   * @name gzRating
   * @type jQuery
   * @param Hash o A set of key/value pairs to set as configuration properties.
   * @cat Plugins/gzRating
   */
   
  $.fn.gzRating = function(o) {
    return this.each(function() {
      new $gzr(this, o);
    });
  }
  
  // Default configuration properties.
  var defaults = {
    amount: 5,
    average: false,
    duration: 0.2,
    height: 20,
    id: false,
    image: 'stars.png',
    imagePath: 'web/images/',
    initCallback: null,
    maximum: 5,
    mouseout: true,
    mouseOut: null,
    mouseover: false,
    mouseOver: null,
    numbers: false,
    onClick: null,
    onRate: null,
    step: 0.5,
    updateUrl: null,
    width: 20
  }
  
  $.gzRating = function(e, o){
  
    this.options = $.extend({}, defaults, o || {});
    this.element = $(e);
    
    $(e)
      .css('display', 'inline-block')
      .empty();
     
    
    if(!this.options.id && $(e).attr('id')) {
      this.options.id = $(e).attr('id');
    }
    
    this.ratingBackground = $('<div>')
      .attr({'class': 'gz-rating'})
      .css({
        'display': 'block',
        'position': 'relative',
        'width': (this.options.amount / this.options.step) * (this.options.width * this.options.step) + 'px',
        'height': this.options.height + 'px',
        'background': 'url(' + this.options.imagePath + this.options.image + ') repeat-x 0 -' + this.options.height + 'px'
      })
      .appendTo($(e));
      
    if(this.options.average) this.options.averageWidth = (this.options.width * this.options.step) * (this.options.average / (this.options.maximum / (this.options.amount / this.options.step)));
    
    this.ratingOverlay = $('<div>')
      .attr({'class': 'display'})
      .css({
        'position': 'absolute',
        'left': 0,
        'width': (this.options.average? this.options.averageWidth:'0') + 'px',
        'height': this.options.height,
        'background': 'url(' + this.options.imagePath + this.options.image + ') repeat-x 0 0'
      })
      .appendTo(this.ratingBackground);
      
    var number = 1;
    
    for(var i = this.options.step; i <= this.options.amount; i+=this.options.step) {
      
      var rating = (this.options.maximum / this.options.amount * i);
      if(this.options.updateUrl) {
        var ratingUrl = this.options.updateUrl.split('{ID}').join(this.options.id);
        ratingUrl = ratingUrl.split('{RATING}').join(rating);
      } else {
        var ratingUrl = '#';
      }
      
      var self = this;
      
      var link = $('<a></a>')
        .attr({
          'href': ratingUrl
        })
        .css({
          'display': 'block',
          'position': 'absolute',
          'margin': 0,
          'overflow': 'hidden',
          'width': (this.options.width * this.options.step) + 'px',
          'height': this.options.height + 'px',
          'left': (this.options.width * (i - this.options.step)) + 'px'
        })
        .click(function(e){
          e.preventDefault();
          
          self.setAverage($(this).data('rating'));
          
          if(self.options.onClick){
            self.options.onClick($(this).data('rating'), (self.options.id ? self.options.id : null));
          }
          
          if(self.options.updateUrl){
            $.ajax({
              type: 'GET',
              url: $(this).attr('href'),
              success: function(msg) {
                if(self.options.onRate) {
                  setTimeout(function(){
                    self.options.onRate(msg);
                  }, 0);
                }
              }
            });
          }
        })
        .html((this.options.numbers ? number++ : ''))
        .data('rating', rating)
        .appendTo(this.ratingBackground);

      if(!navigator.userAgent.match(/(iPhone|iPad|iPod)/i)) {
        link
          .mouseover(function() {
            $(this).nextAll().removeClass('active');
            $(this).prevAll().andSelf().addClass('active');
            
            if(self.options.mouseOut) self.options.mouseOut.stop();
            if(self.options.mouseOver) self.options.mouseOver.stop();
            
            if(self.options.mouseover) {
              mouseout: true
              self.options.mouseOver = self.ratingOverlay.animate({
                'width': ($(this).position().left + $(this).width()) + 'px'
              }, self.options.duration * 1000);
            } else {
              self.ratingOverlay.css({
                'width': ($(this).position().left + $(this).width()) + 'px'
              });
            }
          })
          .mouseout(function() {
            if(self.options.average){
              self.element.find('a').filter(function(index){
                if(self.options.amount / self.options.maximum * self.options.average == (index + 1)){
                  $(this).nextAll().removeClass('active');
                  $(this).prevAll().andSelf().addClass('active');
                }
              });
            }else{
              $(this).prevAll().andSelf().removeClass('active');
            }
            
            if(self.oxptions.mouseOut) self.options.mouseOut.stop();
            if(self.options.mouseOver) self.options.mouseOver.stop();
            
            if(self.options.mouseout) {
              self.options.mouseOut = self.ratingOverlay.animate({
                'width': (self.options.average? self.options.averageWidth:'0') + 'px'
              }, self.options.duration * 1000);
            } else {
              self.ratingOverlay.css({
                'width': (self.options.average? self.options.averageWidth:'0') + 'px'
              });
            }
          })
      }
      
    }
    
    if(this.options.initCallback != null)
        this.options.initCallback(this);
  };

  // Create shortcut for internal use
  var $gzr = $.gzRating;

  $gzr.fn = $gzr.prototype = {
    gzRating: '0.2.3'
  };

  $gzr.fn.extend = $gzr.extend = $.extend;
  
  $gzr.fn.extend({
    
    setAverage: function(amount){
    
      var self = this;
      
      this.options.average = amount;
      this.options.averageWidth = (this.options.width * this.options.step) * (this.options.average / (this.options.maximum / (this.options.amount / this.options.step)));
      
      if(this.options.mouseOut) this.options.mouseOut.stop();
      if(this.options.mouseOver) this.options.mouseOver.stop();
      
      if(this.options.mouseout) {
        this.options.mouseOut = this.ratingOverlay.animate({
          'width': (this.options.average? this.options.averageWidth:'0') + 'px'
        }, this.options.duration * 1000);
      } else {
        this.ratingOverlay.css({
          'width': (this.options.average? this.options.averageWidth:'0') + 'px'
        });
      }
      
      this.element.find('a').filter(function(index){
        $(this).removeClass('active');
        if(self.options.amount / self.options.maximum * self.options.average == (index + 1)){
          $(this).prevAll().andSelf().addClass('active');
        }
      });
    },
    
    clearAverage: function(){
      this.setAverage(0);
    }
    
  });
  
})(jQuery);

