(function ($) {
  $.fn.fhRating = function (options) {
  
    var defaults = {
      animate: {
        duration: 0.2,
        mouseover: false,
        mouseout: true
      },
      mouseOut: false,
      mouseOver: false,
      rating: {
        average: false,
        id: false,
        maximum: 5,
        onRate: false,
        updateUrl: 'test.php?id={ID}&rating={RATING}'
      },
      stars: {
        amount: 5,
        step: 0.5,
        imagePath: 'fh/images/',
        image: 'stars.png',
        width: 20,
        height: 15
      }
    }
    
    for(attr in options) {
      $.extend(defaults[attr], options[attr]);
    }
    
    return this.each(function () {
      
      var _this = $(this);
      
      var ratingBackground = $('<div>').attr({
        'class': 'fh-rating'
      }).css({
        'position': 'relative',
        'width': (defaults.stars.amount / defaults.stars.step) * (defaults.stars.width * defaults.stars.step) + 'px',
        'height': defaults.stars.height + 'px',
        'background': 'url(' + defaults.stars.imagePath + defaults.stars.image + ') repeat-x 0 -' + defaults.stars.height + 'px'
      }).appendTo(_this);
      
      if(defaults.rating.average) _this.data('averageWidth', (defaults.stars.width * defaults.stars.step) * (defaults.rating.average / (defaults.rating.maximum / (defaults.stars.amount / defaults.stars.step))));
      else _this.data('averageWidth', 0);
      var ratingOverlay = $('<div>').attr({
        'class': 'display'
      }).css({
        'position': 'absolute',
        'width': (defaults.rating.average? _this.data('averageWidth'):'0') + 'px',
        'height': defaults.stars.height,
        'background': 'url(' + defaults.stars.imagePath + defaults.stars.image + ') repeat-x 0 0'
      }).appendTo($(ratingBackground));
      for(var i = defaults.stars.step; i <= defaults.stars.amount; i+=defaults.stars.step) {
        var rating = (defaults.rating.maximum / defaults.stars.amount * i);
        if(defaults.rating.updateUrl) {
          var ratingUrl = defaults.rating.updateUrl.split('{ID}').join(defaults.rating.id);
          ratingUrl = ratingUrl.split('{RATING}').join(rating);
        } else {
          var ratingUrl = '#';
        }
        $this = $('<a></a>').attr({
          'href': ratingUrl
        }).css({
          'float': 'left',
          'display': 'block',
          'position': 'absolute',
          'margin': 0,
          'overflow': 'hidden',
          'width': (defaults.stars.width * defaults.stars.step) + 'px',
          'height': defaults.stars.height + 'px',
          'left': (defaults.stars.width * (i - defaults.stars.step)) + 'px'
        }).mouseover(function() {        
          if(defaults.mouseOut) defaults.mouseOut.stop();
          if(defaults.mouseOver) defaults.mouseOver.stop();
          
          if(defaults.animate.mouseover) {
            mouseout: true
            defaults.mouseOver = $(ratingOverlay).animate({
              'width': ($(this).position().left + $(this).width()) + 'px'
            }, defaults.animate.duration * 1000);
          } else {
            $(ratingOverlay).css({
              'width': ($(this).position().left + $(this).width()) + 'px'
            });
          }
        }).mouseout(function() {        
          if(defaults.mouseOut) defaults.mouseOut.stop();
          if(defaults.mouseOver) defaults.mouseOver.stop();

          if(defaults.animate.mouseout) {
            defaults.mouseOut = $(ratingOverlay).animate({
              'width': _this.data('averageWidth') + 'px'
            }, defaults.animate.duration * 1000);
          } else {
            $(ratingOverlay).css({
              'width': _this.data('averageWidth') + 'px'
            });
          }
        }).click(function(){
          $.getJSON($(this).attr('href'), function(json){
            if(json.average) {
              _this.data('averageWidth', (defaults.stars.width * defaults.stars.step) * (json.average / (defaults.rating.maximum / (defaults.stars.amount / defaults.stars.step))));
              $(ratingOverlay).css({
                'width': _this.data('averageWidth') + 'px'
              });
            }
          });
          if(defaults.rating.onRate) {
            setTimeout(defaults.rating.onRate, 0);
          }
          return false;
        }).appendTo($(ratingBackground));
      }
    });
  };
})(jQuery);
