/* #############################################################################

NS: TESCO.system.event
	static: yes

dependancies:
	TESCO
	TESCO.system.browser		**** IMPORTANT: *must* be referenced *before* this library

compatibility: WinIE5, WinIE5.5, WinIE6, Mozilla, Firefox, Netscape 7+, Opera 7+, Safari, Konqueror
		Does not support DOM0 events (e.g. MacIE)
############################################################################# */

TESCO.system.event = new function() {
	this.VERSION = "1.0.8";
	this.NAME = "TESCO.system.event";

	var _self = this;
	
	this._earlyBindEvents = null;
	var wrappedEvents = [];
	var bLoaded = false;
	var bBindComplete = false;
	
	this.attach = function(o, e, f, co) {
		var eventWrapper = function(e) {
			this.source = o;
			this.callback = f;
			this.co = co;
			this.source.callback = this.callback;
			
			TESCO.system.event._dispatchEvent(this, e);
		}

		if(o) {
			if(typeof o == "string") {
				attachEventById(o, e, f, co);
			} else if(isArray(o)) {
				for(var item in o) {
					attachEventById(o[item], e, f, co);
				}
			} else {
				wrappedEvents[wrappedEvents.length] = {o : o, e : e, f : f, w : eventWrapper};
				attachEvent(o, e, eventWrapper);
			}
		} else {
			earlyBind(o, e, f, co);
		}
	}
	
	this.detach = function(o, e, f) {
		if(typeof o == "string") {
			o = document.getElementById(o);
		} else if(isArray(o)) {
			for(var i = 0; i < o.length; i++) {
				this.detach(o[i], e, f);
			}
		}
		
		if(o) {
			for(var i = 0; i < wrappedEvents.length; i++) {
				if(wrappedEvents[i] && wrappedEvents[i].f === f && wrappedEvents[i].o === o && wrappedEvents[i].e == e) {
					if(o.removeEventListener) {
						o.removeEventListener(e, wrappedEvents[i].w, false);
					} else if(o.detachEvent) {
						o.detachEvent("on" + e, wrappedEvents[i].w);
					}
					delete wrappedEvents[i].w;
					delete wrappedEvents[i];
					wrappedEvents.splice(i, 1);
					break;
				}
			}
		}
	}
	
	this._dispatchEvent = function(eventWrapper, e) {
		var oEvent = getEvent(e);
		
		if(!oEvent.preventDefault) {
			oEvent.preventDefault = function() {
				if(!this.canceldisabled) {
					this.returnValue = false;
				}
			}
		}

		if(!oEvent.stopPropagation) {
			oEvent.stopPropagation = function() {
				this.cancelBubble = true
			}
		}
		
		oEvent.stopEvent = function() {
			this.stopPropagation();
			this.preventDefault();
		}
		
		if(!oEvent.target && oEvent.srcElement) {
			oEvent.target = oEvent.srcElement;
		}
		
		if(!oEvent.currentTarget) {
			oEvent.currentTarget = eventWrapper.source;
		}
		
		if(!oEvent.pageX && oEvent.pageX !== 0) {
			oEvent.pageX = oEvent.clientX || 0;
			
			if(TESCO.system.browser.isIE) {
				oEvent.pageX += getScroll()[1];
			}
		}
		
		if(!oEvent.pageY && oEvent.pageY !== 0) {
			oEvent.pageY = oEvent.clientY || 0;
			
			if(TESCO.system.browser.isIE) {
				oEvent.pageY += getScroll()[0];
			}
		}
		
		oEvent.BUTTONLEFT = 1;
		oEvent.BUTTONMIDDLE = 2;
		oEvent.BUTTONRIGHT = 3;

		if(TESCO.system.browser.isIE) {
			switch(oEvent.button) {
				case 1:
					oEvent.which = oEvent.BUTTONLEFT;
					break;
				case 2:
					oEvent.which = oEvent.BUTTONRIGHT;
					break;
				case 4:
					oEvent.which = oEvent.BUTTONMIDDLE;
					break;
			}
		} else if(TESCO.system.browser.isOpera) {
			switch(oEvent.button) {
				case 2:
					oEvent.which = oEvent.BUTTONRIGHT;
					break;
				case 3:
					oEvent.which = oEvent.BUTTONMIDDLE;
					break;
			}
		}
	
		eventWrapper.source.callback(oEvent, eventWrapper.co);

		if(TESCO.system.browser.isSafari && e.type == "click") {
			eventWrapper.source.onclick = function() { return e.returnValue; }
		}
		
		oEvent.preventDefault = null;
		oEvent.stopPropagation = null;
		oEvent.stopEvent = null;
	}
	
	function getScroll() {
		var dd = document.documentElement; db = document.body;
		if (dd && dd.scrollTop) {
			return [dd.scrollTop, dd.scrollLeft];
		} else if (db) {
			return [db.scrollTop, db.scrollLeft];
		} else {
			return [0, 0];
		}
	}

	function attachEvent(o, e, f) {
		if(o) {
			if(o.addEventListener) {
				o.addEventListener(e, f, false);
			} else if(o.attachEvent) {
				o.attachEvent("on" + e, f);
			}
			if(TESCO.system.browser.isSafari && o.onclick) {
				var onclick = o.onclick;
				o.onclick = null;
				_self.attach(o, e, onclick);
			}
		}
	}

	function attachEventById(id, e, f, co) {
		var oItem = document.getElementById(id);
		if(oItem) {
			_self.attach(oItem, e, f, co);
		} else {
			earlyBind(id, e, f, co);
		}
	}
	
	function getEvent(e) {
		if(e) {
			return e;
		} else if(window.event) {
			return window.event;
		}
	}
	
	function isArray(o) {
		return (o && typeof o != "string" && o.length && !o.tagName && typeof(o[0]) != "undefined") == true ? true : false;
	}
	
	function earlyBind(o, e, f, co) {
		if(!TESCO.system.event._earlyBindEvents) {
			TESCO.system.event._earlyBindEvents = [];
		}
		TESCO.system.event._earlyBindEvents[TESCO.system.event._earlyBindEvents.length] = {o : o, e : e, f : f, co : co};
		setTimeout("TESCO.system.event._attachEarlyBindEvents()", 50);
	}
	
	// _attachEarlyBindEvents needs to be public as it needs to be called externally from the setTimeout function
	this._attachEarlyBindEvents = function() {
		var earlyBindEvents = TESCO.system.event._earlyBindEvents, oItem, count = 0;
		for(var i = 0; i < earlyBindEvents.length; i++) {
			if(earlyBindEvents[i]) {
				oItem = document.getElementById(earlyBindEvents[i].o);
				if(oItem) {
					if(oItem.tagName != "IMG" && earlyBindEvents[i].e == "load") {
						oItem.callback = earlyBindEvents[i].f;
						oItem.callback({type : "load"});
					} else {
						_self.attach(oItem, earlyBindEvents[i].e, earlyBindEvents[i].f, earlyBindEvents[i].co);
					}
					delete earlyBindEvents[i];
				} else {
					count++;
				}
			}
		}
		if(!bBindComplete) {
			if(bLoaded) {
				bBindComplete = true;
				TESCO.system.event._attachEarlyBindEvents();
			} else if(count > 0) {
				setTimeout("TESCO.system.event._attachEarlyBindEvents()", 50);
			} else {
				delete earlyBindEvents;
			}
		}
	}
	
	this._onload = function(e) {
		bLoaded = true;
	}

	this._onunload = function(e) {
		bLoaded = false;
		for(var i = 0; i < wrappedEvents.length; i++) {
			wrappedEvents[i].o = null;
			wrappedEvents[i].f = null;
			wrappedEvents[i].w = null;

			delete wrappedEvents[i].o;
			delete wrappedEvents[i].f;
			delete wrappedEvents[i].w;
			delete wrappedEvents[i];
		}
	}

	_self.attach(window, "load", this._onload);
	_self.attach(window, "unload", this._onunload);
}
