/* Unobtrusive Javascript framework, version 0.1
 * (c) July 2006 Elmar Keij
 * Based largely on the work of Ben Nolan
 *
 * Description:
 *   Uses css selectors to apply javascript behaviours to enable
 *   unobtrusive javascript in (x)html documents.
 *
 * Credits:
 *   behavior object based upon - Behaviour v1.1 by Ben Nolan, June 2005.
 *   addHandler function based upon - addLoadEvent by Simon Willison and addEvent by Mark Wubben
 *   document.getElementsBySelector function - Prototype $$() selector function
 *   eventHandlers associative array notation - Dave Herman
 *        http://www.ccs.neu.edu/home/dherman/javascript/behavior/
 *
 * License:
 *   This file is entirely BSD licensed.
 *
 * Usage - automatic:
 *  var eventHandlers = {
 *   'b.someclass' : {
 *     onclick : function(){alert(this.innerHTML);}
 *   },
 *   '#someid u' :
 *     onmouseover : function(){this.innerHTML = "BLAH!";}
 *   };
 *
 * Behaviour.register(eventHandlers);
 *
 * Usage - manual:
 * Behaviour.addOnLoadHandler(somefunction);
 * Behaviour.addHandler(someobject, 'onmouseover', funtion(){alert("Test");});
 */

var Behaviour = {
  eventHandlers : null,

  // constructor
  create : function(){
    Behaviour.addOnLoadHandler(Behaviour.addHandlers);
  },

  // register an array of eventHandlers
  register : function(eventHandlers){
    Behaviour.eventHandlers = eventHandlers;
  },

  // add an event handler on an event of a object
  // it also propagates the event object
  // the context parameter is optional
  addHandler : function(object, event, handler, context) {
    var oldHandler = object[event];
    
    if(context){
      method = handler;
      handler = function(e){return method.call(context, e);};
    }

    if (typeof oldHandler != 'function')
      object[event] = handler;
    else
      object[event] = function(){
        _comp(function(e){handler(e); return e},oldHandler);
      }
  },

  // add eventhandler on the onload event of window
  addOnLoadHandler : function(handler) {
    Behaviour.addHandler(window, 'onload', handler);
  },

  // add eventhandler on the onerror event of window
  addOnErrorHandler : function(handler) {
    Behaviour.addHandler(window, 'onerror', handler);
  },

  // add eventhandler on the onunload event of window
  addOnUnLoadHandler : function(handler) {
    Behaviour.addHandler(window, 'onunload', handler);
  },

  // add the list of eventHandlers
  addHandlers : function(){
    var elements;

    // foreach selector in our list
    for(var selector in Behaviour.eventHandlers) {
      elements = $$(selector);
      if (!elements)
        continue;

      // foreach selected element
      for(i = 0; element = elements[i]; i++) {

        // foreach event, declared for an element, add eventhandler
        for(var event in Behaviour.eventHandlers[selector]) {
          Behaviour.addHandler(element, event , Behaviour.eventHandlers[selector][event]);
        }
      }
    }
  }
}

Behaviour.create();

/* Haskell like function composition*/
function _comp (f, g) {
  var result;

  if(typeof f == 'function' && typeof g == 'function') {
    result = g();
    result = f(result);
  }

  return result;
}

/* Haskell like function application */
function _app (f, x) {
  var result_x;

  if(typeof x == 'function')
    result_x = x();
  else if(typeof x == 'array')
    result_x = x;
  else
    result_x = [x];

  return f.apply(this, result_x);
}

/* Apply function f and g in sequence */
function _seq (f, g) {
  if(typeof f == 'function' && typeof g == 'function') {
    f();
    g();
  }
}

/* Alias for the ProtoType $$() element selector */
document.getElementsBySelector = function(){return $$.apply(this, arguments);};