/**
 * @fileOverview A collection of functions for event handling.
 * @name EventManager
 */


/**
 * An Event Object.
 * @constructor
 * @param {object} obj the event is called on.
 * @param {string} event the event tyoe
 * @config {function} functioncall the function to call on an event
 * @config {object} [jsobj] The object to call the function against.
 */
function EventObject(obj, event, functioncall, jsobj){
	this.obj = obj;
	this.type = event;
	this.functioncall = functioncall;
	this.jsobj = jsobj;
	
	/**
	 * call this's function with the event given.
	 * @function
	 * @param {e} event object generated by the Seisan Event Handler
	 */
	this.call = function(e){
		if(this.jsobj){
			var funct = this.functioncall
			this.jsobj.tmp = funct;
			return this.jsobj.tmp(e);
		}
		else 
			return this.functioncall(e);
	}
}


	/** An stack of timeout events registered. */
	this.TimeoutArray = new Array();

/**
 * a timeout event object.
 * @constructor
 * @param {function} functioncall the function to call on an event firing
 * @param {object} [jsobj] the object to make the function call against
 */
function TimeoutObject(functioncall, jsobj){
	this.functioncall = functioncall;
	this.jsobj = jsobj;
	
	/**
	 * returns if this's properties equal the ones given
	 * @function 
	 * @param {function} f the function to call on an event firing
	 * @param {object} [obj] the object to make the function call against
	 */
	this.equals = function(f, obj){
		return (f== this.functioncall && this.jsobj == obj)
	}
	
	/**
	 * call the function defined by this
	 * @function 
	 */
	this.call = function(){
		if(this.jsobj){
			var funct = this.functioncall
			this.jsobj.tmp = funct;
			return this.jsobj.tmp();
		}
		else 
			return this.functioncall();
	}
}

/** The array of registered events. */
var EventManager = new function(){
	this.RegisteredEventArray = new Array();

	this.removeAllEvents = function(){
	
	}

	/**
	 * Remove all events registered to the object.
	 * @param {object} obj the object to remove all events.
	 */
	this.removeEvents = function(obj){
		var tmp = new Array();
		for(var i=0; i < EventManager.RegisteredEventArray.length; i++){
			if(EventManager.RegisteredEventArray[i].obj != obj){
				tmp.push(EventManager.RegisteredEventArray[i]);
			} 
		}
		EventManager.RegisteredEventArray = tmp;

		for(var i=0; i < obj.childNodes.length; i++){
			this.RemoveEvents(obj.childNodes[0]);
		}
		
	}

	/**
	 * registered to the object the event type specified.
	 * @param {object} obj the object to register the event.
	 * @param {string} type the type of the event ("click", "mouseover", etc)
	 * @param {function} functioncall the function to call on an event firing
	 * @param {object} [jsobj] the object to make the function call against
	 */
	this.addEvent = function(obj, type, functioncall, jsobj){
		EventManager.RegisteredEventArray.push(new EventObject(obj, type, functioncall, jsobj));
		
		if(type == "mousemove"){
			obj.onmousemove = EventManager._eventHandler;
		}
		else if(type == "mousedown"){
			obj.onmousedown = EventManager._eventHandler;
		}
		else if(type == "mouseup")
			obj.onmouseup = EventManager._eventHandler;
		else if(type == "mouseout")
			obj.onmouseout = EventManager._eventHandler;
		else if(type == "mouseover")
			obj.onmouseover = EventManager._eventHandler;
		else if(type == "dblclick")
			obj.ondblclick = EventManager._eventHandler;
		else if(type == "click")
			obj.onclick = EventManager._eventHandler;
		else if(type == "mouseenter")
			obj.onmouseenter = EventManager._eventHandler;
		else if(type == "mouseleave")
			obj.onmouseleave = EventManager._eventHandler;
		else if(type == "keypress")
			obj.onkeypress = EventManager._eventHandler;
		else if(type == "keyup")
			obj.onkeyup = EventManager._eventHandler;
		else if(type == "change")
			obj.onchange = EventManager._eventHandler;
		else if(type == "contextmenu")
			obj.oncontextmenu = EventManager._eventHandler;
	}

	/**
	 * trap the registered event an make the call to all events in the event stack
	 * @param {event} e the event fired
	 */
	this._eventHandler = function(e){
		var targ;
		if (!e) var e = window.event
		if (e.currentTarget) targ = e.currentTarget
		else if (e.srcElement) targ = e.srcElement
		if (targ.nodeType == 3)
			targ = targ.parentNode
		var type = e.type;
		
		e.targ = targ;
		e.key = (e.which) ? e.which : e.keyCode;
			
		var rt = true;
		for(var i=0; i < EventManager.RegisteredEventArray.length; i++){
			if(EventManager.RegisteredEventArray[i].obj == targ){
				if(type == EventManager.RegisteredEventArray[i].type){
					var t = EventManager.RegisteredEventArray[i].call(e);
					if(t == false)
						rt = false;
				}
			} 
		}
		return rt;
			
	}



	/**
	 * register this event
	 * @function 
	 * @param {int} time the timeout in milliseconds
	 * @param {function} f the function to call on an event firing
	 * @param {object} [obj] the object to make the function call against
	 */

	this.setTimeout = function(time, functioncall, jsobj){
		var len = -1;
		for(var i=0; i < this.TimeoutArray.length; i++){
			if(this.TimeoutArray[i].equals(functioncall, jsobj)){
				len = i;
				break;
			}
		}
		if(len < 0){
			len = SeisanTimeoutArray.length;
			this.TimeoutArray.push(new TimeoutObject(functioncall, jsobj));
		}
		return setTimeout("EventManager._timeoutHandler(" + len + ")", time);
	}

	/**
	 * Handles the timeout firing
	 * @function 
	 * @param {int} num the number in the timeout stack to be executed.
	 */
	this._timeoutHandler = function(num){
		this.TimeoutArray[num].call();
	}
}
