/**
 * @fileOverview A collection of functions for event handling.
 * @name EventManager
 */

/** The array of registered events. */
var SeisanEventArray = new Array();


/**
 * 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 SeisanEvent(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);
	}
}

/**
 * Remove all events registered to the object.
 * @param {object} obj the object to remove all events.
 */
function SeisanEventHandlerRemoveEvents(obj){
	var tmp = new Array();
	for(var i=0; i < SeisanEventArray.length; i++){
		if(SeisanEventArray[i].obj != obj){
			tmp.push(SeisanEventArray[i]);
		} 
	}
	SeisanEventArray = tmp;

	for(var i=0; i < obj.childNodes.length; i++){
		SeisanEventHandlerRemoveEvents(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
 */
function SeisanEventHandler(obj, type, functioncall, jsobj){
	SeisanEventArray.push(new SeisanEvent(obj, type, functioncall, jsobj));
	if(type == "mousemove")
		obj.onmousemove = SeisanEventHandlerEvent;
	else if(type == "mousedown")
		obj.onmousedown = SeisanEventHandlerEvent;
	else if(type == "mouseup")
		obj.onmouseup = SeisanEventHandlerEvent;
	else if(type == "mouseout")
		obj.onmouseout = SeisanEventHandlerEvent;
	else if(type == "mouseover")
		obj.onmouseover = SeisanEventHandlerEvent;
	else if(type == "dblclick")
		obj.ondblclick = SeisanEventHandlerEvent;
	else if(type == "click")
		obj.onclick = SeisanEventHandlerEvent;
	else if(type == "mouseenter")
		obj.onmouseenter = SeisanEventHandlerEvent;
	else if(type == "mouseleave")
		obj.onmouseleave = SeisanEventHandlerEvent;
	else if(type == "keypress")
		obj.onkeypress = SeisanEventHandlerEvent;
	else if(type == "keyup")
		obj.onkeyup = SeisanEventHandlerEvent;
	else if(type == "change")
		obj.onchange = SeisanEventHandlerEvent;
	else if(type == "contextmenu")
		obj.oncontextmenu = SeisanEventHandlerEvent;
}

/**
 * trap the registered event an make the call to all events in the event stack
 * @param {event} e the event fired
 */
function SeisanEventHandlerEvent(e){
	if (!e) var e = window.event
	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 < SeisanEventArray.length; i++){
		if(SeisanEventArray[i].obj == targ && type == SeisanEventArray[i].type){
			var t = SeisanEventArray[i].call(e);
			if(t == false)
				rt = false;
		} 
	}
	return rt;
		
}


/** An stack of timeout events registered. */
var SeisanTimeoutArray = 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 SeisanTimeout(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();
	}
}

/**
 * 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
 */

function SeisanSetTimeout(time, functioncall, jsobj){
	var len = -1;
	for(var i=0; i < SeisanTimeoutArray.length; i++){
		if(SeisanTimeoutArray[i].equals(functioncall, jsobj)){
			len = i;
			break;
		}
	}
	if(len < 0){
		len = SeisanTimeoutArray.length;
		SeisanTimeoutArray.push(new SeisanTimeout(functioncall, jsobj));
	}
	return setTimeout("SeisanTimeoutHandler(" + len + ")", time);
}

/**
 * Handles the timeout firing
 * @function 
 * @param {int} num the number in the timeout stack to be executed.
 */
function SeisanTimeoutHandler(num){
	SeisanTimeoutArray[num].call();
}