var EventHandler = {};

EventHandler.type = "EventHandler";
EventHandler.anonymousFunctions = { 
	functionCounter: 0,
	registerAnonymous: function(funcName, handler){
		while(funcName in this){
			funcName = funcName + "_" + this.functionCounter;
			this.functionCounter++;
		}
		this[funcName] = handler;
		return funcName;
    }
 };
 
if (document.addEventListener){
    EventHandler.register = function(element, type, handler, isAnonymous){
		if(isAnonymous)
			isAnonymous = this.anonymousFunctions.registerAnonymous(isAnonymous, handler);
		element.addEventListener(type, handler, false);
		return isAnonymous;
    };
    
    EventHandler.unregister = function(element, type, handler, isAnonymous){
		if(isAnonymous)
			if(isAnonymous in this.anonymousFunctions)
				handler = this.anonymousFunctions[isAnonymous];
        element.removeEventListener(type, handler, false);
        if(isAnonymous)
			if(isAnonymous in this.anonymousFunctions)
				delete this.anonymousFunctions[isAnonymous];
    };
}else{
    EventHandler.registeredHandlers = new Array();
    
    EventHandler.unregisterAllHandlers = function(){
        if(document.eventHandler){
            var ev = (this.type == "EventHandler")?this:document.eventHandler;
            for(var i=0; i<ev.registeredHandlers.length;i++)
                ev.unregister(ev.registeredHandlers[i].element, ev.registeredHandlers[i].type, ev.registeredHandlers[i].wrapper || ev.registeredHandlers[i].handler);           
            document.eventHandler = null;
        }
    }
    
    EventHandler.findHandler = function(element, type, handler){
        for (var i = 0; i<this.registeredHandlers.length; i++){
            if(this.registeredHandlers[i].element == element && this.registeredHandlers[i].type == type && this.registeredHandlers[i].handler == handler)
                return i;
        }
        return -1;
    };
    
    EventHandler.getHandlerWrapper = function(element, handler){
        var handlerWrapper = function(ev){
            if(!ev)ev = window.event;
            var e = {
                event: ev,
                type: ev.type,
                target: ev.srcElement,
                currentTarget: element,
                relatedTarget: (ev.type == "mouseout")? ev.toElement : ev.fromElement,
                eventPhase: (ev.srcElement==element)?2:3,
                
                clientX: ev.clientX,
                clientY: ev.clientY,
                screenX: ev.screenX,
                screenY: ev.screenY,
                altKey: ev.altKey,
                ctrlKey: ev.ctrlKey,
                shiftKey: ev.shiftKey,
                charCode: ev.keyCode,
                
                stopPropagation: function(){this.event.cancelBubble = true;},
                preventDefault: function(){this.event.returnValue = false;} 
            };  
            if(Function.prototype.call)
                handler.call(element, e);
            else{
                element.cH = handler;
                element.cH(e);
                element.cH = null;
            }
        };
        return handlerWrapper;
    };
    
    if(document.attachEvent){
        EventHandler.register = function(element, type, handler, isAnonymous){
            if(this.findHandler(element, type, handler) != -1) return;
             var newEvent = this.getHandlerWrapper(element, handler);
             if(isAnonymous)
				isAnonymous = EventHandler.anonymousFunctions.registerAnonymous(isAnonymous, newEvent);
            element.attachEvent("on"+type, newEvent);
            this.registeredHandlers.push({element: element, type: type, handler: handler, wrapper: newEvent });
            return isAnonymous;
        };
        
        EventHandler.unregister = function(element, type, handler, isAnonymous){
            var handlerIndex = this.findHandler(element, type, handler);            
            var curHandler;
            if(handlerIndex != -1)
				curHandler = this.registeredHandlers[handlerIndex].wrapper;
            if(isAnonymous)
				if(isAnonymous in this.anonymousFunctions)
					curHandler = this.anonymousFunctions[isAnonymous];
			if(!curHandler) return;
            element.detachEvent("on"+type, curHandler);
            this.registeredHandlers.splice(handlerIndex, 1);
            if(isAnonymous)
				if(isAnonymous in this.anonymousFunctions)
					delete this.anonymousFunctions[isAnonymous];
        };
        
    }else{
        EventHandler.register = function(element, type, handler, isAnonymous, reRegister){
            if(!reRegister)
                if(this.findHandler(element, type, handler) != -1) return;
            if(isAnonymous)
				isAnonymous = this.anonymousFunctions.registerAnonymous(isAnonymous, handler);
            var oldEvent = element["on"+type];
            var newEvent = this.getHandlerWrapper(element, handler); 
            if (typeof element["on"+type] != 'function')
                element["on"+type] = function(e) {newEvent(e)};
            else {
                element["on"+type] = function(e) {
                    oldEvent(e);
                    newEvent(e);
                }
            }
            if(!reRegister)
                this.registeredHandlers.push({element: element, type: type, handler: handler });
            return isAnonymous;
        };
        
        EventHandler.unregister = function(element, type, handler, isAnonymous){          
            var handlerIndex = this.findHandler(element, type, handler);
            if(handlerIndex == -1) return;
            element["on"+type] =  null;
            if(isAnonymous){
				if(isAnonymous in this.anonymousFunctions)
					delete this.anonymousFunctions[isAnonymous];
			}   
            if(Array.prototype.splice)
                this.registeredHandlers.splice(handlerIndex, 1);
            else{//if the browser does not support attachEvent, chances are it does not support splice either
                var newHandlers = new Array();
                for (var i = 0; i<this.registeredHandlers.length; i++){
                    if(i != handlerIndex)
                        newHandlers.push(this.registeredHandlers[i]);
                }
                this.registeredHandlers = newHandlers;
            }
            for (var i = 0; i<this.registeredHandlers.length; i++){            
                if(this.registeredHandlers[i].element == element && this.registeredHandlers[i].type == type)
                    this.register(element, type, this.registeredHandlers[i].handler, true);
            }         
        };
    }
}
if(!document.eventHandler)
    document.eventHandler = EventHandler;
if(!document.addEventListener)
    document.eventHandler.register(window, "unload", function(){document.eventHandler.unregisterAllHandlers();});

