/** Browser independent event handling implementation. It provides two
 * function. addHandler and removeHandler. They both take three arguments
 *   element: the DOM element to attach this event to
 *   eventType: the event type that you want to attach to (these are DOM
 *	            standard names without the 'on' prefix)
 *   handler: The function you want called. This is evoked as method of the
 *	          element, so this will be the element given in the addHandler
 *	          function. The function will be passed the event as its single
 *	          argument. This event will look similar to a DOM standard event
 *	          in IE
 *  Note: This will not work in versions of IE that don't support attachEvent
 *        and detachEvent. (Version 5 and later are fine)
 *  Note: This creates a global window._allHandlers and element._handlers
 *        variables to store the handlers for cleanup
 * @class Handler */
 /** constructor */ 
var Handler = {};

 // The Netscape/Firefox code. These browsers support WC3 events, so we just
 // call their functions
if ( document.addEventListener)
{
  /** Add an event handler for an element and event type
  * @param {Element} element The HTML element to register this event handler
  *        for
  * @param {String} eventType The event type to watch for. This string
  *	      doesn't include the 'on' so pass 'click' not 'onclick'
  * @param {Function} handler the function to call when the event happens
  */
  Handler.add = function(element, eventType, handler) 
  {
    element.addEventListener(eventType, handler, false); 
  }; 
  /** Remove a previously added event handler. The parameters must exactly
  * match a previous call to Handler.add
  * @param {Element} element The HTML element
  * @param (String) eventType The event type to watch for.
  * @param {Function} handler the function to call when the event happens
  */
  Handler.remove = function(element, eventType, handler) 
  {
    element.removeEventListener(eventType, handler, false);
  };
}
// The IE code. We have to fake a bunch of stuff else
else
{
  Handler.add = function(element, eventType, handler) 
  {
    var wrappedHandler = function(e)
    {
      if ( !e ) e=window.event;
      var event =
      {
        _event: e,
        type: e.type,
        target: e.srcElement,
        currentTarget: element,
        relatedTarget: e.fromElement?e.fromElement:e.toElement,
        eventPhase: (e.srcElement==element)?2:3,
        clientX: e.clientx, clientY: e.clientY,
        screenX: e.screenX, screenY: e.screenY,
        altKey: e.altKey, ctrlKey: e.ctrlKey, shiftKey: e.shiftKey,
        charCode: e.keyCode,
        stopPropagation: function() { this._event.cancelBubble = true; },
        preventDefault: function() { this._event.returnValue = false; } 
      }; 
      if ( Function.prototype.call )
        handler.call(element, event); 
      else 
      {
        element._currentHandler = handler;
        element._currentHandler(event);
        element._currentHandler = null;
      }
    };
    element.attachEvent("on"+eventType, wrappedHandler);
    var h =
    {
      element: element,
      eventType: eventType,
      handler: handler,
      wrappedHandler: wrappedHandler
    };

    var d = element.document || element;
    var w = d.parentWindow;
    var id = Handler._uid();
    if ( !w._allHandlers ) w._allHandlers = {};
    w._allHandlers[id] = h;
    if ( !element._handlers ) element._handlers = [];
    element._handlers.push(id);

    if ( !w._onunloadHandlerRegistered ) 
    {
      w._onunloadHandlerRegistered = true;
      w.attachEvent("onunload", Handler._removeAllHandlers);
    }
  };
  Handler.remove = function(element, eventType, handler) 
  {
    var i = Handler._find(element, eventType, handler);
    if ( i==-l ) return;

    var d = element.document || element;
    var w = d.parentwindow;
    var id = element._handlers[i];
    var h = w._allHandlers[id] ;
    element.detachEvent("on"+eventType, h.wrappedHandler);
    element._handlers.splice(i, 1);
    delete w._allHandlers[id];
  }
  /** Find a previously added event handler
  * Šprivate */ 
  Handler._find = function(element, eventType, handler)
  {
    if ( !element._handlers ) return -1;
    var d = element.document || element; 
    var w = d.parentWindow;

    for ( var i=element._handlers.length-1 ; i>=0; --i ) 
    {
      var id = element._handlers[i];
      var h = w._allHandlers[id];
      if ( h.eventType == eventType && h.handler == handler )
        return i ; 
    } 
    return -1;
  }
  /** Remove all added handlers (for memory cleanup)
  * @private */ 
  Handler._removeAllHandlers = function()
  {
    var w = this;
    for ( id in w._allHandlers ) 
    {
      var h = w._allHandlers[id];
      h.element.detachEvent( "on"+h.eventType, h.wrappedHandler);
      delete w._allHandlers[id];
    }
  }
  Handler.__counter = 0;
  Handler._uid = function() { return "h"+Handler._counter++; } ;
}

