
function calculateOffsetLeft(r) { return sumUpOffsetChain(r, "offsetLeft"); }
function calculateOffsetTop(r) { return sumUpOffsetChain(r, "offsetTop"); }
function calculateOffsetRight(r) { return r.offsetWidth + calculateOffsetLeft(r); }
function calculateOffsetBottom(r) { return r.offsetHeight + calculateOffsetTop(r); }

function overlapHorizontal(f1, f2) { return overlapCommon(f1, f2, calculateOffsetLeft, calculateOffsetRight); }
function overlapVertical(f1, f2) { return overlapCommon(f1, f2, calculateOffsetTop, calculateOffsetBottom); }
function isBetween(checkValue, beforeValue, afterValue) {
	return checkValue >= beforeValue && checkValue <= afterValue;
}
function overlapCommon(elementOne, elementTwo, beforeFunction, afterFunction) {
	var before1 = beforeFunction(elementOne); var after1 = afterFunction(elementOne);
	var before2 = beforeFunction(elementTwo); var after2 = afterFunction(elementTwo);

	// These three checks cover all possible overlap cases.
	return isBetween(before1, before2, after2) || isBetween(before2, before1, after1) || isBetween(after1, before2, after2);
}
function elementsOverlap(elementA, elementB) {
	return overlapHorizontal(elementA, elementB) && overlapVertical(elementA, elementB);
}

function sumUpOffsetChain(currentNode, attributeName){
	var theSum = 0;
	while (currentNode) {
		theSum += currentNode[attributeName];
		currentNode = currentNode.offsetParent;
	}
	return theSum;
}

function windowDimension(widthOrHeight) {
	var inner = 'inner' + widthOrHeight;
	var client = 'client' + widthOrHeight;
	return window[inner] || (document.documentElement && document.documentElement[client] > 0 && document.documentElement[client]) || document.body[client];
}
function windowWidth() { return windowDimension('Width'); }
function windowHeight() { return windowDimension('Height'); }


// IE has a non-javascript bug that causes select boxes to appear above things
// they should be below (because it uses the Windows builtins to draw them, or
// something, I believe). To prevent mass uglification, we detect IE, and hide
// them.
function hideSelectBoxes() {
	return navigator && navigator.userAgent && navigator.userAgent.toLowerCase().match(/msie/);
}
function clearAreaOfBrokenObjects(contentArea, hoverArea, purpose) {
	if (hideSelectBoxes()) {
		if (purpose) {
			if (!contentArea.brokenObjectsHidden)
				contentArea.brokenObjectsHidden = {};
			if (contentArea.brokenObjectsHidden[purpose])
				return;
			contentArea.brokenObjectsHidden[purpose] = 1;
		}
		var selectList = contentArea.getElementsByTagName('select');
		for (var i = 0; i < selectList.length; i++)
			hideObject(selectList[i], elementsOverlap(selectList[i], hoverArea));
	}
}
function hideObject(obj, doHide) {
	if (!obj || !obj.style)
		return;

	if (!obj.oldVisibilityStack) obj.oldVisibilityStack = [];

	obj.oldVisibilityStack[obj.oldVisibilityStack.length] = obj.style.visibility || 'visible';
	if (doHide)
		obj.style.visibility = 'hidden';
}
function unHideObject(obj) {
	// If something's gone horribly wrong, and we never hid the object, assume
	// we should be making it visible, as that's generally what we're here for.
	if (!obj.oldVisibilityStack || obj.oldVisibilityStack.length <= 0)
		obj.oldVisibilityStack = ['visible'];

	var oldVal = obj.oldVisibilityStack[obj.oldVisibilityStack.length - 1];
	obj.oldVisibilityStack.length--;
	obj.style.visibility = oldVal || 'visible';
}
function restoreBrokenObjects(contentArea, purpose) {
	if (hideSelectBoxes()) {
		if (purpose) {
			if (!contentArea.brokenObjectsHidden)
				contentArea.brokenObjectsHidden = {};
			if (!contentArea.brokenObjectsHidden[purpose])
				return;
			contentArea.brokenObjectsHidden[purpose] = 0;
		}
		var selectList = contentArea.getElementsByTagName('select');
		for (var i = 0; i < selectList.length; i++)
			unHideObject(selectList[i]);
	}
}


function positionDivAsCloseAsPossible(targetNode, divToPosition, currentX, currentY, offsetX, offsetY, divContainer) {
   var divBoundaries = { left: 0, top: 0, right: windowWidth(), bottom: windowHeight() };
   if (divContainer)
      divBoundaries = {
         left: calculateOffsetLeft(divContainer),
         top: calculateOffsetTop(divContainer),
         right: calculateOffsetRight(divContainer),
         bottom: calculateOffsetBottom(divContainer)
      };
   var posX = currentX + offsetX;
   var posY = currentY + offsetY;
   var previousDisplay = divToPosition.style.display;
   divToPosition.style.display = '';
   if (offsetX < 0) { posX -= divToPosition.offsetWidth; }
   if (offsetY < 0) { posY -= divToPosition.offsetHeight; }
   if (posX + divToPosition.offsetWidth >= divBoundaries.right) posX = divBoundaries.right - divToPosition.offsetWidth;
   if (posY + divToPosition.offsetHeight >= divBoundaries.bottom) posY -= 2 * Math.abs(offsetY) + divToPosition.offsetHeight;
   if (posX < divBoundaries.left) posX = 0;
   if (posY < divBoundaries.top) posY += 2 * Math.abs(offsetY) + divToPosition.offsetHeight;
   divToPosition.style.left = posX + 'px';
   divToPosition.style.top = posY + 'px';
   divToPosition.style.display = previousDisplay;
}

