var RatingWidget = Class.create({
  initialize: function(container) {
    this.element = $(container);

    var current_value = this.element.down('input[checked=checked]') ? 
      this.element.down('input[checked=checked]').value : null;

    this.element.select('label').invoke('remove');

    var inputs = this.element.select('input');
    this.name  = inputs.first().getAttribute('name');

    this.input = new Element('input', { 'type': 'hidden', 'name': this.name });
    this.input.value = current_value;

    var form = this.element.up('form');
    form.insert({ 'top': this.input });

    var stars = $A();

    inputs.each(function(inputElement) {
      var star = new RatingWidget.Star(inputElement.value, stars.clone());
      Element.replace(inputElement, star.link);
      stars.push(star);
      if (inputElement.value == current_value) { star.selected() }
    });

    this.stars = stars;

    this.original_value = current_value;

    form.observe('reset', this.reset.bindAsEventListener(this));
    this.element.observe('rating_star:click', this.onstarclick.bindAsEventListener(this));
    this.element.observe('rating_star:mouseout', this.onstarmouseout.bindAsEventListener(this));

    RatingWidget._all.push(this);
  },

  clear: function() {
    this.value       = null;
    this.input.value = null;
    this.stars.invoke('removeClassName', 'over', 'checked');
  },

  reset: function(event) {
    this.stars.invoke('removeClassName', 'over', 'checked');
    var value = this.original_value;
    var star  = this.stars.find(function(s) { return s.value == value });
    if (value && star) {
      this.input.value = value;
      star.selected();
    }
  },

  onstarclick: function(event) {
    this.input.value = event.memo.value;
    this.stars.invoke('removeClassName', 'over', 'checked');
  },

  onstarmouseout: function(event) {
    this.stars.invoke('removeClassName', 'over');
  }
});

RatingWidget._all = $A();

RatingWidget.clear = function() {
  RatingWidget._all.invoke('clear');
}

RatingWidget.Star = Class.create({
  initialize: function(value, siblings) {
    this.value    = value;
    this.siblings = siblings;
    this.link     = new Element('a', { 'href': '#', 'title': this.value }).update(this.value);

    this.link.observe('click', this.onclick.bindAsEventListener(this));
    this.link.observe('keypress', this.onkeypress.bindAsEventListener(this));
    this.link.observe('mouseover', this.onmouseover.bindAsEventListener(this));
    this.link.observe('focus', this.onfocus.bindAsEventListener(this));
    this.link.observe('mouseout', this.onmouseout.bindAsEventListener(this));
    this.link.observe('blur', this.onblur.bindAsEventListener(this));
  },

  selected: function() {
    this.link.fire('rating_star:click', { 'value': this.value });
    $A([this.siblings, this]).flatten().invoke('addClassName', 'checked');
  },

  addClassName: function(class_name) {
    this.link.addClassName(class_name);
  },

  removeClassName: function() {
    var iterator = function(class_name) {
      this.link.removeClassName(class_name);
    }
    $A(arguments).each(iterator.bind(this));
  },

  onclick: function(event) {
    event.stop();
    this.selected();
  },

  onkeypress: function(event) {
    if (event.keyCode == 0) {  // space bar
      event.stop();
      this.selected();
    }
  },

  onmouseover: function(event) {
    $A([this.siblings, this]).flatten().invoke('addClassName', 'over');
  },

  onfocus: function(event) {
    this.link.fire('rating_star:mouseout');
    $A([this.siblings, this]).flatten().invoke('addClassName', 'over');
  },

  onmouseout: function(event) {
    this.link.fire('rating_star:mouseout');
  },

  onblur: function(event) {
    this.link.fire('rating_star:mouseout');
  }
});

document.observe('dom:loaded', function() {
  $$('.rating_widget').each(function(container) {
    new RatingWidget(container);
  });
});