/* Copyright (c) 2006, Yahoo! Inc. All rights reserved. */ 
YAHOO.util.CustomEvent = function(type, oScope, silent) {
	this.type = type;
	this.scope = oScope || window;
	this.silent = silent;
	this.subscribers = [];
	if (YAHOO.util.Event) { YAHOO.util.Event.regCE(this); }
	if (!this.silent) { }
};
YAHOO.util.CustomEvent.prototype = {
	subscribe: function(fn, obj, bOverride) {
		this.subscribers.push(new YAHOO.util.Subscriber(fn, obj, bOverride));
	},
	unsubscribe: function(fn, obj) {
		var found = false;
		for (var i=0, len=this.subscribers.length; i < len; ++i) {
			var s = this.subscribers[i];
			if (s && s.contains(fn, obj)) {
				this._delete(i);
				found = true;
			}
		}
		return found;
	},
	fire: function() {
		var len=this.subscribers.length;
		var args = [];
		for (var i=0; i < arguments.length; ++i) { args.push(arguments[i]); }
		if (!this.silent) { }
		for (var i=0; i < len; ++i) {
			var s = this.subscribers[i];
			if (s) {
				if (!this.silent) { }
				var scope = (s.override)? s.obj : this.scope;
				s.fn.call(scope, this.type, args, s.obj);
			}
		}
	},
	unsubscribeAll: function() {
		for (var i=0, len=this.subscribers.length; i < len; ++i) { this._delete(i); }
	},
	_delete: function(index) {
		var s = this.subscribers[index];
		if (s) {
			delete s.fn;
			delete s.obj;
		}
		delete this.subscribers[index];
	},
	toString: function() {
		 return "CustomEvent: '" + this.type + "', scope: " + this.scope;
	}
};
YAHOO.util.Subscriber = function(fn, obj, bOverride) {
	this.fn = fn;
	this.obj = obj || null;
	this.override = (bOverride);
};
YAHOO.util.Subscriber.prototype.contains = function(fn, obj) {
	return (this.fn == fn && this.obj == obj);
};
YAHOO.util.Subscriber.prototype.toString = function() {
	return "Subscriber { obj: " + (this.obj || "") +
	 ", override: " + (this.override || "no") + " }";
};
if (!YAHOO.util.Event) {
	YAHOO.util.Event = function() {
		var loadComplete =  false;
		var listeners = [];
		var delayedListeners = [];
		var unloadListeners = [];
		var customEvents = [];
		var legacyEvents = [];
		var legacyHandlers = [];
		var retryCount = 0;
		var onAvailStack = [];
		var legacyMap = [];
		var counter = 0;
		return { // PREPROCESS
			POLL_RETRYS: 200,
			POLL_INTERVAL: 50,
			EL: 0,
			TYPE: 1,
			FN: 2,
			WFN: 3,
			SCOPE: 3,
			ADJ_SCOPE: 4,
			isSafari: (/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),
			isIE: (!this.isSafari && !navigator.userAgent.match(/opera/gi) && 
			 navigator.userAgent.match(/msie/gi)),
			addDelayedListener: function(el, sType, fn, oScope, bOverride) {
				delayedListeners[delayedListeners.length] = [el, sType, fn, oScope, bOverride];
				if (loadComplete) {
					retryCount = this.POLL_RETRYS;
					this.startTimeout(0);
				}
			},
			startTimeout: function(interval) {
				var i = (interval || interval === 0)? interval : this.POLL_INTERVAL;
				var self = this;
				var callback = function() { self._tryPreloadAttach(); };
				this.timeout = setTimeout(callback, i);
			},
			onAvailable: function(p_id, p_fn, p_obj, p_override) {
				onAvailStack.push( { id: p_id, fn: p_fn, obj: p_obj, override: p_override } );
				retryCount = this.POLL_RETRYS;
				this.startTimeout(0);
			},
			addListener: function(el, sType, fn, oScope, bOverride) {
				if (!fn || !fn.call) { return false; }
				if (this._isValidCollection(el)) {
					var ok = true;
					for (var i=0, len=el.length; i < len; ++i) {
						ok = (this.on(el[i], sType, fn, oScope, bOverride) && ok);
					}
					return ok;
				}
				else if (typeof(el) == "string") {
					var oEl = this.getEl(el);
					if (loadComplete && oEl) { el = oEl; }
					else {
						this.addDelayedListener(el, sType, fn, oScope, bOverride);
						return true;
					}
				}
				if (!el) { return false; }
				if ("unload" == sType && oScope !== this) {
					unloadListeners[unloadListeners.length] = [el, sType, fn, oScope, bOverride];
					return true;
				}
				var scope = (bOverride)? oScope : el;
				var wrappedFn = function(e) {
					return fn.call(scope, YAHOO.util.Event.getEvent(e), oScope);
				};
				var li = [el, sType, fn, wrappedFn, scope];
				var index = listeners.length;
				listeners[index] = li;
				if (this.useLegacyEvent(el, sType)) {
					var legacyIndex = this.getLegacyIndex(el, sType);
					if (legacyIndex == -1) {
						legacyIndex = legacyEvents.length;
						legacyMap[el.id + sType] = legacyIndex;
						legacyEvents[legacyIndex] = [el, sType, el["on" + sType]];
						legacyHandlers[legacyIndex] = [];
						el["on" + sType] = function(e) {
							YAHOO.util.Event.fireLegacyEvent(YAHOO.util.Event.getEvent(e), legacyIndex);
						};
					}
					legacyHandlers[legacyIndex].push(index);
				}
				else if (el.addEventListener) { el.addEventListener(sType, wrappedFn, false); }
				else if (el.attachEvent) { el.attachEvent("on" + sType, wrappedFn); }
				return true;
			},
			fireLegacyEvent: function(e, legacyIndex) {
				var ok = true;
				var le = legacyHandlers[legacyIndex];
				for (var i=0, len=le.length; i < len; ++i) {
					var index = le[i];
					if (index) {
						var li = listeners[index];
						if (li && li[this.WFN]) {
							var scope = li[this.ADJ_SCOPE];
							var ret = li[this.WFN].call(scope, e);
							ok = (ok && ret);
						}
						else { delete le[i]; }
					}
				}
				return ok;
			},
			getLegacyIndex: function(el, sType) {
				var key = this.generateId(el) + sType;
				if (typeof(legacyMap[key]) == "undefined") { return -1; }
				else { return legacyMap[key]; }
			},
			useLegacyEvent: function(el, sType) {
				if (!el.addEventListener && !el.attachEvent) { return true; }
				else if (this.isSafari) {
					if ("click" == sType || "dblclick" == sType) { return true; }
				}
				return false;
			},
			removeListener: function(el, sType, fn, index) {
				if (!fn || !fn.call) { return false; }
				if (typeof(el) == "string") { el = this.getEl(el); }
				else if ( this._isValidCollection(el)) {
					var ok = true;
					for (var i=0, len=el.length; i < len; ++i) {
						ok = (this.removeListener(el[i], sType, fn) && ok);
					}
					return ok;
				}
				if ("unload" == sType) {
					for (var i=0, len=unloadListeners.length; i < len; i++) {
						var li = unloadListeners[i];
						if (li && li[0] == el && li[1] == sType && li[2] == fn) {
							delete unloadListeners[i];
							return true;
						}
					}
					return false;
				}
				var cacheItem = null;
				if ("undefined" == typeof(index)) { index = this._getCacheIndex(el, sType, fn); }
				if (index >= 0) { cacheItem = listeners[index]; }
				if (!el || !cacheItem) { return false; }
				if (el.removeEventListener) {
					el.removeEventListener(sType, cacheItem[this.WFN], false);
				}
				else if (el.detachEvent) {
					el.detachEvent("on" + sType, cacheItem[this.WFN]);
				}
				delete listeners[index][this.WFN];
				delete listeners[index][this.FN];
				delete listeners[index];
				return true;
			},
			getTarget: function(ev, resolveTextNode) {
				var t = ev.target || ev.srcElement;
				return this.resolveTextNode(t);
			},
			resolveTextNode: function(node) {
				if (node && node.nodeName && "#TEXT" == node.nodeName.toUpperCase()) {
					return node.parentNode;
				}
				else { return node; }
			},
			getPageX: function(ev) {
				var x = ev.pageX;
				if (!x && 0 !== x) {
					x = ev.clientX || 0;
					if (this.isIE) { x += this._getScrollLeft(); }
				}
				return x;
			},
			getPageY: function(ev) {
				var y = ev.pageY;
				if (!y && 0 !== y) {
					y = ev.clientY || 0;
					if (this.isIE) { y += this._getScrollTop(); }
				}
				return y;
			},
			getXY: function(ev) { return [this.getPageX(ev), this.getPageY(ev)]; },
			getRelatedTarget: function(ev) {
				var t = ev.relatedTarget;
				if (!t) {
					if (ev.type == "mouseout") { t = ev.toElement; }
					else if (ev.type == "mouseover") { t = ev.fromElement; }
				}
				return this.resolveTextNode(t);
			},
			getTime: function(ev) {
				if (!ev.time) {
					var t = new Date().getTime();
					try { ev.time = t; }
					catch(e) { return t; }
				}
				return ev.time;
			},
			stopEvent: function(ev) {
				this.stopPropagation(ev);
				this.preventDefault(ev);
			},
			stopPropagation: function(ev) {
				if (ev.stopPropagation) { ev.stopPropagation(); }
				else { ev.cancelBubble = true; }
			},
			preventDefault: function(ev) {
				if (ev.preventDefault) { ev.preventDefault(); }
				else { ev.returnValue = false; }
			},
			getEvent: function(e) {
				var ev = e || window.event;
				if (!ev) {
					var c = this.getEvent.caller;
					while (c) {
						ev = c.arguments[0];
						if (ev && Event == ev.constructor) { break; }
						c = c.caller;
					}
				}
				return ev;
			},
			getCharCode: function(ev) {
				return ev.charCode || ((ev.type == "keypress")? ev.keyCode : 0);
			},
			_getCacheIndex: function(el, sType, fn) {
				for (var i=0, len=listeners.length; i < len; ++i) {
					var li = listeners[i];
					if ( li && li[this.FN] == fn && li[this.EL] == el && li[this.TYPE] == sType ) {
						return i;
					}
				}
				return -1;
			},
			generateId: function(el) {
				var id = el.id;
				if (!id) {
					id = "yuievtautoid-" + counter;
					++counter;
					el.id = id;
				}
				return id;
			},
			_isValidCollection: function(o) {
				return ( o && o.length && typeof(o) != "string" &&
				 !o.tagName && !o.alert && typeof(o[0]) != "undefined" );
			},
			elCache: {},
			getEl: function(id) { return document.getElementById(id); },
			clearCache: function() { },
			regCE: function(ce) { customEvents.push(ce); },
			_load: function(e) { loadComplete = true; },
			_tryPreloadAttach: function() {
				if (this.locked) { return false; }
				this.locked = true;
				var tryAgain = !loadComplete;
				if (!tryAgain) { tryAgain = (retryCount > 0); }
				var stillDelayed = [];
				for (var i=0, len=delayedListeners.length; i < len; ++i) {
					var d = delayedListeners[i];
					if (d) {
						var el = this.getEl(d[this.EL]);
						if (el) {
							this.on(el, d[this.TYPE], d[this.FN], d[this.SCOPE], d[this.ADJ_SCOPE]);
							delete delayedListeners[i];
						}
						else { stillDelayed.push(d); }
					}
				}
				delayedListeners = stillDelayed;
				var notAvail = [];
				for (var i=0, len=onAvailStack.length; i < len ; ++i) {
					var item = onAvailStack[i];
					if (item) {
						el = this.getEl(item.id);
						if (el) {
							var scope = (item.override)? item.obj : el;
							item.fn.call(scope, item.obj);
							delete onAvailStack[i];
						}
						else { notAvail.push(item); }
					}
				}
				retryCount = (stillDelayed.length === 0 && notAvail.length === 0)? 0 : retryCount - 1;
				if (tryAgain) { this.startTimeout(); }
				this.locked = false;
				return true;
			},
			purgeElement: function(el, recurse, sType) {
				var elListeners = this.getListeners(el, sType);
				if (elListeners) {
					for (var i=0, len=elListeners.length; i < len ; ++i) {
						var l = elListeners[i];
						this.removeListener(el, l.type, l.fn, l.index);
					}
				}
				if (recurse && el && el.childNodes) {
					for (var i=0, len=el.childNodes.length; i < len ; ++i) {
						this.purgeElement(el.childNodes[i], recurse, sType);
					}
				}
			},
			getListeners: function(el, sType) {
				var elListeners = [];
				if (listeners && listeners.length > 0) {
					for (var i=0, len=listeners.length; i < len ; ++i) {
						var l = listeners[i];
						if ( l && l[this.EL] === el && (!sType || sType === l[this.TYPE]) ) {
							elListeners.push({ type: l[this.TYPE], fn: l[this.FN],
							 obj: l[this.SCOPE], adjust: l[this.ADJ_SCOPE], index: i });
						}
					}
				}
				return (elListeners.length)? elListeners : null;
			},
			_unload: function(e, me) {
				for (var i=0, len=unloadListeners.length; i < len; ++i) {
					var l = unloadListeners[i];
					if (l) {
						var scope = (l[this.ADJ_SCOPE])? l[this.SCOPE]: window;
						l[this.FN].call(scope, this.getEvent(e), l[this.SCOPE] );
					}
				}
				if (listeners && listeners.length > 0) {
					for (var i=0, len=listeners.length; i < len ; ++i) {
						l = listeners[i];
						if (l) { this.removeListener(l[this.EL], l[this.TYPE], l[this.FN], i); }
					}
					this.clearCache();
				}
				for (var i=0, len=customEvents.length; i < len; ++i) {
					customEvents[i].unsubscribeAll();
					delete customEvents[i];
				}
				for (var i=0, len=legacyEvents.length; i < len; ++i) {
					delete legacyEvents[i][0];
					delete legacyEvents[i];
				}
			},
			_getScrollLeft: function() { return this._getScroll()[1]; },
			_getScrollTop: function() { return this._getScroll()[0]; },
			_getScroll: function() {
				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]; }
			}
		};
	} ();
	YAHOO.util.Event.on = YAHOO.util.Event.addListener;
	if (document && document.body) { YAHOO.util.Event._load(); }
	else { YAHOO.util.Event.on(window, "load", YAHOO.util.Event._load, YAHOO.util.Event, true); }
	YAHOO.util.Event.on(window, "unload", YAHOO.util.Event._unload, YAHOO.util.Event, true);
	YAHOO.util.Event._tryPreloadAttach();
}
