/**
 * Singleton object of functions for handling events
 * @class Functions for handling events
 */
W.Event = new function()
{
	/**
	 * Add an event listener to an object
	 * usage: W.Event.addEvent(window, 'load', initDragNDrop);
	 * @param {Object}		obj 	Object that raises the event
	 * @param {String}		type 	Name of event we're interested in
	 * @param {Reference}	fn 		Reference to the function to be called
	 * @return void
	 */
	this.add = function(obj, type, fn)
	{
		var result;
		//alert('add: ' + obj + ' ' + type + ' ' + fn);
		
		if (obj.addEventListener) {
			obj.addEventListener(type, fn, false);
			result = true;
		}
		else if (obj.attachEvent) {
			var r = obj.attachEvent('on' + type, fn);
			result = r;
		}
		else {
			// most likely MacIE
			// check if event handler already has a function assigned to it, and if it does, chain together the functions
			var old	= obj['on' + type];
			if (typeof obj['on' + type] != 'function') {
				obj['on' + type] = fn;
			} else {
				obj['on' + type] = function()
				{
					old();
					fn();
				};
			}
		}
		
		//W.Event.Cache.add(obj, type, fn);
		return result;
	};
	
	
	
	this.remove = function(obj, type, fn)
	{
		//alert('remove: ' + obj + ' ' + type + ' ' + fn);
		if (obj.removeEventListener) {
			obj.removeEventListener(type, fn, false);
		} else if (obj.detachEvent) {
			obj.detachEvent('on' + type, fn);
		} else {
			obj['on' + type] = null;
		}
	};



	this.preventDefault = function(e)
	{
		e.returnValue = false;
		
		if (e.preventDefault) { e.preventDefault(); }
		
		return false;
	};
	
	
	
	this.cancelBubble = function(e)
	{
		e.cancelBubble = true;
		if (e.stopPropagation) { e.stopPropagation(); }
	};


	this.source = function(e)
	{
		return window.event? window.event.srcElement : e ? e.target : null;
	};
	
	
	
	this.target = function(e, targetElement)
	{
		return window.event? targetElement : e ? e.currentTarget : null;
	};
	
	
	
	/*
	 *	Returns the first non-text node parent of an element receiving the event
	 */
	this.getTarget = function(e)
	{
		var targetElement = null;
		
		targetElement = this.source(e);
		
		// don't return a text node
		while (targetElement.nodeType == 3 && targetElement.parentNode !== null) {
			targetElement = targetElement.parentNode;
		}
		
		return targetElement;
	};
	
	
	
	//---- Mark Wubben's solution to memory leak in WinIE -----//
	this.Cache = function()
	{
		var listEvents = [];
		return {
			listEvents : listEvents,
			add : function(node, sEventName, fHandler){
				listEvents.push(arguments);
			},
			flush : function(){
				var i, item;
				for(i = listEvents.length - 1; i >= 0; i = i - 1){
					item = listEvents[i];
					if (item[0].removeEventListener){
						item[0].removeEventListener(item[1], item[2], item[3]);
					}
					if (item[1].substring(0, 2) != "on"){
						item[1] = "on" + item[1];
					}
					if (item[0].detachEvent){
						item[0].detachEvent(item[1], item[2]);
					}
					item[0][item[1]] = null;
				}
			}
		};
	}();
		
}();



Function.prototype.bind = function(object, args)
{
	var method = this;
	return function(event) {
		return method.call(object, event || window.event, args);
	};
};



//	MacIE doesn't seem to see this if put on a different script like W.js
if (Array.prototype.push === null) {
	Array.prototype.push = function() {
		for (var i = 0; i < arguments.length; ++i) {
			this[this.length] = arguments[i];
		}
		return this.length;
	};
}



W.Event.add(window, 'unload', W.Event.Cache.flush);

