function EventListener(type, listener, useCapture) {
	this.type = type;
	this.listener = listener;
	this.useCapture = useCapture;
	this.handleEvent = function(evt) {
		if (!this.removed && evt.type == this.type && !this.useCapture)
			listener.apply(evt.currentTarget, [evt]);
	}
}
function EventListenerList() {
	var list = new Array();
	list.item = function(index) { return list[index]; }
	return list;
}
var Event = (function() {
	var eventType = new Array();
	eventType["click"]     = {bubbles:true, cancelable:true};
	eventType["mousedown"] = {bubbles:true, cancelable:true};
	eventType["mouseup"]   = {bubbles:true, cancelable:true};
	eventType["mouseover"] = {bubbles:true, cancelable:true};
	eventType["mousemove"] = {bubbles:true, cancelable:false};
	eventType["mouseout"]  = {bubbles:true, cancelable:true};
	eventType["keydown"]   = {bubbles:true, cancelable:true};
	eventType["keyup"]     = {bubbles:true, cancelable:true};
	eventType["keypress"]  = {bubbles:true, cancelable:true};
	eventType["load"]      = {bubbles:false,cancelable:false};
	eventType["unload"]    = {bubbles:false,cancelable:false};
	eventType["abort"]     = {bubbles:true, cancelable:false};
	eventType["error"]     = {bubbles:true, cancelable:false};
	eventType["select"]    = {bubbles:true, cancelable:false};
	eventType["change"]    = {bubbles:true, cancelable:false};
	eventType["submit"]    = {bubbles:true, cancelable:true};
	eventType["reset"]     = {bubbles:true, cancelable:false};
	eventType["focus"]     = {bubbles:false,cancelable:false};
	eventType["blur"]      = {bubbles:false,cancelable:false};
	eventType["resize"]    = {bubbles:true, cancelable:false};
	eventType["scroll"]    = {bubbles:true, cancelable:false};

	return function(currentTarget) {
		if (this.bubbles == undefined)    this.bubbles =         (eventType[this.type])    ? eventType[this.type].bubbles    : true;
		if (this.cancelable == undefined) this.cancelable =      (eventType[this.type])    ? eventType[this.type].cancelable : true;
		if (!this.currentTarget)          this.currentTarget =   (currentTarget == window) ? document : currentTarget;
		if (!this.target && window.event) this.target =          (window.event.srcElement) ? window.event.srcElement : document;
		if (this.timeStamp == undefined)  this.timeStamp =       new Date().valueOf();
		if (!this.preventDefault)         this.preventDefault =  function() { if (this.cancelable) this.returnValue = false; };
		if (!this.stopPropagation)        this.stopPropagation = function() { this.cancelBubble = true; }
		if (!this.eventPhase) {
			this.eventPhase = (this.currentTarget == this.target) ? Event.AT_TARGET : Event.BUBBLING_PHASE;
		} else if (this.eventPhase == Event.AT_TARGET && currentTarget != this.target) {
			this.eventPhase = Event.BUBBLING_PHASE;
		}
	}
})();
function MouseEvent() { /* To be written later */ }
function KeyboardEvent() { /* To be written later */ }
function PhaseType() {
	this.CAPTURING_PHASE = 1;
	this.AT_TARGET       = 2;
	this.BUBBLING_PHASE  = 3;
}
PhaseType.apply(Event);

function EventTarget() {
	function isMatch(eventListener, type, listener, useCapture) {
		return (eventListener.type == type && eventListener.listener == listener && eventListener.useCapture == useCapture); 
	}
	this.eventListenerList = null;
	if (this == document || !this.addEventListener) {
		var _addEventListener = (this == document) ? this.addEventListener || null : null;
		this.addEventListener = function(type, listener, useCapture) {
			if (!_addEventListener || (this == document && type == "load" && !useCapture)) {
				var obj = (this == document && type == "load") ? window : this;
				if (!this.eventListenerList) {
					this.eventListenerList = new EventListenerList();
				}

				for (var i = 0; i < this.eventListenerList.length; i++) {
					if (isMatch(this.eventListenerList.item(i), type, listener, useCapture)) {
						return;
					}
				}

				this.eventListenerList.push(new EventListener(type, listener, useCapture));

				var eventName = "on" + type;
				if (!obj[eventName]) {
					obj[eventName] = function(evt) {
						var currentTarget = (this == window) ? document : this;
						currentTarget.dispatchEvent(evt);
					}
				}
			} else if (_addEventListener) {
				_addEventListener(type, listener, useCapture);
			}
		}
	}
	if (this == document || !this.removeEventListener) {
		var _removeEventListener = (this == document) ? this.removeEventListener || null : null;
		this.removeEventListener = function(type, listener, useCapture) {
			if (!_removeEventListener || (this == document && type == "load")) {
				var filteredList = new EventListenerList()
				for (var i = 0; i < this.eventListenerList.length; i++) {
					if (isMatch(this.eventListenerList.item(i), type, listener, useCapture))
						this.eventListenerList.item(i).removed = true;
					else
						filteredList.push(this.eventListenerList.item(i));
				}
				this.eventListenerList = filteredList;
			} else {
				_removeEventListener(type, listener, useCapture);
			}
		}
	}
	if (this == document || !this.dispatchEvent) {
		this.dispatchEvent = function(evt) {
			if (!evt) evt = window.event;
			Event.apply(evt, [this]);
			MouseEvent.apply(evt);
			KeyboardEvent.apply(evt);
			if (this.eventListenerList) {
				var list = new Array().concat(this.eventListenerList)
				for (var i = 0; i < list.length; i++)
					list[i].handleEvent(evt);
			}
		}
	}
}
EventTarget.apply(document);
EventTarget.apply(Node.prototype);
