JAME.Package('JAME.Events');

JAME.Events =  {
	
	Normalize : function(event) {

    	event = event || window.event;

    	if(window.event) {

        	event.preventDefault = function() {
             	this.returnValue= false;
        	};
        	event.stopPropagation = function() {
            	this.cancelBubble = true;
        	};
        	event.target = event.srcElement;       

        	event.relatedTarget = (event.fromElement == event.target) 
                                ? event.toElement 
                                : event.fromElement;
    	}
		if(!event.target) return event;
    	if (event.target.nodeType == 3) event.target = event.target.parentNode;

    	if ( event.pageX == null && event.clientX != null ) {
        	var e = document.documentElement, b = document.body;
        	event.pageX = event.clientX + (e && e.scrollLeft || b.scrollLeft || 0);
        	event.pageY = event.clientY + (e && e.scrollTop || b.scrollTop || 0);    
    	}

    	if ( event.layerX == null && event.offsetX != null ) {
        	event.layerX = event.offsetX || 0;
        	event.layerY = event.offsetY || 0;
    	}

    	if ( !event.which && (event.charCode || event.keyCode) )
      		event.which = event.charCode || event.keyCode;
    
    	if ( !event.metaKey && event.ctrlKey )
      		event.metaKey = event.ctrlKey;

    	if ( !event.which && event.button )
      		event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));
      
    	return event;
	},
	
	addListener : function (elm,evt, func,bind) {

		if (!elm.listeners) elm.listeners = {};

		if (!elm.listeners[evt]) elm.listeners[evt] = [];

		for(var i=0;i<elm.listeners[evt].length;i++){
			if(elm.listeners[evt][i]===func) {
				JAME.warn('the same event '+evt+' is set for '+elm+' ',-1);
				return false;
			}
		}
		elm.listeners[evt].push(func);
		if(bind===undefined)
			func.____willBindTo=elm;
		else 
			func.____willBindTo=bind;

		if(!window.attachEvent)
			evt = (evt=='mouseenter')?'mouseover':(evt=='mouseleave')?'mouseout':evt;	
		elm["on" + evt] = JAME.Events._handleEvent;
		return elm;
	},

	_isChild : function(parent,child) {
		if(parent === child) return false;

		while (child && child!==parent)
			child= child.parentNode;
		return child===parent;
	},

	_handleLeaveEnterEvent : function (evt) {

		var relatedTarget = evt.relatedTarget;

		if(this ===relatedTarget || JAME.Events._isChild(this,relatedTarget)) return;

		var listeners = this.listeners[evt.type=='mouseover'?'mouseenter':'mouseleave'];
		var ln     = listeners.length;
		var ret;
		for (var i=0; i<ln; i++) {
			ret = listeners[i].call(listeners[i].____willBindTo, evt);
			if (i === (ln - 1))
				return ret;
		}
	},

	_handleEvent : function (evt) {

		evt = JAME.Events.Normalize(evt);

		if(evt.type=='mouseover' && !window.attachEvent && this.listeners['mouseenter']){
			JAME.Events._handleLeaveEnterEvent.call(this,evt);
		}
		if(evt.type=='mouseout' && !window.attachEvent && this.listeners['mouseleave']){
			JAME.Events._handleLeaveEnterEvent.call(this,evt);
		}

		var listeners = this.listeners[evt.type];
		if(!listeners) return;
		var ln     = listeners.length;

		var ret;
		for (var i=0; i<ln; i++) {
			ret = listeners[i].call(listeners[i].____willBindTo, evt);
			if (i === (ln - 1))
				return ret;
		}

	},
	removeListener : function (elm,evt, func) {
		if(!elm) return;
		if(!evt) return;
		if(!elm.listeners) return;
		var listeners = elm.listeners[evt];
		if(!listeners) return;
		if(!func) 
			return JAME.Events.removeListeners(elm,[evt]);
		var ln = listeners.length;
		for (var i=0; i<ln; i++) {
			if (listeners[i] === func) {
				//avoid leaks
				//if(func.____willBindTo) func.____willBindTo=null;
				delete listeners[i];
				listeners.splice(i, 1);
			}
		}
		return true;
	},
	removeListeners : function (elm,evts) {
		evts = (evts.constructor===Array) ?evts :[evts];
		for(var i=0,ln=evts.length;i<ln;i++)
			elm.listeners[evts[i]]=[];
		return true;
	}
};


JAME.Events.EventDispatcher = function() {this.listeners = {}};

JAME.Events.EventDispatcher.prototype = {
    dispatch : function(evt) {
        var listeners = (this.listeners[evt]) ?this.listeners[evt].length : 0;
        for(var i=0;i<listeners;i++)
            this.listeners[evt][i].apply(this,arguments);
        return this;
    },
    addListener : function (evt,func) {
        if(!this.listeners[evt]) this.listeners[evt]=[];
        this.listeners[evt].push(func);
    },
    removeListener : function (evt,func) {
		JAME.Events.removeListener(this,evt,func);
    }
};



