
// -------------------------------------------------------------------
// parseSelector() : parse CSS selectors
// Writen by Shaun Inman + Mark Wubben; tweaked by WSOD
// -------------------------------------------------------------------
var parseSelector = function(){
	var reParseSelector = /^([^#.>`]*)(#|\.|\>|\`)(.+)$/;
	function parseSelector(sSelector, oParentNode){
		var listSelectors = sSelector.split(/\s*\,\s*/);
		var listReturn = [];
		for(var i = 0; i < listSelectors.length; i++){
			listReturn = listReturn.concat(doParse(listSelectors[i], oParentNode));
		};
		
		return listReturn;
	};
	
	function doParse(sSelector, oParentNode, sMode){
		sSelector = sSelector.replace(" ", "`");
		var selector = sSelector.match(reParseSelector);
		var node, listNodes, listSubNodes, subselector, i, limit;
		var listReturn = [];
		
		if(selector == null){ selector = [sSelector, sSelector] };
		if(selector[1] == ""){ selector[1] = "*" };
		if(sMode == null){ sMode = "`" };
		if(oParentNode == null){
			oParentNode = document;
		};

		switch(selector[2]){
			case "#":
				subselector = selector[3].match(reParseSelector);
				if(subselector == null){ subselector = [null, selector[3]] };
				node = 	document.getElementById(subselector[1]);
				if(node == null || (selector[1] != "*" && !matchNodeNames(node, selector[1]))){
					return listReturn;
				};
				if(subselector.length == 2){
					listReturn.push(node);
					return listReturn;	
				};
				return doParse(subselector[3], node, subselector[2]);
			case ".":
				if(sMode != ">"){
					listNodes = getElementsByTagName(oParentNode, selector[1]);
				} else {
					listNodes = oParentNode.childNodes;
				};
				
				for(i = 0, limit = listNodes.length; i < limit; i++){
					node = listNodes[i];
					if(node.nodeType != 1){
						continue;	
					};
					subselector = selector[3].match(reParseSelector);
					if(subselector != null){
						if(node.className == null || node.className.match("\\b" + subselector[1] + "\\b") == null){
							continue;
						};
						listSubNodes = doParse(subselector[3], node, subselector[2]);
						listReturn = listReturn.concat(listSubNodes);	
					} else if(node.className != null && node.className.match("\\b" + selector[3] + "\\b") != null){
						listReturn.push(node);
					};
				};
				return listReturn;
			case ">":
				if(sMode != ">"){
					listNodes = getElementsByTagName(oParentNode, selector[1]);
				} else {
					listNodes = oParentNode.childNodes;
				};
								
				for(i = 0, limit = listNodes.length; i < limit; i++){
					node = listNodes[i];
					
					if(node.nodeType != 1){
						continue;	
					};
					
					if(!matchNodeNames(node, selector[1])){
						continue;
					};
					listSubNodes = doParse(selector[3], node, ">");
					listReturn = listReturn.concat(listSubNodes);	
				};
				return listReturn;
			case "`":
				listNodes = getElementsByTagName(oParentNode, selector[1]);
				for(i = 0, limit = listNodes.length; i < limit; i++){
					node = listNodes[i];
					listSubNodes = doParse(selector[3], node, "`");
					listReturn = listReturn.concat(listSubNodes);	
				};
				return listReturn;
			default:
				if(sMode != ">"){
					listNodes = getElementsByTagName(oParentNode, selector[1]);
				} else {
					listNodes = oParentNode.childNodes;
				};

				for(i = 0, limit = listNodes.length; i < limit; i++){
					node = listNodes[i];
					if(node.nodeType != 1){
						continue;	
					};
					if(!matchNodeNames(node, selector[1])){
						continue;
					};
					listReturn.push(node);
				};
				return listReturn;
		};
	};
	
	function getElementsByTagName(oParentNode, sTagName){
		/*	IE5.x does not support document.getElementsByTagName("*")
			therefore we're falling back to element.all */
		if(sTagName == "*" && oParentNode.all != null){
			return oParentNode.all;
		};
		return oParentNode.getElementsByTagName(sTagName);
	};
	
	function matchNodeNames(node, sMatch){
		if(sMatch == "*"){
			return true;
		};
		return node.nodeName.toLowerCase().replace("html:", "") == sMatch.toLowerCase();
	};
	
	return parseSelector;
}();

// alternate name
document.getElementsBySelector = parseSelector;

