/* Makes registering behavior through unobtrusive
 * JavaScript easy. Example:
 *
 * new Behavior({
 *   '.new':     function() {...},
 *   '.edit':    function() {...},
 *   '.delete':  function() {...},
 *   '.row:mouseover': function() {...}
 * });
 *
 * Inspired by the behaviour.js by Ben Nolan
 * and Event-Selectors
 * (http://alternateidea.com/event-selectors/).
 */
var Behavior = Class.create({

  /* Registers a new set of behaviors */
  initialize: function(specs /*, options*/) {
    this.specs = specs;
    this.handlers = [];

    this.options = $H({
      auto_apply: true,
      reload_on_ajax: true
    }).merge(arguments[1] || {});

    if(this.options.get('auto_apply'))
      Event.observe(document, 'dom:loaded',
        this.apply.bindAsEventListener(this));

    if(this.options.get('reload_on_ajax'))
      Ajax.Responders.register({
        onComplete: (function() {this.reload()}).bind(this)
      });
  },

  /* Will unregister all events registered through
   * this object and re-apply. This is automatically
   * called after every Ajax request unless you
   * provide the option 'reload_on_ajax' with the
   * value false in the constructor.
   */
  reload: function() {
    this.handlers.each(function(handler) {
      Event.stopObserving.apply(handler[0], handler);
    });
    this.handlers = [];
    this.apply();
  },

  /* Will apply the callbacks to the rules.
   * No need to call this manually as it
   * is automatically called on dom:loaded
   * Unless you provide the option
   * 'auto_apply' with a value of false
   * in the constructor.
   */
  apply: function() {
    for(var rules in this.specs) {
      var behavior = this.specs[rules];
      rules = rules.split(/\s*,\s*/);
      rules.each((function(rule) {
        var selector = rule.split(':')[0];
        var event = rule.split(':')[1] || 'click';

        $$(selector).each((function(element) {
          if(event == 'load') {
            try {
              behavior.bind(element)();
            } catch(e) {
              alert('Error applying: '+rule);
            }
          } else {
            var bound = behavior.bind(element)
            var bound_with_stop = (function(event) {
              try {
                if(bound(event) != false) event.stop()
              } catch(e) {
                event.stop();
                throw e
              }
            }).bindAsEventListener(this);
            Event.observe(element, event, bound_with_stop);
            this.handlers.push([element, event, bound_with_stop]);
          }
        }).bind(this))
      }).bind(this));
    }
  }
});
