/**
 * addEvent & removeEvent -- cross-browser event handling Copyright (C)
 * 2006-2007 Dao Gottwald
 * 
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 * 
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 * 
 * Contact information: Dao Gottwald <dao at design-noir.de>
 * 
 * @version 1.2.1
 */

var EventManager = {
	add: function addEvent(el, type, fn) {
		el.addEventListener(type, fn, false);
	},
	fire: function(el, type, shiftKey, ctrlKey) {
		var e = document.createEvent("MouseEvents");
		e.initMouseEvent(
				type,
				true,
				true,
				window,
				0,
				0,
				0,
				0,
				0,
				ctrlKey,
				false,
				shiftKey,
				false,
				0,
				null);
		el.dispatchEvent(e);
	},
	remove: function(el, type, fn) {
		el.removeEventListener(type, fn, false);
	}
};

if (!window.addEventListener) {
	EventManager.add = function(el, type, fn) {
		if (!el.events) el.events = {};
		var queue = el.events[type];
		if (!queue) {
			el.events[type] = [fn];
			if (!el.events.callback) el.events.callback = function(e) {
				Event.callListeners(e, el);
			};
			el.attachEvent("on" + type, el.events.callback);
		}
		else if (Event.fnIndex(el, type, fn) == -1) queue.push(fn);
		else return;
		Event.mem.push( [el, type, fn]);
	};
	EventManager.fire = function(el, type, shiftKey, ctrlKey) {
		var e = document.createEventObject();
		e.detail = 0;
		e.screenX = 0;
		e.screenY = 0;
		e.clientX = 0;
		e.clientY = 0;
		e.ctrlKey = ctrlKey;
		e.altKey = false;
		e.shiftKey = shiftKey;
		e.metaKey = false;
		e.button = 0;
		e.relatedTarget = null;
		el.fireEvent("on" + type, e);
	};
	EventManager.remove = function(el, type, fn) {
		var i = Event.fnIndex(el, type, fn);
		if (i < 0) return;
		var queue = el.events[type];
		if (queue.calling) {
			delete queue[i];
			if (queue.removeListeners) queue.removeListeners.push(i);
			else queue.removeListeners = [i];
		}
		else if (queue.length == 1) Event.detach(el, type);
		else queue.splice(i, 1);
	};
	var Event = {
		AT_TARGET: 2,
		BUBBLING_PHASE: 3,
		callListeners: function(e, el) {
			e.stopPropagation = this.stopPropagation;
			e.preventDefault = this.preventDefault;
			e.currentTarget = el;
			e.target = e.srcElement;
			e.eventPhase = e.currentTarget == e.target ? this.AT_TARGET : this.BUBBLING_PHASE;
			switch (e.type) {
				case "mouseover":
					e.relatedTarget = e.fromElement;
					break;
				case "mouseout":
					e.relatedTarget = e.toElement;
			}
			var queue = el.events[e.type];
			queue.calling = true;
			for ( var i = 0, l = queue.length; i < l; i++)
				if (queue[i]) if ("handleEvent" in queue[i]) queue[i]
						.handleEvent(e);
				else queue[i].call(el, e);
			queue.calling = null;
			if (!queue.removeListeners) return;
			if (queue.length == queue.removeListeners.length) {
				this.detach(el, e.type);
				return;
			}
			queue.removeListeners = queue.removeListeners.sort(function(a, b) {
				return a - b;
			});
			var i = queue.removeListeners.length;
			while (i--)
				queue.splice(queue.removeListeners[i], 1);
			if (queue.length == 0) this.detach(el, e.type);
			else queue.removeListeners = null;
		},
		cleanup: function() {
			for ( var m, i = 0; m = Event.mem[i]; i++)
				if (m[1] != "unload" || m[2] == Event.cleanup) EventManager
						.remove(m[0], m[1], m[2]);
		},
		detach: function(el, type) {
			el.detachEvent("on" + type, el.events.callback);
			delete el.events[type];
		},
		fnIndex: function(el, type, fn) {
			var queue = el.events[type];
			if (queue) for ( var i = 0, l = queue.length; i < l; i++)
				if (queue[i] == fn) return i;
			return -1;
		},
		mem: [],
		preventDefault: function() {
			this.returnValue = false;
		},
		stopPropagation: function() {
			this.cancelBubble = true;
		}
	};
	EventManager.add(window, "unload", Event.cleanup);
}
