Core.createNamespace("tools");

tools.DOM = Core.createStaticClass("DOM","1.0.0");
tools.DOM.extend(
{
	getElementById: function(id)
	{
		return (document.all && !document.getElementById) ? document.all[id] : document.getElementById(id);
	},

	getElementsByTagName: function(strName,elem)
	{
		elem = (typeof elem === "undefined") ? document.documentElement : elem;
		return elem.getElementsByTagName(strName);
	},
	
	getElementsByClassName: function( classNames,elem,tagName )
	{
		elem = (typeof elem === "undefined") ? document.documentElement : elem;
		tagName = (typeof tagName === "undefined") ? '*' : tagName;
		var elems = ( elem.getElementsByTagName ) ? tools.DOM.getElementsByTagName( tagName,elem ) : document.all;
		var results = [];
		var regExpressions = [];
		var bMatch = false;
		
		if( typeof classNames === "object" )
		{
			// Class names are an array
			for( var i=0; i<classNames.length; i++ )
			{
				regExpressions.push( new RegExp( "(^|\\s)" + classNames[i].replace( /\-/g,'\\-') + "(\\s|$)" ) );
			}
		}
		else
		{
			// Class name is a single string
			regExpressions.push( new RegExp( "(^|\\s)" + classNames.replace( /\-/g,'\\-' ) + "(\\s|$)" ) );
		}
		for( var i=0,element; element = elems[i]; i++ )
		{
			bMatch = true;
			for( var j=0; j<regExpressions.length; j++ )
			{
				bMatch = (!regExpressions[j].test( element.className )) ? false : true;
				if( bMatch === false )
				{
					break;
				}
			}
			if( bMatch )
			{
				results.push( element );
			}
		}
		return results;
	},
	
	getOuterHTML: function( element )
	{
		var strXML = "";
		if( element.nodeType === 1 )
		{
			strXML += "<" + element.nodeName.toLowerCase();
			var attrib;
			var attribsLength = element.attributes.length;
			for( var j=0; j < attribsLength; j++ )
			{
				attrib = element.attributes[j];
				if( attrib.nodeName !== "title" && attrib.nodeValue !== null && attrib.nodeValue.length > 0 )
				{
					strXML += ' ' + attrib.nodeName.toLowerCase() + '="' + attrib.nodeValue + '"';
				}
			}
			strXML += ">";
			var elem;
			var elemChildNodesLength = element.childNodes.length;
			for( var i=0; i < elemChildNodesLength; i++ )
			{
				elem = element.childNodes[i];
				strXML += tools.DOM.getOuterHTML( elem );
			}
			strXML += "</" + element.nodeName.toLowerCase() + ">";

		} else if( element.nodeType === 3 ) {
			strXML += element.nodeValue;
		}
		return strXML;
	},

	getInnerHTML: function( element )
	{
		var strXML = "";
		var elem = null;
		var elemChildNodesLength = element.childNodes.length;
		for( var i=0; i < elemChildNodesLength; i++ )
		{
			elem = element.childNodes[i];
			if( elem.nodeType === 1 )
			{
				strXML += "<" + elem.nodeName;
				var attrib;
				var attribsLength = element.attributes.length;
				for( var j=0; j < attribsLength; j++ )
				{
					attrib = element.attributes[j];
					strXML += ' ' + attrib.nodeName + '="' + attrib.nodeValue + '"';
				}
				strXML += ">";
				if( elem.childNodes.length > 0 )
				{
					strXML += tools.DOM.getInnerHTML( elem );
				}
				strXML += "</" + elem.nodeName + ">";

			} else if( elem.nodeType === 3 ) {
				strXML += elem.nodeValue;
			}
		}
		return strXML;
	},

	getFirstChildElement: function( parentNode )
	{
		if( parentNode && parentNode.nodeType === 1 && parentNode.hasChildNodes )
		{
			var firstChildNode = parentNode.firstChild;
			if( firstChildNode !== null && firstChildNode.nodeType === 3 )
			{
				var numberOfChildNodes = parentNode.childNodes.length;
				for( var i=0; i < numberOfChildNodes; i++ )
				{
					firstChildNode = parentNode.childNodes[i];
					if( firstChildNode.nodeType === 1 )
					{
						return firstChildNode;
					}
				}
			}
			return firstChildNode;
		}
	},

	getPreviousSibling: function( parentNode )
	{
		if( parentNode && parentNode.nodeType === 1 )
		{
			// BUG:  Cant default it to a node since that node may be null.  IE hates that.
			// Adding an if statement to null check
//			var previousSiblingNode = parentNode.previousSibling;
			if( parentNode.previousSibling )
			{
				var previousSiblingNode = parentNode.previousSibling;

				// BUG:  previousSiblingNode.previousSibling is not null checked... if theres no next sibling it throws an error 
				if( previousSiblingNode.nodeType === 3 && previousSiblingNode.previousSibling )
				{
					previousSiblingNode = previousSiblingNode.previousSibling;
				}

				if( previousSiblingNode.nodeType !== 1 )
				{
					previousSiblingNode = null;
				}
				return previousSiblingNode;
			}
		}
		return null;
	},

	getLastChildElement: function( parentNode )
	{
		if( parentNode && parentNode.nodeType === 1 )
		{
			var lastChildNode = parentNode.lastChild;
			if( lastChildNode.nodeType === 3 )
			{
				var numberOfChildNodes = parentNode.childNodes.length;
				for( var i=numberOfChildNodes; i===0; i-- )
				{
					lastChildNode = parentNode.childNodes[1];
					if( lastChildNode.nodeType === 1 )
					{
						break;
					}
				}
			}
			if( lastChildNode.nodeType !== 1 )
			{
				lastChildNode = null;
			}
			return lastChildNode;
		}
		return null;
	},

	getNextSibling: function( parentNode )
	{
		if( parentNode && parentNode.nodeType === 1 )
		{
			// BUG:  Cant default it to a node since that node may be null.  IE hates that.
			// Adding an if statement to null check
//			var nextSiblingNode = parentNode.nextSibling;
			if( parentNode.nextSibling )
			{
				var nextSiblingNode = parentNode.nextSibling;
	
				// BUG:  nextSiblingNode.nextSibling is not null checked... if theres no next sibling it throws an error 
				if( nextSiblingNode.nodeType === 3 && nextSiblingNode.nextSibling )
				{
					nextSiblingNode = nextSiblingNode.nextSibling;
				}
				if( nextSiblingNode.nodeType !== 1 )
				{
					nextSiblingNode = null;
				}
				return nextSiblingNode;
			}
		}
		return null;
	},
	
	hasClassName: function( element,classNameToCheck )
	{
		var listOfClasses;
		if( element !== null && element.nodeType === 1 )
		{
			listOfClasses = element.className.split(' ');
			return listOfClasses.contains(classNameToCheck);
		}
		return false;
	},

	addClassName: function( element,classNameToAdd )
	{
		var listOfClasses = [];
		if( element !== null && element.nodeType === 1 )
		{
			listOfClasses = element.className.split(' ');
			listOfClasses.push(classNameToAdd);
			element.className = listOfClasses.join(' ');
		}
		listOfClasses.clear();
	},

	removeClassName: function( element,classNameToRemove )
	{
		var listOfClasses = [];
		if( element !== null && element.nodeType === 1 )
		{
			listOfClasses = element.className.split(' ');
			listOfClasses.remove(classNameToRemove);
			element.className = listOfClasses.join(' ');
		}
		listOfClasses.clear();
	},

	replaceClassName: function( element,classNameToReplace,classNameToPlace )
	{
		if( element !== null && element.nodeType === 1 )
		{
			element.className = element.className.replace(classNameToReplace,classNameToPlace);
		}
	},
	
	insertNodeBefore: function(elementToAdd,elementToAddBefore)
	{
		elementToAddBefore.parentNode.insertBefore(elementToAdd,elementToAddBefore);
	},
	
	insertNodeAfter: function(elementToAdd,elementToAddAfter)
	{
		if( elementToAddAfter.nextSibling )
		{
			elementToAddAfter.parentNode.insertBefore(elementToAdd,elementToAddAfter.nextSibling);
		}
		else
		{
			elementToAddAfter.parentNode.appendChild(elementToAdd);
		}
	},
	
	removeChildNodes: function(node)
	{
		if( node !== null )
		{
			while( node.childNodes[0] )
			{
				node.removeChild(node.childNodes[0]);
			}
		}
	},
	
	getX: function( element )
	{
		var curleft = 0;
		if( element.offsetParent )
		{
			while( element.offsetParent )
			{
				curleft += element.offsetLeft;
				element = element.offsetParent;
			}
		} else if ( element.x ) {
			curleft += element.x;
		}
		return curleft;
	},

	getY: function( element )
	{
		var curtop = 0;
		if( element.offsetParent )
		{
			while( element.offsetParent )
			{
				curtop += element.offsetTop;
				element = element.offsetParent;
			}
		} else if( element.y ) {
			curtop += element.y;
		}
		return curtop;
	},
	
	getViewportX: function()
	{
		var x;
		if( self.pageYOffset )
			// all except Explorer
		{
			x = self.pageXOffset;
		}
		else if( document.documentElement && document.documentElement.scrollTop )
			// Explorer 6 Strict
		{
			x = document.documentElement.scrollLeft;
		}
		else if (document.body )
			// all other Explorers
		{
			x = document.body.scrollLeft;
		}
		return x;
	},

	/**
	 * Returns the vertical scroll location of the top of the viewport in px
	 * @public
	 */
	getViewportY: function()
	{
		var y;
		if( self.pageYOffset )
			// all except Explorer
		{
			y = self.pageYOffset;
		}
		else if( document.documentElement && document.documentElement.scrollTop )
			// Explorer 6 Strict
		{
			y = document.documentElement.scrollTop;
		}
		else if( document.body )
			// all other Explorers
		{
			y = document.body.scrollTop;
		}
		return y;
	},
	
	createGUID: function()
	{
		var guid = "{";
		for( var i = 0; i < 32; i++ )
		{
			guid += Math.floor(Math.random() * 0xF).toString(0xF) + (i === 8 || i === 12 || i === 16 || i === 20 ? '-' : '');
		}
		return guid.toUpperCase() + "}";
	}
});
