/**
	Gets tags in the page or under a Tag/Element by CSS Selector.
	
	Currently supports:
		id + [tag] + [classes]				e.g.: #myId, ul#myId, ul#myId.menu.active
		tag									e.g.: ul
		tag + class							e.g.: ul.menu
		tag + class + class ...				e.g.: ul.menu.active.pretty
		token token token					e.g.: ul#mainmenu li.mycategory
	
	@TODO: support just classes				e.g.: .menu.active		// may perform very poorly!
*/
document.getBySelector = Tag_getBySelector;
function Tag_getBySelector(sSelector) {	// uses basic CSS selectors to get tags
	var selector = new Selector(sSelector);
	var tags = new Array();
	
	// hack for Mozilla; "body" is a tag but takes no events
	if(sSelector == 'body' && document.body.addEventListener) {	// more selectors than just "body" will get proper results without this fix
		tags.push(window);
		return tags;	// applying selectors to "window" would cause errors
	}
	
	tags.push(this);		// tags is initially just current tag

	var simple;

	while(simple = selector.next()) {
		var tagParents = tags;
		tags = new Array();

		for(var iParent = tagParents.length - 1; iParent >= 0; iParent--) {
			var tagParent = tagParents[iParent];
			if(simple.id) {
				var tag = tagParent.getElementById(simple.id);
				if(tag.tagName && tag.tagName == simple.tag.toUpperCase()) {
					for(var iClass = simple.classList.length - 1; iClass >= 0 && callHasClass(tag, simple.classList[iClass]); iClass--)
						{}
					
					if(iClass < 0) {
						tags.push(tag);
					}
				}
			} else {
				if(simple.tag) {
					if(simple.classList.length == 0) {
						if(tagParent.getElementsByTagName) {	// make sure this is an Element, not just a Node
							var domtags = tagParent.getElementsByTagName(simple.tag);
							for(var iDomtag = 0; iDomtag < domtags.length; iDomtag++) {
								tags.push(domtags[iDomtag]);
							}
						}
					} else if(simple.classList.length == 1) {
						tags = tags.concat(callGetTagsByClassName(tagParent, simple.tag, simple.classList[0]));
					} else {
						tags = tags.concat(callGetTagsByClassList(tagParent, simple.tag, simple.classList));
					}
				}
			}
		}
		
		// eliminate matches from the "not" clause
		if(simple.not) {
			var sId = simple.not.id;
			var sClassList = simple.not.classList;
			for(var iTag = tags.length - 1; iTag >= 0; iTag--) {
				var tag = tags[iTag];
				
				var bHasId = false;
				var bId = false;
				if(sId) {
					bHasId = true;
							
					if(tag.id == sId)
						bId = true;
				}

				var bHasClass = sClassList.length > 0;
				var bClass = false;
				if(bHasClass) {				
					var sTagClassList = tag.className.toString().split(' ');
					for(var iClass = sClassList.length - 1; iClass >= 0 && sTagClassList.has(sClassList[iClass]); iClass--)
						{}
					
					bClass = (iClass < 0);	// matched all classes
				}
				
				if(
					(bId && bClass)
					|| (!bHasId && bClass)
					|| (bId && !bHasClass)
				) {
					tags.splice(iTag, 1);
				}
			}
		}
	}
	
	return tags;
}
function callGetBySelector(tag, sSelector) {
	tag.getBySelector = Tag_getBySelector;
	return tag.getBySelector(sSelector);
}

document.getTagsByClassName = Tag_getTagsByClassName;
function Tag_getTagsByClassName(sTag, sClass) {
	var tagsBase = document.getElementsByTagName(sTag);
	var tags = new Array();
	
	for(var i = tagsBase.length - 1; i >= 0; i--) {
		var tag = tagsBase[i];
		var sClassList = new String(tag.className);
		
		if(callHasClass(tag, sClass)) {
			tags.push(tag);
		}
	}
	
	return tags;
}
function callGetTagsByClassName(tag, sTag, sClass) {
	tag.getTagsByClassName = Tag_getTagsByClassName;
	return tag.getTagsByClassName(sTag, sClass);
}

document.getTagsByClassList = Tag_getTagsByClassList;
function Tag_getTagsByClassList(sTag, sClassList) {
	var tagsBase = document.getElementsByTagName(sTag);
	var tags = new Array();
	
	for(var i = tagsBase.length - 1; i >= 0; i--) {
		var tag = tagsBase[i];
		var sTagClassList = new String(tag.className);
		
		for(var iTagClass = sClassList.length - 1; iTagClass >= 0 && callHasClass(tag, sClassList[iTagClass]); iTagClass--)
			{}
		
		if(iTagClass < 0)
			tags.push(tag);
	}
	
	return tags;
}
function callGetTagsByClassList(tag, sTag, sClassList) {
	tag.getTagsByClassList = Tag_getTagsByClassList;
	return tag.getTagsByClassList(sClassList);
}

function Tag_hasClass(sClass) {
	var sClassList = (new String(this.className)).split(' ');
	return sClassList.has(sClass);
}
function callHasClass(tag, sClass) {
	tag.hasClass = Tag_hasClass;
	return tag.hasClass(sClass);
}

function Tag_getChildTags(sTagName) {
	sTagName = sTagName.toUpperCase();
	var tagChildList = new Array();

	for(var iChild = 0; iChild < this.childNodes.length; iChild++) {
		var tagChild = this.childNodes[iChild];
		if(tagChild.tagName && tagChild.tagName == sTagName)
			tagChildList.push(tagChild);
	}
	
	return tagChildList;
}
function callGetChildTags(tag, sTagName) {
	tag.getChildTags = Tag_getChildTags;
	return tag.getChildTags(sTagName);
}
