// Provides numerous DOM helper objects

// Returns a four position array of the object's top, left, height, width in pixels.
function getObjectDimensions(obj) {
	if (typeof obj == "string") {
		obj=document.getElementById(obj);
	}
	if (typeof obj == "undefined") return null;
	if (obj==null) return null;
	
	widthVal=obj.offsetWidth;
	heightVal=obj.offsetHeight;
	
	leftVal=0;
	topVal=0;
	
	do {
		leftVal+=obj.offsetLeft;
		topVal+=obj.offsetTop;
		obj=obj.offsetParent;
	} while (obj!=null);	
	
	return [topVal, leftVal, heightVal, widthVal];
}

// Move an object to the position of another object.
// If bRelativeToLeft or bRelativeToTop are false, it will position relative to the right or bottom edge.
// The offset values allow you to specify an amount to offset this position by.
function moveObjectTo(moveObject, toObject, bRelativeToLeft, bRelativeToTop, offsetFromLeft, offsetFromTop) {
	if (typeof moveObject == "string") {
		moveObject=document.getElementById(moveObject);
	}
	if (typeof moveObject == "undefined") return false;
	if (moveObject==null) return false;
	
	toObjDimensions=getObjectDimensions(toObject);
	if (toObjDimensions==null) return false;
	
	leftVal=toObjDimensions[1];
	topVal=toObjDimensions[0];
	
	if (!bRelativeToLeft) leftVal+=toObjDimensions[3];
	if (!bRelativeToTop) topVal+=toObjDimensions[2];
	
	leftVal+=offsetFromLeft;
	topVal+=offsetFromTop;
	
	moveObject.style.left=leftVal+"px";
	moveObject.style.top=topVal+"px";
	
	return true;
}

function containsClassName(obj, className) {
	if (typeof obj == "string") {
		obj=document.getElementById(obj);
	}
	if (typeof obj == "undefined") return false;
	if (obj==null) return false;
	
	if ( (typeof obj.className=="undefined") || (obj.className==null) || (obj.className=="") ) {
		return false;
	} else {
		// Build a regular expression to match "[word boundary]newClassName[word boundary]"
		regMatch=new RegExp("\\b"+className+"\\b", "gi");
		
		if (obj.className.search(regMatch)==-1) {
			return false;
		} else {
			return true;
		}
	}
}

// Adds a new class to an object without losing any of the existing classes.
function addClass(obj, newClassName) {
	if (typeof obj == "string") {
		obj=document.getElementById(obj);
	}
	if (typeof obj == "undefined") return false;
	if (obj==null) return false;
	
	// If there is no existing className, simply write it in.
	if ( (typeof obj.className=="undefined") || (obj.className==null) || (obj.className=="") ) {
		obj.className=newClassName;
	} else {
		if (containsClassName(obj, newClassName)==false) {
			obj.className+=" "+newClassName;
		}
	}
	return true;
}

// Removes a class from an object without affecting any other classes it might have.
function removeClass(obj, classNameToRemove) {
	if (typeof obj == "string") {
		obj=document.getElementById(obj);
	}
	if (typeof obj == "undefined") return null;
	if (obj==null) return null;
	
	// Build a regular expression to match "[word boundary]newClassName[word boundary]" 
	//plus versions with preceeding and post spacing.
	regMatchNoSpace=new RegExp("\\b"+classNameToRemove+"\\b", "gi");
	regMatchPreSpace=new RegExp("\\s"+classNameToRemove+"\\b", "gi");
	regMatchPostSpace=new RegExp("\\b"+classNameToRemove+"\\s", "gi");
	
	// If there is no existing className, nothing needs removing.
	if ( (typeof obj.className=="undefined") || (obj.className==null) || (obj.className=="") ) {
		return;
	} else {
		obj.className=obj.className.replace(regMatchPreSpace, "");
		obj.className=obj.className.replace(regMatchPostSpace, "");
		obj.className=obj.className.replace(regMatchNoSpace, "");
	}
}

// Copy the content from one object to another object.
function copyContents(fromObj, toObj) {
	if (typeof fromObj == "string") {
		fromObj=document.getElementById(fromObj);
	}
	if (typeof fromObj == "undefined") return false;
	if (fromObj==null) return false;
	
	if (typeof toObj == "string") {
		toObj=document.getElementById(toObj);
	}
	if (typeof toObj == "undefined") return false;
	if (toObj==null) return false;
	
	toObj.innerHTML=fromObj.innerHTML;
	
	return true;
}

// Returns an array of all elements of a given tagName with a given className
// If you want to apply this to ALL elements and only search by className,
// simply set tagName to "*"
function getElementsByTagAndClassNames(tagName, className, parentObj) {
	if (typeof parentObj=="undefined") { parentObj=document; }
	if (typeof parentObj=="string") { parentObj=document.getElementById(parentObj); }
	if (parentObj==null) { parentObj=document; }
	
	results=new Array();
	
	allTags=parentObj.getElementsByTagName(tagName);
	
	if (allTags==null) return results;
	
	for (var count=0; count<allTags.length; count++) {
		if (containsClassName(allTags[count], className)) {
			results[results.length]=allTags[count];
		}
	}
	
	return results;
}

// Returns an array of all elements of a given tagName that have an id starting with the prefix.
// If you want to apply this to ALL elements and only search by id prefix
// simply set tagName to "*"
function getElementsByTagAndIDPrefix(tagName, idPrefix) {
	results=new Array();
	
	allTags=document.getElementsByTagName(tagName);
	
	if (allTags==null) return results;
	
	for (var count=0; count<allTags.length; count++) {
		if (typeof allTags[count].id!="undefined") {
			if (allTags[count].id!=null) {
				if (allTags[count].id.toString().indexOf(idPrefix)==0) {
					results[results.length]=allTags[count];
				}
			}
		}
	}
	
	return results;
}

// Returns an array of all elements of a given tagName that have a given "name" parameter
// If you want to apply this to ALL elements and only search by "name"
// simply set tagName to "*"
function getElementsByTagAndName(tagName, nameParam) {
	results=new Array();
	
	allTags=document.getElementsByTagName(tagName);
	
	if (allTags==null) return results;
	
	for (var count=0; count<allTags.length; count++) {
		if (typeof allTags[count].name!="undefined") {
			if (allTags[count].name!=null) {
				if (allTags[count].name==nameParam) {
					results[results.length]=allTags[count];
				}
			}
		}
	}
	
	return results;
}

// Returns all tags of a given tagName that are direct children of the parentObj
function getImmediateChildrenByTagName(parentObj, tagName) {
	results=new Array();
	
	allTags=document.getElementsByTagName(tagName);
	
	if (allTags==null) return results;
	
	for (var count=0; count<allTags.length; count++) {
		if (allTags[count].parentNode==parentObj) {
			results[results.length]=allTags[count];
		}
	}
	
	return results;
}

// Returns the first parentNode of a given obj that has a given tagName
// Or returns null if it can't be found.
function getFirstParentNodeOfTagName(obj, tagName) {
	if (typeof obj == "string") {
		obj=document.getElementById(obj);
	}
	if (typeof obj == "undefined") return null;
	if (obj==null) return null;
	
	do {
		if (obj.nodeName.toString().toLowerCase()==tagName.toString().toLowerCase()) {
			return obj;
		}
		obj=obj.parentNode;
	} while (obj!=null);
	
	return null;
}

// Returns the first parentNode of a given obj that has a given className
// Or returns null if it can't be found.
function getFirstParentNodeOfClassName(obj, className) {
	if (typeof obj == "string") {
		obj=document.getElementById(obj);
	}
	if (typeof obj == "undefined") return null;
	if (obj==null) return null;
	
	do {
		if (containsClassName(obj, className)) {
			return obj;
		}
		obj=obj.parentNode;
	} while (obj!=null);
	
	return null;
}

// Sets an object's display style to block
function showObj(obj) {
	if (typeof obj == "string") {
		obj=document.getElementById(obj);
	}
	if (typeof obj == "undefined") return false;
	if (obj==null) return false;
	
	obj.style.display="block";
}

// Sets an object's display style to none
function hideObj(obj) {
	if (typeof obj == "string") {
		obj=document.getElementById(obj);
	}
	if (typeof obj == "undefined") return false;
	if (obj==null) return false;
	
	obj.style.display="none";
}

// Move an object relative to another and then display it
function moveToAndShow(moveObject, toObject, bRelativeToLeft, bRelativeToTop, offsetFromLeft, offsetFromTop) {
	moveObjectTo(moveObject, toObject, bRelativeToLeft, bRelativeToTop, offsetFromLeft, offsetFromTop);
	showObj(moveObject);
}

// Assign a given function to the onclick events of all elements in an array
// Will also work with a single item
// Warning: Will overwrite any existing onclicks
function assignOnClick(obj, onclickfn) {
	if (typeof obj == "string") obj=document.getElementById(obj);
	if (typeof obj == "undefined") return false;
	if (obj == null) return false;
		
	if (typeof obj.length=="number") { // It's an array
		for (var count=0; count<obj.length; count++) {
			obj[count].onclick=onclickfn;
		}
	} else {
		obj.onclick=onclickfn;
	}
	
	return true;
}

// Gets the zero indexed column number of a given object
function getColumnNumber(obj) {
	if ( (obj.nodeName.toString().toLowerCase()!="td") && (obj.nodeName.toString().toLowerCase()!="th") ) { // Not a td or th
		return -1;
	}
	
	tr=obj.parentNode; // Get the parent tr - should always be the parent of the td or th
	
	tdthcount=0;
	for (var count=0; count<tr.childNodes.length; count++) { // Move through the child nodes of the tr
		if ( (tr.childNodes[count].nodeName.toString().toLowerCase()=="td") || (tr.childNodes[count].nodeName.toString().toLowerCase()=="th") ) { // If a td or th is found
			if (tr.childNodes[count]==obj) { // If it is the object we're looking for (as opposed to the droids we are not)
				return tdthcount; // Return that position
			}
			tdthcount+=tr.childNodes[count].rowSpan; // Increment the counter
		}
	}
	return -1; // It wasn't found, return -1;
}

// Moves through the tds and ths in a tr
// When it gets to the appropriate one
// It hides it.
function hideTDorTH(tr, columnCount) {
	tdthcount=0;
	for (htdothcount=0; htdothcount<tr.childNodes.length; htdothcount++) {
		if ( (tr.childNodes[htdothcount].nodeName.toString().toLowerCase()=="td") || (tr.childNodes[htdothcount].nodeName.toString().toLowerCase()=="th") ) {
			if (tdthcount==columnCount) {
				hideObj(tr.childNodes[htdothcount]);
			}
			tdthcount+=tr.childNodes[htdothcount].rowSpan;
		}
	}
}

// Move through a containing element (thead, tbody, tfoot, table) and process all trs that are immediate children of it.
// Only process immediate children or you get issues with nested tables.
function hideColumnsWithinTRContainer(trcontainer, columnCount) {
	trs=getImmediateChildrenByTagName(trcontainer, "tr");
	for (hcwtrccount=0; hcwtrccount<trs.length; hcwtrccount++) {
		hideTDorTH(trs[hcwtrccount], columnCount)
	}
}

// Hide a specific column within a table
// table - the table element 
// columnCount - the zero indexed column to lose
// bInclude... - whether to look in theads, tbodys, tfoots, and the table tag itself for trs as immediate children
function hideColumn(table, columnCount, bIncludeHead, bIncludeBody, bIncludeFoot, bIncludeSyntacticallyPoorTables) {
	if (typeof table == "string") table=document.getElementById(table);
	if (typeof table == "undefined") return false;
	if (table == null) return false;
	
	// If desired, check in the theads
	if (bIncludeHead) {
		thead=getImmediateChildrenByTagName(table, "thead");
		for (var count=0; count<thead.length; count++) {
			hideColumnsWithinTRContainer(thead[count], columnCount);
		}
	}
	
	// If desired, check in the tbodys
	if (bIncludeBody) {
		tbody=getImmediateChildrenByTagName(table, "tbody");
		for (var count=0; count<tbody.length; count++) {
			hideColumnsWithinTRContainer(tbody[count], columnCount);
		}
	}
	
	// If desired, check in the tfoots
	if (bIncludeFoot) {
		tfoot=getImmediateChildrenByTagName(table, "tfoot");
		for (var count=0; count<tfoot.length; count++) {
			hideColumnsWithinTRContainer(tfoot[count], columnCount);
		}
	}
	
	// If desired, check in the table itself - this implies sucky syntax on the HTML part as all trs should be in thead/tbody/tfoot.
	if (bIncludeSyntacticallyPoorTables) {
		hideColumnsWithinTRContainer(table, columnCount);
	}
}