/*
 * Event class
 * ===========
 * Author: Barak Ulmann, dreamer_yet@hotmail.com
 * Description: global add event handler function
 * based on the DynLayer technology. learn more about the DynDuo and cross-browser dhtml in:
 * http://www.dansteinman.com/dynduo/
 * Last Updated: June 20th 2004
 *
 * IMPORTANT! the addEventHandler function overwrites the event handler. if it was already
 * set then the it 'older' event handler is appended. however if event handler was defined
 * as in the following example (IE allowable syntax):
 *		function document.onclick()
 *		{
 *			// do something
 *		}
 * a runtime error 'stack overflow' or worse an ilegal recursive call will be generated.
 * this could be avoided by using one of the following common event handler definitions:
 *		document.onclick = new Function(...) or
 *		document.onclick = func
 */

// ========================================================================
//	function: Event()
//
//	description: event class constructor
//
//	parameters:
//		e	- object. optional event object. not IE required
// ========================================================================
function Event(e)
{
	// this class requires browsercheck.js file to be included
	if (typeof(BrowserCheck) != 'function')
		return;
	
	// initialize the browser checkobject
	if (!Event.browser)
		Event.browser = new BrowserCheck();
	
	// reference to event object
	this.event = !e? event: e;
	
	// set event source element
	if (this.event.srcElement)
		this.srcElement = this.event.srcElement;
	else if (this.event.currentTarget)
		this.srcElement = this.event.currentTarget;
	
	// set event type
	this.type = this.event.type;
	
	// mouse event additional properties
	if (this.type == 'click' || /^mouse/.test(this.type)) {
		// set mouse coordinates and clicked mouse button type
		if (Event.browser.ns4) {
			this.x = this.event.pageX;
			this.y = this.event.pageY;
		}
		else if (Event.browser.ie4) {
			this.x = this.event.x + document.body.scrollLeft;
			this.y = this.event.y + document.body.scrollTop;
		}
		else if (Event.browser.ie) {
			this.x = this.event.clientX + document.body.scrollLeft;
			this.y = this.event.clientY + document.body.scrollTop;
			this.button = [Event.Button.None, Event.Button.Left, Event.Button.Right, Event.Button.None, Event.Button.Middle][this.event.button]; // e.button: 1=left,2=right,4=middle
		}
		else if (Event.browser.ns && Event.browser.version >= 5) {
			this.x = this.event.clientX;
			this.y = this.event.clientY;
			this.button = [Event.Button.Left, Event.Button.Middle, Event.Button.Right][this.event.button]; // e.button: 0=left,1=middle,2=right
		}
		
		// set event from element
		if (this.event.fromElement)
			this.fromElement = this.event.fromElement;
		else if (this.event.relatedTarget)
			this.fromElement = this.event.relatedTarget;
	}
	
	// key event additional properties
	if (/^key/.test(this.type)) {
		this.key = this.event.keyCode? this.event.keyCode: this.event.which;
		this.char = String.fromCharCode(this.key);
		this.shiftKey = this.event.shiftKey;
		this.ctrlKey = this.event.ctrlKey;
	}
}

/*
 * Section: event class methods
 */

// cancel bubble method
Event.prototype.cancelBubble = function()
{
	this.event.cancelBubble = true;
}

/*
 * Section: event global functions
 */

function EventAddEventHandler(
	eventRef	// reference to event handler
	,handler	// a function or string to be added to event handler
	,pos		// an ineger indicating the order of evaluation.
				//	 -1: call new handler before evaluating current handler
				//	  0: new handler replaces current handler
				//    1: call new handler after current handler evaluated
	)
{
	if (typeof(handler) != 'string' && typeof(handler) != 'function') return;
	if (arguments.length == 3 && isNaN(pos)) return;
	
	var param = '', eventStr, parsedEventObj, parsedHandlerObj;
	
	if (typeof(handler) == 'function') // parse function
		parsedHandlerObj = new Event.parseFunction(handler);
	
	if (eventRef && (typeof(eventRef) == 'object' || typeof(eventRef) == 'function') && pos) {
		// parse event handler
		parsedEventObj = new Event.parseFunction(eventRef);
		param = parsedEventObj.arguments;
		if (parsedEventObj.name != 'anonymous')
			eventStr = parsedEventObj.name + '(' + param + ')';
		else
			eventStr = parsedEventObj.body;
		if (typeof(handler) == 'function') {
			if (param.length == 0) param = parsedHandlerObj.arguments;
			if (parsedHandlerObj.name != 'anonymous')
				handler = parsedHandlerObj.name + '(' + param + ')';
			else
				handler = parsedHandlerObj.body;
		}
		
		handler = pos > 0? eventStr + '\n' + handler: handler + '\n' + eventStr;
	}
	else if (typeof(handler) == 'function') {
		param = parsedHandlerObj.arguments;
		if (parsedHandlerObj.name != 'anonymous')
			handler = parsedHandlerObj.name + '(' + param + ')';
		else
			handler = parsedHandlerObj.body;
	}
	
	return new Function(param,handler);
}
Event.addEventHandler = EventAddEventHandler;

function EventParseFunction(funcRef)
{
	var funcStr = funcRef.toString();
	this.name = funcStr.replace(/^(\s*function\s+)(\w+)([\s\S]+)$/,'$2');
	this.arguments = funcStr.replace(/^(\s*function\s+\w+\s*\()(\w*)([\s\S]+)$/,'$2');
	this.body = funcStr.substring(funcStr.indexOf('{') + 1, funcStr.lastIndexOf('}')).replace(/^\s+/,'').replace(/\s+$/,'');
}
Event.parseFunction = EventParseFunction;

// addEvent and removeEvent
// cross-browser event handling for IE5+,  NS6 and Mozilla
// By Scott Andrew
Event.addEvent = function(i_oElm, i_sEvType, i_oFunc, i_bUseCapture)
{
	if (!i_oElm || !i_oFunc)
		return false;
	
	// trim leading 'on'
	if (/^on/.test(i_sEvType))
		i_sEvType = i_sEvType.substring(2);
	
	if (i_oElm.addEventListener) {
		if (i_sEvType == 'readystatechange')
			i_sEvType = 'DOMContentLoaded';
		i_oElm.addEventListener(i_sEvType, i_oFunc, i_bUseCapture);
		return true;
	}
	else if (i_oElm.attachEvent) {
		var r = i_oElm.attachEvent('on' + i_sEvType, i_oFunc);
		return r;
	}
}

// mouse button types enum
Event.Button = {None:-1, Left:0, Middle:1, Right:2};

// key types enum
Event.Key = {
	Tab:9, Enter:13, Shift:16, Ctrl:17, Esc:27,
	Up:38, Down:40, Left:37, Right:39, Delete:46, 
	Key0:48, Key1:49, Key2:50, Key3:51, Key4:52,
	Key5:53, Key6:54, Key7:55, Key8:56, Key9:57};
