/*  Call this to make some element spring to life as a star rating control.
    For example:
    
      new Rateable('something', {rating:3, send_url:'/rate'});
      
    Creates the stars with JavaScript, which isn't the most accessible solution...


    Author: Michael Daines
*/

var Rateable = Class.create();

Object.extend(Rateable, {
  PUBLIC: 1,
  UNRATED: 2,
  RATED: 4,
  
  // Make a star element.
  make_star: function(color, state, which, binding) {
    if (color == 'red') star = Builder.node('img', {src:'/images/icons/star-red.png'});
    else star = Builder.node('img', {src:'/images/icons/star.png'});
    if (state != Rateable.PUBLIC) {
      star.onmouseover = (function(){this.show_rating(which);this.show_state(Rateable.RATED)}).bind(binding);
      star.onmouseout = (function(){this.show_rating(this.options.rating);this.show_state(this.options.state)}).bind(binding);
      star.onclick = (function(){this.set_rating(which)}).bind(binding);
    }
    return star;
  }
});

Rateable.prototype = {
  
  initialize: function(element) {
    var options = Object.extend({
      max: 5,
      rating: 0,
      state: Rateable.PUBLIC
    }, arguments[1] || {});
    
    this.element = $(element);
    this.options = options;
    
    this.red_stars = Builder.node('span', {style:'display:none'});
    this.yellow_stars = Builder.node('span');
    
    var self = this;
    $R(1,this.options.max).each(function(i) {
      self.red_stars.appendChild(Rateable.make_star('red', self.options.state, i, self));
      self.yellow_stars.appendChild(Rateable.make_star('yellow', self.options.state, i, self));
    });
    
    this.element.appendChild(self.red_stars);
    this.element.appendChild(self.yellow_stars);
    
    this.show_state(this.options.state);
    this.show_rating(this.options.rating);
    
  },
  
  // Update this Rateable's rating and send the rating to the server.
  set_rating: function(rating) {
    this.options.rating = rating;
    this.options.state = Rateable.RATED;
    new Ajax.Request(this.options.send_url, {parameters: 'rating=' + this.options.rating});
  },
  
  // Set the opacity of the stars of this Rateable to show the provided rating
  show_rating: function(rating) {
    var self = this;
    $R(1,this.options.max).each(function(i) {
      Element.setOpacity(self.yellow_stars.childNodes[i-1], (rating >= i ? 1.0 : 0.4));
      Element.setOpacity(self.red_stars.childNodes[i-1], (rating >= i ? 1.0 : 0.4));
    });
  },
  
  // Show the state of this rating as the provided state.
  show_state: function(state) {
    if (state != Rateable.RATED) {
      Element.show(this.red_stars);
      Element.hide(this.yellow_stars);
    } else {
      Element.hide(this.red_stars);
      Element.show(this.yellow_stars);
    }
  }
}