/*
	Locate one element onscreen relative to another
*/
function locateRelativeTo(landmark, element, relationship, horizontalPad, verticalPad, debug) {
	if(horizontalPad == null)	horizontalPad = 0;
	if(verticalPad == null)		verticalPad = 0;
	if(debug == null)			debug = false;
	
	//	get landmark element boundary co-ordinates
	var lmLeft = getOffsetLeft(landmark.id);
	var lmTop = getOffsetTop(landmark.id);
	var lmRight = lmLeft + landmark.offsetWidth;
	var lmBottom = lmTop + landmark.offsetHeight;
	if(debug) {
		alert("landmark [l,r,t,b]: " + lmLeft + ", " + lmRight + ", " + lmTop + ", " + lmBottom);
	}
	
	//	new co-ords, if needed
	var newLeft = null;
	var newTop = null;
	
	//	reposition based on requested relationship
	switch(relationship) {
		case "on_top_of":
			element.style.left = (lmLeft + horizontalPad) + "px";
			element.style.top = (lmTop + verticalPad) + "px";
			break;
			
		case "below":
			element.style.left = (lmLeft + horizontalPad) + "px";
			newTop = lmBottom + verticalPad;
			element.style.top = newTop + "px";
			if(debug)
				alert("bottom + pad = newTop: " + lmBottom + " + " + verticalPad + " = " + newTop);
			break;
			
		case "above":
			element.style.left = (lmLeft + horizontalPad) + "px";
			newTop = lmTop - element.offsetHeight - verticalPad;
			element.style.top = newTop + "px";
			if(debug)
				alert("top - elementHeight - pad = newTop: " + lmTop + " - " + element.offsetHeight + " - " + verticalPad + " = " + newTop);
			break;
			
		case "to_right_of":
			newLeft = lmRight + horizontalPad;
			element.style.left = newLeft + "px";
			if(debug)
				alert("right + pad = newLeft: " + lmRight + " + " + horizontalPad + " = " + newLeft);
			break;
			
		case "to_left_of":
			newLeft = lmLeft - element.offsetWidth - horizontalPad;
			element.style.left = newLeft + "px";
			if(debug)
				alert("left - elementWidth - pad = newLeft: " + lmLeft + " - " + element.offsetWidth + " - " + horizontalPad + " = " + newLeft);
			break;
			
		default:
			alert("Invalid relationship parameter, must be:\n\n\t[above | below | to_left_of | to_right_of | on_top_of]");
			return;
	}	// switch
}

/*
	Make sure an element is totally onscreen, and if it's not, move it so that it is.  Useful 
	when displaying popup menus and other hidden elements that will be dynamically located.
*/
function ensureOnscreen(element, horizontalPad, verticalPad, debug) {
	if(horizontalPad == null)	horizontalPad = 10;
	if(verticalPad == null)		verticalPad = 10;
	if(debug == null)			debug = false;

	//	new co-ordinatses, if needed
	var newLeft = null;
	var newTop = null;
	
	//	get current viewport (client window/screen) boundary co-ordinates
	var minLeft = getScrollX(null, debug);
	var minTop = getScrollY(null, debug);
	var maxRight = minLeft + getVisiblePageWidth(null, debug);
	var maxBottom = minTop + getVisiblePageHeight(null, debug);
	if(debug) {
		alert("viewport [l,r,t,b]: " + minLeft + ", " + maxRight + ", " + minTop + ", " + maxBottom);
	}
	
	//	get element boundary co-ordinates
	var objLeft = element.offsetLeft;
	var objTop = element.offsetTop;
	var objRight = objLeft + element.offsetWidth;
	var objBottom = objTop + element.offsetHeight;
	if(debug) {
		alert("element [l,r,t,b]: " + objLeft + ", " + objRight + ", " + objTop + ", " + objBottom);
	}
	
	//	 if the dimensions are offscreen (not visible), change them
	if(objRight > maxRight)
		newLeft = maxRight - element.offsetWidth - horizontalPad;

	if(objLeft < minLeft)
		newLeft = minLeft + horizontalPad;

	if(objBottom > maxBottom)
		newTop = maxBottom - element.offsetHeight - verticalPad;

	if(objTop < minTop)
		newTop = minTop + verticalPad;
	
	//	if co-ordinates were changed above, move the element onscreen
	if(newLeft != null)
		element.style.left = newLeft + "px";

	if(newTop != null)
		element.style.top = newTop + "px";
}


function expandToAccomodate(containerID, childID, extraWidth, extraHeight) {
	widenToAccomodate(containerID, childID, extraWidth);
	lengthenToAccomodate(containerID, childID, extraHeight)
}

function widenToAccomodate(containerID, childID, extraWidth) {
	if(extraWidth == null)		extraWidth = 0;
	
	var container = document.getElementById(containerID);
	var child = document.getElementById(childID);
	
	var childWidth = child.offsetWidth + extraWidth;
	
	container.style.width = childWidth + "px";
}

function lengthenToAccomodate(containerID, childID, extraHeight) {
	if(extraHeight == null)		extraHeight = 0;
	
	var container = document.getElementById(containerID);
	var child = document.getElementById(childID);
	
	var childHeight = child.offsetHeight + extraHeight;
	
	container.style.height = childHeight + "px";
}


/*	needed to enable IE workarounds in some cases, IE is the only browser we will cater to
	in this way, due to it's popularity, all other code will be W3C standard	*/
function isIE() {
	if(navigator.appName.indexOf("Microsoft Internet Explorer") == -1)
		return false;
	else
		return true;
}


/*
	Helper functions used by functions above to overcome some differing browser support
	for measuring window and elemente size and position.
*/
function getVisiblePageHeight(useDocumentElement, debug) {
	if(useDocumentElement == null)		useDocumentElement = false;
	if(debug == null)			debug = false;
	var retVal;
	
	if(debug) {
		alert("document.documentElement.clientHeight = " + document.documentElement.clientHeight
			  + "\nwindow.innerHeight = " + window.innerHeight
			  + "\ndocument.body.clientHeight = " + document.body.clientHeight);
	}
	
	if (useDocumentElement && document.documentElement && document.documentElement.clientHeight)
		retVal = document.documentElement.clientHeight;
	else if (window.innerHeight)
		retVal = window.innerHeight;
	else if (document.body)
		retVal = document.body.clientHeight;
	else
		retVal = "not able to determine page height due to crummy DHTML support";
	
	if(debug)
		alert(retVal);

	return retVal;
}

function getVisiblePageWidth(useDocumentElement, debug) {
	if(useDocumentElement == null)		useDocumentElement = false;
	if(debug == null)					debug = false;
	var retVal;

	if(debug) {
		alert("document.documentElement.clientWidth = " + document.documentElement.clientWidth
			  + "\nwindow.innerWidth = " + window.innerWidth
			  + "\ndocument.body.clientWidth = " + document.body.clientWidth);
	}

	if (useDocumentElement && document.documentElement && document.documentElement.clientWidth)
		retVal = document.documentElement.clientWidth;
	else if (window.innerWidth)
		retVal = window.innerWidth;
	else if (document.body)
		retVal = document.body.clientWidth;
	else
		retVal = "not able to determine page width due to crummy DHTML support";

	if(debug)
		alert(retVal);

	return retVal;
}


function getScrollX(useDocumentElement, debug) {
	if(useDocumentElement == null)		useDocumentElement = false;
	if(debug == null)			debug = false;
	var retVal;
	
	if(debug) {
		alert("document.documentElement.scrollLeft = " + document.documentElement.scrollLeft
			  + "\nwindow.pageXOffset = " + window.pageXOffset
			  + "\ndocument.body.scrollLeft = " + document.body.scrollLeft);
	}

	if (useDocumentElement && document.documentElement && document.documentElement.scrollLeft)
		retVal = document.documentElement.scrollLeft;
	else if (window.pageXOffset)
		retVal = window.pageXOffset;
	else if (document.body)
		retVal = document.body.scrollLeft;
	else
		retVal = "not able to determine vertical page scrolling due to crummy DHTML support";

	if(debug)
		alert(retVal);

	return retVal;
}

function getScrollY(useDocumentElement, debug) {
	if(useDocumentElement == null)		useDocumentElement = false;
	if(debug == null)			debug = false;
	var retVal;
	
	if(debug) {
		alert("document.documentElement.scrollTop = " + document.documentElement.scrollTop
			  + "\nwindow.pageYOffset = " + window.pageYOffset
			  + "\ndocument.body.scrollTop = " + document.body.scrollTop);
	}

	if (useDocumentElement && document.documentElement && document.documentElement.scrollTop)
		retVal = document.documentElement.scrollTop;
	else if (window.pageYOffset)
		retVal = window.pageYOffset;
	else if (document.body)
		retVal = document.body.scrollTop;
	else
		retVal = "not able to determine vertical page scrolling due to crummy DHTML support";

	if(debug)
		alert(retVal);

	return retVal;
}


/*	gets true offsets for an element, to position other elements relative to it
	elements in tables will return co-ords realtive to their table cell, these fix that.	*/
function tagStack(elementID) {
	//	determine the tag stack above the supplied element
	var element = document.getElementById(elementID);
	var stack = element.tagName;
	
	while(element.parentNode) {
		element = element.parentNode;
		if(element.tagName)
			stack += "," + element.tagName;
	}
	
	return stack;
}

//	get a parent tag of an element
function getParentTag(elementID, tagName) {
	var stack = tagStack(elementID);
	var regEx = new RegExp(tagName, "gi");
	var node = document.getElementById(elementID);
	
	if(stack.search(regEx) == -1)
		return null;
	else {
		while(node.parentNode) {
			node = node.parentNode;
			if(node.tagName.toLowerCase() == tagName.toLowerCase())
				return node;
		}
		return true;
	}
}


function getOffsetLeft(elementID) {
	var element = document.getElementById(elementID);
	var left = element.offsetLeft;

	var parentTd = getParentTag(elementID, "td");
	var parentTable = getParentTag(elementID, "table");
	var parentBody = getParentTag(elementID, "body");
	

	if(parentTd) {
		left += parentTd.offsetLeft + parentTable.offsetLeft;
		//	exploder considers the body padding extra, not factored into the table result, as Mozilla does
		if(isIE())
			left += parentBody.offsetLeft;
	}
	
	return left;
}

function getOffsetTop(elementID) {
	var element = document.getElementById(elementID);
	var top = element.offsetTop;

	var parentTd = getParentTag(elementID, "td");
	var parentTable = getParentTag(elementID, "table");
	var parentBody = getParentTag(elementID, "body");

	if(parentTd) {
		top += parentTd.offsetTop + parentTable.offsetTop;
		if(isIE())
		//	exploder considers the body padding extra, not factored into the table result, as Mozilla does
			top += parentBody.offsetTop;
	}
	
	return top;
}
