NETJOHNHENRY = window.NETJOHNHENRY ||
{};

NETJOHNHENRY.dom = (function()
{

	function recurseAllChildNodes(node, injected_function, params)
	{
		if (node)
		{
			injected_function(node, params);
			for (var i = 0; i < node.childNodes.length; i++)
			{
				var childnode = node.childNodes[i];
				if (childnode !== undefined && (childnode.nodeType == childnode.ELEMENT_NODE || childnode.nodeType == 1))
				{ // <- IE doesn't support node.ELEMENT_NODE therefore || node.nodeType == 1			
					recurseAllChildNodes(childnode, injected_function, params);
				}
			}
		}
	}

	//The difference between this function and the above is the scope of injected_function
	//here the injected function is run within the scope of the object that declares the function
	//while the above is run with the scope of the window object.
	//The following has also a return of the original node.
	function recurseAllChildNodesWithDelegate(node, scope, injected_function, params)
	{
		if (node)
		{
			NETJOHNHENRY.delegate(scope, injected_function, params);
			for (var i = 0; i < node.childNodes.length; i++)
			{
				var childnode = node.childNodes[i];
				if (childnode !== undefined && (childnode.nodeType == childnode.ELEMENT_NODE || childnode.nodeType == 1))
				{ // <- IE doesn't support node.ELEMENT_NODE therefore || node.nodeType == 1	
					try
					{
						params.currentNode = childnode;
					}
					catch (e)
					{
					}

					node.replaceChild(recurseAllChildNodesWithDelegate(childnode, scope, injected_function, params), node.childNodes[i]);
					//#note: we are using the replace child because IE complains with the following code
					//node.childNodes[i] = recurseAllChildNodesWithDelegate(childnode, scope, injected_function, params);
				}
			}
		}
		return node;
	}

	function getElementPosition(element, ancestor)
	{
		var left = 0, top = 0;

		if (element.offsetParent)
		{
			do
			{
				left += element.offsetLeft;
				top += element.offsetTop;
			}
			while ((element.offsetParent != ancestor) && (element = element.offsetParent));
		}

		return {
			'left': left,
			'top': top
		};
	}

	/* Class manipulation functions */
	function hasClass(e, c)
	{
		var re = new RegExp('(^|\\s)' + c + '(\\s|$)');
		return re.test(e.className);
	}

	function addClass(e, c)
	{
		if (!hasClass(e, c))
		{
			if (!e.className)
			{
				e.className = c;
			}
			else
			{
				var current = e.className;
				e.className = [current, c].join(' ');
			}
		}
	}

	function removeClass(e, c)
	{
		if (e.className)
		{
			if (e.className == c)
			{
				e.className = '';
			}
			else
			{
				re = new RegExp('(^|\\s)' + c + '(\\s|$)');
				m = e.className.match(re);
				if (m && m.length == 3) { e.className = e.className.replace(re, (m[1] && m[2]) ? ' ' : ''); }
			}
		}
	}

	function replaceClass(e, oldClass, newClass)
	{
		removeClass(e, oldClass);
		addClass(e, newClass);
	}

	function toggleClass(e, c)
	{
		hasClass(e, c) ? removeClass(e, c) : addClass(e, c);
	}


	function getElementsByClassName(searchClass, node, tag)
	{
		if (!node)
		{
			node = document;
		}
		var classElements = [];
		if (!tag)
		{
			tag = '*';
		}
		var els = node.getElementsByTagName(tag);
		var pattern = new RegExp("(^|\\s)" + searchClass + "(\\s|$)");
		for (i = 0, elsLen = els.length; i < elsLen; i++)
		{
			if (pattern.test(els[i].className))
			{
				classElements.push(els[i]);
			}
		}
		return classElements;
	}

	return {
		recurseAllChildNodes: recurseAllChildNodes,
		recurseAllChildNodesWithDelegate: recurseAllChildNodesWithDelegate,
		getElementPosition: getElementPosition,
		hasClass: hasClass,
		addClass: addClass,
		removeClass: removeClass,
		replaceClass: replaceClass,
		toggleClass: toggleClass,
		getElementsByClassName: getElementsByClassName
	};

})();

