var EventCache = Class.create();
EventCache.globalCache = [];
EventCache.unloadAll = function(){
  while(EventCache.globalCache.length){
    EventCache.globalCache.shift().clear();
  }
};

EventCache.prototype = {
  initialize: function(){
    this.cache = {};
    this.cacheIndex = 0;
    EventCache.globalCache.push(this);
  },

  clear: function(){
    for (var key in this.cache){
      M4Event._stopObserving.apply(this, this.cache[key]);
      delete this.cache[key];
    }
  },

  observe: function(element, name, observer, useCapture){
    this.cache[++this.cacheIndex] = [element, name, observer, useCapture];
    M4Event._observe(element, name, observer, useCapture);
    return this.cacheIndex;
  },

  stopObserving: function(element, name, observer, useCapture){
    if(!arguments.length){ this.clear(); return; }
    if(this.cache[element]){
      M4Event._stopObserving.apply(this,this.cache[element]);
      delete this.cache[element];
      return;
    }

    for (var key in this.cache ){
      if( (element == this.cache[key][0]) &&
          (!name || name == this.cache[key][1]) &&
          (!observer || observer == this.cache[key][2]) &&
          (useCapture === this.cache[key][3])
      ){
        M4Event._stopObserving.apply(this,this.cache[key]);
        delete this.cache[key];
        if(name && observer){ return; } //short circuit if not using wildcards
      }
    }
  }
};


var M4Event = new EventCache();

Object.extend(M4Event, {
  _observe: function(element, name, observer, useCapture){
    element = $(element);
    name = this._getEventName(name);
    useCapture = useCapture || false;
    try{
      element[M4Event._addFnName](name, observer, useCapture);
    } catch (e) {}
  },

  _stopObserving: function(element, name, observer, useCapture) {
    element = $(element);
    name = M4Event._getEventName(name);
    useCapture = useCapture || false;
    try {
      element[M4Event._removeFnName](name, observer, useCapture);
    } catch (e) {}
  },

  unloadCache: EventCache.unloadAll
});

if( window.addEventListener )
{
  M4Event._addFnName = 'addEventListener';
  M4Event._removeFnName = 'removeEventListener';
  M4Event._getEventName = ( navigator.appVersion.match(/Konqueror|Safari|KHTML/) ?
    function(name){ return name == 'keypress' ? 'keydown' : name; } :
    function(name){ return name; } );
}
else if( window.attachEvent )
{
  M4Event._addFnName = 'attachEvent';
  M4Event._removeFnName = 'detachEvent';
  M4Event._getEventName = function(name)
  {
    return 'on'+(name == 'keypress' ? 'keydown' : name);
  };
  
  window.attachEvent('onunload', EventCache.unloadAll);
}




/******************************************************************************
M4Behaviour
by Chris Exon. Copyright Macro4 plc. 2007

A replacement class for behaviour.js. Needs prototype 1.5.1 or above to run.

Uses css selectors to apply javascript behaviours to enable
unobtrusive javascript in html documents. Protects against IE memory leaks

All calls to M4Behaviour.apply called before window.onload are cached, and executed
on the page onload event. Any calls after that are applied immediately.

var tabEvents=
{
    "#updateTabName":{
        click:function(e)
        {
            magikTabMenu.updateTabName();
        }
    },
    
    ".setNumCols input":{
        click:function(e)
        {
            magikTabMenu.changeNumberOfColumns(this);
        }    
    }
}

M4Behaviour.apply(tabEvents,"tabMenu");

*******************************************************************************/
var M4Behaviour={
    
    list : new Array(),
    started : false,
    
    start : function()
    {
        if (M4Behaviour.started==false)
        {
            M4Behaviour._pageLoaded();
            M4Behaviour.started=true;
        }
    },
    
    apply : function(aSelectors,aStartElement,group)
    {
        aStartElement=(!aStartElement) ? document : aStartElement;
        //If the page hasn't finished loading then cache until it has
        if (this.started==false)
        {
            M4Behaviour.list[M4Behaviour.list.length]={selectors:aSelectors, start:aStartElement};
        }
        else
        {
            M4Behaviour._apply(aSelectors,aStartElement,group);
        }    
    },
    
    _pageLoaded : function()
    {        
        for (var i=0;i<M4Behaviour.list.length;i++)
        {
            M4Behaviour._apply(M4Behaviour.list[i].selectors,M4Behaviour.list[i].start);
        }
        
        M4Behaviour.list=new Array();
    },
    
    _apply: function(selectors,startElement,group)
    {
       var eventObj=(!group) ? Event : group;
       
        for (selector in selectors)
        {
            $css(selector,startElement).each(
                function(el) 
                {                    
                    var events=selectors[selector];
                    
                    for (ev in events)
                    {
                    	eventObj.observe(el,ev,events[ev].bindAsEventListener(el));
                    }
                }
            );
        }
    }
}

/******************************************************************************
** m4EventObserve
**
** Wrapper function for Event.observe. Only applies event if the object exists
******************************************************************************/
function m4EventObserve(obj,evnt, func)
{
	if ($(obj))
	{
		Event.observe(obj,evnt,func);
	}
}

//This will register the M4Behaviour to run on pageload. If M4Behaviour.start has been
//manually called before that then the start function will do nothing
Event.observe(window,"load",M4Behaviour.start);