/**
 * Create namespace
 */
nl.xd.XD.namespace( 'nl.xd.event' ) ;

/**
 * Event Class
 * @abstract
 */
nl.xd.event.Event = {
	listeners: [] ,
	
	/**
	 * Adds an event listener to a HTMLElement
	 * 
	 * @param HTMLElement, the html element that fires the Event
	 * @param string, the name of the Event without the 'on'
	 * @param function, the function to call when the Event fires
	 * @return void
	 */
	addListener: function( element , type , func ) {
		this.listeners.push( { element:element , type:type , func:func } ) ;
		
		if ( element.addEventListener ) {
			element.addEventListener( type , func , false ) ;
		} else if ( element.attachEvent ) {
			element.attachEvent( 'on' + type , func ) ;
		} ;
	} ,
	
	/**
	 * Remove an event listener from a HTMLElement
	 * 
	 * @param HTMLElement, the html element that fires the Event
	 * @param string, the name of the Event without the 'on'
	 * @param function, the function to call when the Event fires
	 * @return void
	 */
	removeListener: function( element , type , func ) {
		if ( element.removeEventListener ) {
			element.removeEventListener( type , func , false ) ;
		} else if ( element.detachEvent ) {
			element.detachEvent( 'on' + type , func ) ;
		} ;
		
		var index = -1 ;
		
		for ( var i = 0; i < this.listeners.length; i++ ) {
		 	var listener = this.listeners[ i ] ;
		 	
			if ( listener && listener.func == func && listener.element == element && listener.type == type ) {
				index = i ;
				
				break ;
			} ;
		} ;
		
		if ( index >= 0 ) {
			delete this.listeners[ index ];
		} ;
		
		return true ;
	} ,
	
	/**
	 * Remove all event listeners from their HTMLElements
	 * 
	 * @return void
	 */
	unload: function() {
		for ( var i = 0; i < this.listeners.length; ++i ) {
			this.removeListener( this.listeners[ i ].element , this.listeners[ i ].type , this.listeners[ i ].func ) ;
		} ;
	} ,
	
	/**
	 * Get the Event object
	 * 
	 * @param Event
	 * @return Event object
	 */
	get: function( event ) {
		var e ;
		
		if ( ! event ) {
			e = window.event ;
		} else {
			e = event ;
		} ;
		return e ;
	} ,
	
	/**
	 * @param Event
	 * @return HTMLElement
	 */
	target: function( event ) {
		var target = null ;
		var e      = this.get( event ) ;
		
		if ( e.target  ) {
			target = e.target ;
		} else {
			target = e.srcElement ;
		} ;
		
		target = this.checkTarget( target ) ;
		
		return target ;
	} ,
	
	/**
	 * Get the mouse coordinates
	 * 
	 * @param Event
	 * @return Object (coordinates)
	 */
	client: function( event ) {
		var e   = this.get( event ) ;
		var pos = { x:0 , y:0 } ;
		
		if( e.pageX || e.pageY ) {
			pos.x = e.pageX || 0 ;
			pos.y = e.pageY || 0 ;
		} else {
			pos.x  = e.clientX || 0 ;
			pos.x += document.body.scrollLeft || 0 ;
			pos.x -= document.body.clientLeft || 0 ;
			
			pos.y  = e.clientY || 0 ;
			pos.y += document.body.scrollTop || 0 ;
			pos.y -= document.body.clientTop || 0 ;
		} ;
		
		return pos ;
	} ,
	
	/**
	 * @param Event
	 * @return HTMLElement
	 */
	relatedTarget: function( event ) {
		var e      = this.get( event ) ;
		var target = e.relatedTarget ;
		
		if ( ! target ) {
			if ( e.type == 'mouseout' ) {
				target = e.toElement ;
			} else if ( e.type == 'mouseover' ) {
				target = e.fromElement ;
			} ;
		} ;
		
		target = this.checkTarget( target ) ;
		
		return target ;
	} ,
	
	/**
	 * @param Node
	 * @return Node
	 */
	checkTarget: function( target ) {
		if ( target.nodeType == 3 ) {
			target = target.parentNode ;
		} ;
		
		return target ;
	} ,
	
	/**
	 * @param Event
	 * @return void
	 */
	preventDefault: function( e ) {
		if ( e.preventDefault ) {
			e.preventDefault() ;
		} ;
		
		e.returnValue = false ;
	}
} ;

nl.xd.event.Event.addListener( window , 'unload' , function() { nl.xd.event.Event.unload() ; } ) ;