/*
 * Misc functions used by lots of things
 */

/*
 * Stretch an object out to fill its parent.  Give space for siblings
 * If Mozilla didn't have a funky bug, we could *maybe* do this without JavaScript
 * 
 * A more robust stretchObject() replacement
 */
function fitToParent(el, tweakVal) {
	if(typeof el == "string") el = document.getElementById(el);
	
	// we set overflow = hidden so that large children don't muck things up
	if(el.parentNode.style.overflow != 'auto') el.parentNode.style.overflow = 'hidden';
	
	var otherHeight = 0;
	
	var notAComment;
	for(var i=0;i<el.parentNode.childNodes.length;i++) {
		if(el.parentNode.childNodes[i].outerHTML == null) notAComment = true;
		else if(el.parentNode.childNodes[i].outerHTML.indexOf("<!--") != 0) notAComment = true;
		else notAComment = false;
		if(el.parentNode.childNodes[i].className && el.parentNode.childNodes[i].className.indexOf('fitToParent_ignore') != -1) notAComment = false;
		
		if((el != el.parentNode.childNodes[i]) && 
				el.parentNode.childNodes[i].offsetHeight && notAComment && (el.parentNode.childNodes[i].tagName.toLowerCase() != 'script') && (el.parentNode.childNodes[i].style.display != 'none')) {
			otherHeight += parseInt(el.parentNode.childNodes[i].offsetHeight);
		}
	}
		
	if(!tweakVal) tweakVal = 0;
	
//	if(el.clientHeight) tweakVal += el.offsetHeight - el.clientHeight;
	tweakVal += getDimension(el,'marginTop');
	tweakVal += getDimension(el,'marginBottom');
	tweakVal += getDimension(el,'paddingTop');
	tweakVal += getDimension(el,'paddingBottom');


	tweakVal += getDimension(el,'borderBottomWidth');
	tweakVal += getDimension(el,'borderTopWidth');


	if(el.parentNode.offsetHeight - otherHeight - tweakVal < 0)
		el.style.height = '0px';
	else
		el.style.height = (el.parentNode.offsetHeight - otherHeight - tweakVal) + 'px';
}

/*
 * Returns the value of the given dimension - marginBottom, paddingTop, etc
 * Checks both stylesheet and style="" attribute
 * Defaults to 0, always returns an integer
 */
function getDimension(el, dim, notAInteger) {
	if(!notAInteger) notAInteger = false;
	
	var checkForNoneValue = {
		'borderBottomWidth' : 'borderBottomStyle',
		'borderTopWidth' : 'borderTopStyle',
		'borderLeftWidth' : 'borderLeftStyle',
		'borderRightWidth' : 'borderRightStyle'
	};
	
	// Handle hidden borders
	if(checkForNoneValue[dim]) {
		if(getDimension(el, checkForNoneValue[dim], true) == 'none') return 0;
	}
	
	if(el.style[dim]) {
		return notAInteger ? el.style[dim] : parseInt(el.style[dim]);
	
	} else if(el.currentStyle) {
		if(el.currentStyle[dim] != 'auto') {
			return notAInteger ? el.currentStyle[dim] : parseInt(el.currentStyle[dim]);
		}
		
	} else if(document.defaultView && document.defaultView.getComputedStyle) {
		var s = document.defaultView.getComputedStyle(el, null);
		var val = s[dim];
		if(val) return notAInteger ? val : parseInt(val);
	}
	
	return notAInteger ? null : 0;
}



// Browser stuff
var agt = navigator.userAgent.toLowerCase();
var is_mac = (agt.indexOf("mac")!=-1);

/*
 * Stretch all stretchable objects
 */

var stretchObjects;

// Recursively get stretchable objects
function getStretchObjects(parentNode) {	
	var i;
	var curNode;
	
	for(i=0;i<parentNode.childNodes.length;i++) {
		curNode = parentNode.childNodes[i];
		if(curNode.tagName != null) {	
			// Don't iterate into the invisible
			if(curNode.style.display != "none") {
				if(curNode.stretchthis != null) {
					
					// If stretchthis component not yet set, give it an initial value to aid the calculations
					if(eval("curNode." + curNode.stretchthis) == "")
						eval("curNode." + curNode.stretchthis + " = parseInt(curNode.offsetHeight);");
						
					stretchObjects[stretchObjects.length] = curNode;
				
					// There's an option to search for stretchers within this node, and override
					// the stretchiness of this
					if(curNode.checkmychildren) getStretchObjects(curNode);
				} else {
					getStretchObjects(curNode);
				}				
			}
		}
	}
}

function stretchObject(dontShrinkObject, originalScrollHeight, stretchIterations, tweakValue) {
	t = Array();
	t[0] = getNow();
	
	var sObj;
	stretchObjects = new Array();
	getStretchObjects(document.body);

	// Remove stretch objects which have a stretcher as a child
	var i,j, badNodes = new Array(), newStretchObjects = new Array();
	for(i=0;i<stretchObjects.length;i++) {
		for(j=0;j<stretchObjects.length;j++) {
			// Restore the overflow that is changed below
			// alert(i + ', ' + stretchObjects[i].oldOverflow;
			if(stretchObjects[i].oldOverflow != null)
				stretchObjects[i].style.overflow = stretchObjects[i].oldOverflow;
				
			if(i != j && stretchObjects[i].contains(stretchObjects[j])) {
				badNodes[i] = true;
				stretchObjects[i].style.height = "";
				// A stretched object will often use overflow-auto to add a scrollbar
				if(stretchObjects[i].style.overflow == "auto") {
					stretchObjects[i].oldOverflow = "auto";
					stretchObjects[i].style.overflow = "visible";
				}
			} else {
				// If we've got auto overflow, default dontShrinkObject to false
				if(stretchObjects[i].style.overflow == "auto" && dontShrinkObject == null) {
					dontShrinkObject = false;
				}
			}
		}
	}

	// If we don't have auto overflow, default dontShrinkObject to true
	if(dontShrinkObject == null) dontShrinkObject = true;
	
	var newStretchObjects = new Array();
	for(i=0;i<stretchObjects.length;i++) {
		if(!badNodes[i]) newStretchObjects[newStretchObjects.length] = stretchObjects[i];
	}
	stretchObjects = newStretchObjects;

	var numDistinctStretchObjects = 0;
	var countedSiblings = Array();
	for(i=0;i<stretchObjects.length;i++) {
		if(stretchObjects[i].stretchsiblinggroup != null) {
			if(countedSiblings[stretchObjects[i].stretchsiblinggroup] == null) {
				countedSiblings[stretchObjects[i].stretchsiblinggroup] = true;
				numDistinctStretchObjects++;
			}
		} else {
			numDistinctStretchObjects++;
		}
	}

	t[1] = getNow();
	
	var sizeChange;

	if(tweakValue == null) tweakValue = 0;

	if(is_mac) {
		var totalHeight = 0;
		var nodeSet = document.body.childNodes;
		for(i=0;i<nodeSet.length;i++)
			if(nodeSet[i].tagName != null)	
				totalHeight += nodeSet[i].offsetHeight

		sizeChange = (document.body.scrollHeight - totalHeight - tweakValue);
	} else {
		sizeChange = (document.body.offsetHeight - document.body.scrollHeight - tweakValue);
	}
	
	// If we don't want to shrink the object, then don't do anything
	if(sizeChange < 0 && dontShrinkObject) {
		return;
	}
	
	// The amount of resizing on each stretchable object 
	sizeChange /= numDistinctStretchObjects;

	// Actually perform the stretching
	for(i=0;i<stretchObjects.length;i++) {
		sObj = stretchObjects[i];

		
		if(eval("parseInt(sObj." + sObj.stretchthis + ") + sizeChange") > 10) {
			eval("sObj." + sObj.stretchthis + " = parseInt(sObj." + sObj.stretchthis + ") + sizeChange;");
		} else {
			eval("sObj." + sObj.stretchthis + " = 10;");
		}
	}
	
	
	//alert(sizeChange + ', ' + stretchObjects.length);
	
	// Scroll bar setting
	if(document.body.scrollHeight > document.body.offsetHeight) document.body.scroll = "yes";
	else document.body.scroll = "no";

	// Sometimes stretchObject needs to be repeatedly called to converge to the right height
	// stretchIterations prevents infinite loops
	
	if(originalScrollHeight == null) originalScrollHeight = 0;
	if(stretchIterations == null) stretchIterations = 0;

	t[2] = getNow();

	stretchObjectWidth();

	t[3] = getNow();
	
//	showProfile(t);

	if(!dontShrinkObject) dontShrinkObject = false;
	
	if(document.body.scrollHeight != document.body.offsetHeight && stretchIterations < 50) {
		//alert('stretchObject(' + dontShrinkObject + ',' + document.body.scrollHeight + ', ' + (stretchIterations + 1) + ')');
		setTimeout('stretchObject(' + dontShrinkObject + ',' + document.body.scrollHeight + ', ' + (stretchIterations + 1) + ', ' + tweakValue + ')',50);
	}
	
}

function stretchObjectWidth(node) {
	if(node == null) node = document.body;
	
	if(node.stretchwidth != null) {
		eval("node." + node.stretchwidth + " = ''");
		if(document.body.offsetWidth < document.body.scrollWidth) {
			var tweakValue = 0;
			eval("node." + node.stretchwidth + " = parseInt(node.offsetWidth);");
			sizeChange = (document.body.offsetWidth - document.body.scrollWidth - tweakValue);
			if((parseInt(eval("node." + node.stretchwidth)) + sizeChange) >= 0) {
				eval("node." + node.stretchwidth + " = parseInt(node." + node.stretchwidth + ") + sizeChange;");
			}
		}
		
	} else {
		for(var i=0;i<node.childNodes.length;i++) {
			stretchObjectWidth(node.childNodes[i]);
		}
	}
}

/*
 * Cookie Functions
 */

// name - name of the cookie
// value - value of the cookie
// [expires] - expiration date of the cookie (defaults to end of current session)
// [path] - path for which the cookie is valid (defaults to path of calling document)
// [domain] - domain for which the cookie is valid (defaults to domain of calling document)
// [secure] - Boolean value indicating if the cookie transmission requires a secure transmission
// * an argument defaults when it is assigned null as a placeholder
// * a null placeholder is not required for trailing omitted arguments
function setCookie(name, value, expires, path, domain, secure) {
  var curCookie = name + "=" + escape(value) +
      ((expires) ? "; expires=" + expires.toGMTString() : "") +
      ((path) ? "; path=" + path : "") +
      ((domain) ? "; domain=" + domain : "") +
      ((secure) ? "; secure" : "");
  document.cookie = curCookie;
}

// name - name of the desired cookie
// * return string containing value of specified cookie or null if cookie does not exist
function getCookie(name) {
  var dc = document.cookie;
  var prefix = name + "=";
  var begin = dc.indexOf("; " + prefix);
  if (begin == -1) {
    begin = dc.indexOf(prefix);
    if (begin != 0) return null;
  } else
    begin += 2;
  var end = document.cookie.indexOf(";", begin);
  if (end == -1)
    end = dc.length;
  return unescape(dc.substring(begin + prefix.length, end));
}

function doWhileRunning(objButton) {
	if(this != null) objButton = this;
	if(objButton.WHILERUNNING != null)
		objButton.value = objButton.WHILERUNNING;
}

/*
 * Image Preloading
 */
var preloadedImages = Array();

// Preload the given image
function preloadImage(imageName) {
	var i = preloadedImages.length;
	preloadedImages[i] = new Image();
	preloadedImages[i].src = imageName;
}


/*
 * Show/Hide without errors, whether they exist or not
 */
function show(el) {
	if(typeof el == "string") el = document.getElementById(el);
	if(el != null) el.style.display = "";
}
function hide(el) {
	if(typeof el == "string") el = document.getElementById(el);
	if(el != null) el.style.display = "none";
}



////// PROFILING

function getNow() {
	var d = new Date();
	return d.getSeconds() * 1000 + d.getMilliseconds();
}

function showProfile(t) {
	var totalTime = t[t.length-1] - t[0];
	var i;
	var result = "";
	var gap, percent;
	for(i=1;i<t.length;i++) {
		gap = (t[i]-t[i-1]);
		percent = gap / totalTime * 100
		result += (i-1) + "-" + i + ": " + gap + " (" + percent + "%)\n";
	}
	result += "Total Time: " + totalTime;
	alert(result);
}

/*
* Show/Hide without errors, whether they exist or not
*/
function show(el) {
	if(typeof el == "string") el = document.getElementById(el);
	if(el != null) el.style.display = "";
}
function hide(el) {
	if(typeof el == "string") el = document.getElementById(el);
	if(el != null) el.style.display = "none";
}
 