(function()
{

if (!js && !js.event) return;

evtHash = [];

function ieGetUniqueID(_elem)
{
	if (_elem === window) { return 'theWindow'; }
	else if (_elem === document) { return 'theDocument'; }
	else { return _elem.uniqueID; }
}

js.event.addEvent = function(_elem, _evtName, _fn, _useCapture)
{
	if (typeof _elem.addEventListener != 'undefined')
	{
		if (_evtName == 'mouseenter')
			{ _elem.addEventListener('mouseover', mouseEnter(_fn), _useCapture); }
		else if (_evtName == 'mouseleave')
			{ _elem.addEventListener('mouseout', mouseEnter(_fn), _useCapture); } 
		else
			{ _elem.addEventListener(_evtName, _fn, _useCapture); }
	}
	else if (typeof _elem.attachEvent != 'undefined')
	{
		var key = '{FNKEY::obj_' + ieGetUniqueID(_elem) + '::evt_' + _evtName + '::fn_' + _fn + '}';
		var f = evtHash[key];
		if (typeof f != 'undefined')
			{ return; }
		
		f = function()
		{
			_fn.call(_elem);
		};
	
		evtHash[key] = f;
		_elem.attachEvent('on' + _evtName, f);

		// attach unload event to the window to clean up possibly IE memory leaks
		window.attachEvent('onunload', function()
		{
			_elem.detachEvent('on' + _evtName, f);
		});
	
		key = null;
		//f = null;   /* DON'T null this out, or we won't be able to detach it */
	}
	else
		{ _elem['on' + _evtName] = _fn; }
}	

js.event.removeEvent = function(_elem, _evtName, _fn, _useCapture)
{
	if (typeof _elem.removeEventListener != 'undefined')
		{ _elem.removeEventListener(_evtName, _fn, _useCapture); }
	else if (typeof _elem.detachEvent != 'undefined')
	{
		var key = '{FNKEY::obj_' + ieGetUniqueID(_elem) + '::evt' + _evtName + '::fn_' + _fn + '}';
		var f = evtHash[key];
		if (typeof f != 'undefined')
		{
			_elem.detachEvent('on' + _evtName, f);
			delete evtHash[key];
		}
	
		key = null;
		//f = null;   /* DON'T null this out, or we won't be able to detach it */
	}
}

function mouseEnter(_pFn)
{
	return function(_evt)
	{
		var relTarget = _evt.relatedTarget;				
		if (this == relTarget || isAChildOf(this, relTarget))
			{ return; }

		_pFn.call(this, _evt);
	}
}

function isAChildOf(_parent, _child)
{
	if (_parent == _child) { return false };
	
	while (_child && _child != _parent)
		{ _child = _child.parentNode; }
	
	return _child == _parent;
}

})();
