
// Implements the "eval" style rule
// Must be part of the onLoad event
function preEval()
{
	var evalElements = document.getElementsByClassName('eval');
	for (var i = 0; i < evalElements.length; i++)
	{
		var el = evalElements[i];
		if (el.className = "eval") el.innerHTML = eval(el.innerHTML);
	}
}


// Used to reveal and hide test data 
function showContent(elmt, btn)
{
	var tmp = cascadedStyle(document.getElementById(elmt), "display");
     	if (tmp == "none") 
     	{
     		tmp = "block"; 
     		btn.value = "hide " + btn.value.slice(5);
     	}
     	else
     	{
     		tmp = "none";
     		btn.value = "show " + btn.value.slice(5);
     	}
     	document.getElementById(elmt).style.display = tmp
}

//-----------------------------------------------------------------------------------------//

// The statement showSoln(btn) hows or hides the soln-class element corresponding to the 
// supplied btn-class element. See findSoln for details of this correspondence.
// If the soln is being displayed, the btn's contents are set to an up-arrow and the 
// whole btn is grayed.  If it is being hidden, the btn's contents are set to a down-arrow.
function showSoln(btn)
{
	var elmt = findSoln(btn);  // get the element to be displayed
	if (elmt == null)
	{
		alert("Can't find expansion element.");
		return;
	};
	var display = cascadedStyle(elmt, "display");
//	var color = cascadedStyle(btn, "color");
	if (display == "none") 
	{
		display = "block"; 
		btn.innerHTML = "⇑"
//		btn.savedColor = color;
		btn.style.color = "#999999";
		btn.style.borderStyle = "solid";
	}
	else
	{
		display = "none";
		btn.innerHTML = "⇓"
//		btn.style.color = btn.savedColor; // "#0000CC";
		btn.style.borderStyle = "outset";
	}
	elmt.style.display = display

	// On input, btn is the nth btn-class node of its parent element;
	// nodes other than btn-class nodes may be interspersed.
	// On exit, findSoln(btn) is the nth soln-class sibling after the parent element; 
	// non soln-class elements may be interspersed.
	function findSoln(btn)
	{
		var n = buttonCount(btn);
		var el = btn.parentNode;  // e.g. containing paragraph
		for (var i = 1; i <= n; i++) el = getNextSoln(el);
		return el;
	}
	
	// number of previous btn-class siblings plus one
	function buttonCount(btn) 
	{
		var i = 1;
		while (true)
		{
			btn = btn.previousSibling;
			if (btn == null) return i; // no more button siblings
			if (btn.nodeType == 1)
				if (typeof(btn.className) != "undefined")
					 if (btn.className == "btn") i++;
		}
	}
	
	// gets the next soln-class node
	function getNextSoln(el)
	{
		while(true) 
		{
			el = el.nextSibling;
			if (el == null) break;
			if (el.nodeType == 1)
				if (typeof(el.className) != "undefined")
				{
					var clss = el.className;
					var classes = clss.split(/\s+/);
	  				for (var i = 0; i < classes.length; ++i) 
					{
						if (classes[i] == "soln") return el;
    				}
				}
		}
	}
	
}




// The following function operates on a list of child elements.
// Interspersing non-element nodes (including text nodes) are ignored.
// The disploay of each child node is toggled.
// The first node is initially assumed to have a blue border, inviting user interaction
// When the first node is undisplayed, its border is removed, and if it is redisplayed,
// then the border is restored.
// The function stops event propagation, allowing nested lists of children to be toggled.  

function toggleChildren(ev)
{
	var el = ev.currentTarget;
	var elParent= el;
	el = el.childNodes[0];
	var firstElement = true;
	while (true)					// could be better done with a for loop!
	{
		if (el == null) break;      // we've toggled all of the child nodes
		if (el.nodeType == 1)   	// skip over text nodes and garbage
		{
			if (el.style.display=="none") 
			{
				el.style.display = ""; 
				if (firstElement) 
				{
					elParent.style.border = "1px solid";
					elParent.style.borderColor = elParent.borderColor;
					elParent.style.color = elParent.color; // saved from before
				}
			}
			else 
			{
				el.style.display = "none";
				if (firstElement) 
				{
					elParent.style.borderWidth = "0px";
					elParent.color = cascadedStyle(elParent, "color"); // alert(elParent.color);
					elParent.borderColor = cascadedStyle(elParent, "border-color");//  alert(elParent.borderColor);
					elParent.style.color = "black";
				}
			};
			firstElement = false;
		};
		el = el.nextSibling;
	};
	ev.stopPropagation()
}

// degugging code
function displayNode(el)
{
	var tmp = "";
	var display = "";
	if (el.innerHTML) tmp = el.innerHTML;
	if (el.nodeType == 1 && el.style)
		display =  " display: " + el.style.display
	else
		display = "";
	alert(el + ": nodeType = " + el.nodeType +  display + " +"+ tmp +"+");
}


// //////////////////////////////////////////////////////////////////////////////////
// Browser-dependent support functions

function cascadedStyle(elem, attr)
// This function is a essentially a decamelized variant of MSIE's currentStyle property. 
// This function tests for order of precedence per MSIE's currentStyle definition, 
// which may conflict with user direction due to ignorance or carelessness.
// The current compromise is to honor user direction but complain about it.
{
	if (elem.currentStyle)  // MSIE
	{
		var rtnAttr = elem.currentStyle[camelize(attr)];
		var rtnProp = elem.getAttribute(attr)
	}
	else
	{	
		var calcStyle = document.defaultView.getComputedStyle(elem, null);
		var rtnAttr = calcStyle.getPropertyValue(attr)
		var rtnProp = elem.getAttribute(attr)
	};
	if (rtnAttr && rtnProp && (rtnAttr != rtnProp))
	{	
		var msg = "Error.  Replace property '" + attr + "=\"" + rtnProp + "\" '  with inline style declaration";
		if (elem.className)
			msg = "Class '" + elem.className + "' conflicts with property '" + attr + "=\"" + rtnProp + "\" '";
		nEvent.errorFlag = true; 
		window.status = msg;
	};
	if (rtnProp) return rtnProp; // violates standards but not without complaint
	if (rtnAttr) return rtnAttr;
	return "";

	function camelize(prop)
	{
		var tmp = prop;
		j = tmp.search(/-/) + 1;
		if (j > 0)
		{
			tmp = tmp.slice(0, j-1) + tmp.slice(j,j+1).toUpperCase() + tmp.slice(j+1)
		};
		return tmp
	}  // end camalize
	
} // end cascadedStyle
