var advSearchIdent = "advSearchForm";
var searchRegionWidth = 360; // pixels
var seg = 10; // number of pixels in each fold-segment

function buildAdvancedSearch(dest) {
	try {
		var theRegion = document.createElement("form");
		theRegion.id = advSearchIdent;
		theRegion.onsubmit = function() { return checkBasicSearch(theRegion); };
		theRegion.setAttribute("method", "get");
		theRegion.setAttribute("action", dest);
		
		var mainTable = document.createElement("table");
		mainTable.className = "advFields";
		mainTable.id = "advMainTerms";
//		buildLabeledRow(mainTable, buildTextField("basic"), "Basic Search");
		buildLabeledRow(mainTable, buildTextField("excluded"), "Excluded Words");
		buildLabeledRow(mainTable, buildTextField("phrase"), "Containing Phrase");
		buildLabeledRow(mainTable, buildTextField("partial"), "Partial Words");
		buildLabeledRow(mainTable, buildTextField("required"), "Required Words");

		theRegion.appendChild(mainTable);

		var theIdentifier = buildField("adv", "hidden");
		theIdentifier.setAttribute("value", "1");
				
		theRegion.appendChild(theIdentifier);

		var theRemoveButton = document.createElement("a");
		theRemoveButton.id = "removeButton";
		theRemoveButton.setAttribute("href", "javascript:removeAdvancedSearch();");
		theRemoveButton.appendChild(document.createTextNode("close"));
		theRegion.appendChild(theRemoveButton);

		return theRegion;
	} catch (m) {
		alert("Caught exception in buildAdvancedSearch: " + m.toString());
	}
	return null;
}


function displayAdvancedSearch(dest) {
	try {
		if (!document.getElementById(advSearchIdent)) {
			// find container region
			var theContainerRegion = document.documentElement; // could be some other child, by finding it here
			var theSearchContainer = document.createElement("div");
			theSearchContainer.id = "advSearchContain";
			var theSearchRegion = buildAdvancedSearch(dest);
			theSearchRegion.style.width = searchRegionWidth + "px";
			// hide theSearchRegion (important to use visibility:hidden, not display:none)
			theSearchRegion.style.visibility = "hidden";
				// following is just for testing...
				// we actually want to calculate top and left based on position of search box
	// 		theSearchContainer.style.top = "10px";
	// 		theSearchContainer.style.left = "50px";
			theSearchContainer.appendChild(theSearchRegion);
			positionBySearchForm(theSearchContainer);
			theContainerRegion.appendChild(theSearchContainer);
	//		alert("region height: " + theSearchRegion.scrollHeight);
			theSearchRegion.style.top = (-1*theSearchRegion.scrollHeight) + "px";
			unfold(theSearchRegion);
			theSearchRegion.style.display = "block"; // can be un-hidden once positioned for unfold()
		} else {
			removeAdvancedSearch();
//			alert("DEBUG: Advanced search controls should already be visible");
		}
	} catch (m) {
		alert("Caught exception in displayAdvancedSearch: " + m.toString());
	}
}

	/// This is functional, but can probably be cleaned up a bit.
	/// We may want a window.onresize function to fix position in case
	/// the search box moves when window is resized and advanced search is
	/// visible.
	/// Assume that negative top-position values are properly handled as "hidden" (this could be a div overflow setting)
function unfold(node) { // is there a universal way to get the bounds of an object (eg, scrollHeight)?
//	var seg = 10; // number of pixels to reveal at each step
	var height = node.scrollHeight; // might want clientHeight or offsetHeight instead (non-major browser support?)
	var steps = height/seg;
	var s = 0; // number of steps so far
	node.style.visibility = "visible";
	var initTop = -1*height;
	var theEvent = setInterval(
		function () {
			++s; // turns out, this can be defined inside the lambda form instead of in the closure
			if (s < steps) {
				// unfold node by seg px
				node.style.top = (initTop + seg*s)+"px";
			} else {
					// done, so stop interval
				clearInterval(theEvent);
			}
		},
		20
	);
}

function fold(node) { // is there a universal way to get the bounds of an object (eg, scrollHeight)?
//	var seg = 10; // number of pixels to reveal at each step
	var height = node.scrollHeight; // might want clientHeight or offsetHeight instead (non-major browser support?)
	var steps = height/seg;
	var s = 0; // number of steps so far
//	node.style.visibility = "visible";
	var initTop = 0;
	var theEvent = setInterval(
		function () {
			++s;
			if (s < steps) {
				// unfold node by seg px
				node.style.top = (initTop - seg*s)+"px";
			} else {
					// done, so stop interval
				clearInterval(theEvent);
				var theSearchContainer = node.parentNode;
				theSearchContainer.removeChild(node); // we may want to hide, instead
			}
		},
		20
	);
}


function positionBySearchForm(targ) {
	try {
		var theSearchForm = document.getElementById("sbox"); // #sbox is search form from default-page-context
		var theTotalTop = totalOffsetTop(theSearchForm);
		var theTotalLeft = totalOffsetLeft(theSearchForm);
//		alert("Would position to " + theTotalTop + ", " + theTotalLeft);
			// just setting top and left to totalTop and totalLeft attaches at the top corner--
			// obviously need to get the width and height of the search form, 
			// and the width of the target, and center and bump down accordingly
				// (16 is the padding, which doesn't count into searchRegionWidth, 4 is the shadow width on #sbox -- yuck!)
		theTotalLeft += Math.round((theSearchForm.offsetWidth - 16 - 4 - searchRegionWidth) / 2);
		targ.style.top = theSearchForm.offsetHeight + theTotalTop + "px";
		targ.style.left = theTotalLeft + "px";
		
/*
			/// handle alignment
		var theSearchFieldLeft = totalOffsetLeft(document.getElementById("searchField"));
		var theTestFloat = document.createElement("span");
		theTestFloat.id = "testFloat";
		theTestFloat.appendChild(document.createTextNode("(floating) test text"));
		targ.appendChild(theTestFloat);
		theTestFloat.style.position = "relative";
		theTestFloat.style.display = "block";
		theTestFloat.style.left = (theSearchFieldLeft - theTotalLeft) + "px";
		
			// get table, get table left offset, get first text field left offset,
			// push table over to align properly
		var theTargFields = findChildWithId(targ, "advMainTerms", true);
		var rowExemplar  = theTargFields.rows.item(0);
		var firstField = rowExemplar.cells.item(1).firstChild;
		var fieldOffset = totalOffsetLeft(firstField);
		var tableOffset = theSearchFieldLeft - fieldOffset;
		alert("Bumping table by: " + tableOffset + " ( " + theSearchFieldLeft + " - " + fieldOffset + " )");
		theTargFields.style.paddingLeft = tableOffset + "px";
*/		
	} catch (m) {
		// handle positioning when we can't get search form, or can't get numerical position data
		alert("Caught exception in positionBySearchForm: " + m.toString());
	}
}

/*
function findChildWithId(par, ident) {
	try {
		for (var curr = par.firstChild; curr != null; curr = curr.nextSibling) {
			if (curr.id && curr.id == ident) {
				return curr;
			}
		}
	} catch (m) {
		alert("caught exception in findChildWithId: " + m.toString());
	}
	return null;
}
*/


function totalOffsetTop(nd) {
	return totalOffset(nd, "offsetTop");
}

function totalOffsetLeft(nd) {
 	return totalOffset(nd, "offsetLeft");
}

function totalOffset(nd, prop) {
	return (nd != null) ? nd[prop] + totalOffset(nd.offsetParent, prop) : 0;
}

function removeAdvancedSearch() {
	try {
		var theSearchForm = document.getElementById(advSearchIdent);
		if (theSearchForm) {
			fold(theSearchForm);
// 			var theSearchContainer = theSearchForm.parentNode;
// 			theSearchContainer.removeChild(theSearchForm); // we may want to hide, instead
		}
	} catch (m) {}
}

function checkBasicSearch(advForm) {
		// things to do: 
		// * check for basic search value in main form
		// * make sure 'excluded' is not the only field (meaningless)
	try {
		var isClear = true;
			/// check basic search field
		var theBasicSearchField = document.getElementById("searchField");
		if (theBasicSearchField && theBasicSearchField.value != "") {
			var hiddenBasic = buildField("keywords", "hidden");
			hiddenBasic.setAttribute("value", theBasicSearchField.value);
			advForm.appendChild(hiddenBasic);
		}
			/// check excluded field
		if (advForm.elements && advForm.elements.length > 0) {
			var notEmpty = /\S+/;
			var formIsEmpty = true;
			var hasNonExcludedInput = false;
			for (var i=0; !hasNonExcludedInput && i<advForm.elements.length; i++) {
				var curr = advForm.elements[i];
				var currType = curr.getAttribute("type");
				var currNodeName = curr.nodeName.toLowerCase();
				if ((currNodeName == "input" && currType != "submit" && currType != "button") || currNodeName == "textarea") {
					if (currType == "hidden") {
						if (curr.getAttribute("name") == "keywords" && notEmpty.test(curr.value)) {
							hasNonExcludedInput = true;
						}
					} else {
						if (notEmpty.test(curr.value)) {
							if (curr.getAttribute("name") != "excluded") {
								hasNonExcludedInput = true;
							} else {
								formIsEmpty = false;
							}
						}
					}
				}
			}
			if (!hasNonExcludedInput) {
				isClear = false;
				if (formIsEmpty) {
					alert("No values to search with");
				} else {
					alert("Cannot exclude values from empty search");
				}
			}
		}
		return isClear;
	} catch (m) { 
		alert("Could not determine basic search value: " + m.toString());
	}
	return false;
}

function includeAdvanced() {
	var advancedForm = document.getElementById(advSearchIdent);
	if (advancedForm != null) {
		if (checkBasicSearch(advancedForm)) { // we have to do this manually, because the form onsubmit event isn't triggered by theFormInstance.submit() (at least, not in Firefox)
			advancedForm.submit(); // submit this form instead (does this replace original submission?)
		}
		return false;
	}
	return true;
	// do we want to return true/false here to control (original) submission?
}
