function suggestRespond(fn) { // contain should be id of current content container
	try {
		if (req.readyState == 4 && req.status == 200) { // readyState == 4 -> complete; status == 200 -> good response
//			alert("back now");
			var errs = req.responseXML.getElementsByTagName("err");
				// if we can find a cursor (anything with id #busyCursor), toggle visibility
			isProcessing = false;
			removeCursor();
			if (errs.length > 0) { // there were errors in processing
				removeSimilarWaiting(); // otherwise this persists when there are errors
				showErrors(errs);
			} else {
				var newContents = fn.apply(); // assume this returns DocumentFragment that can be inserted into new div#details (NB: apply() with no 'this' argument uses global object as target, which is what we want here)
				if (contain) { // only swap containers when given an old one
					var theNewContainer = document.createElement("div");
					theNewContainer.appendChild(newContents);
					var theOrigContainer = (isElement(contain)) ? contain : document.getElementById(contain);
					var theDetailContainer = theOrigContainer.parentNode;
					theDetailContainer.replaceChild(theNewContainer, theOrigContainer);
					if (!isElement(contain)) {
						theNewContainer.setAttribute("id", contain); // replace id, because we've removed original node with this id
					}
				}
			}
		}
	} catch (e) {
		handleError(e);
		removeCursor();
		isProcessing = false;
	}
}

function searchSuggest(pid) {
	var theTextField = document.getElementById("suggsearch");
	if (theTextField) {
		requestChange("/suggest.php", "mode=search&prod="+pid+"&search="+encodeURIComponent(theTextField.value), function() {suggestRespond(respondSuggestSearch);});
		placeSimilarWaiting();
	} else {
		alert("Could not get contents of comment field");
	}
	
}

function makeSuggest(pid, sid, idx) {
	requestChange("/suggest.php", "mode=add&prod="+pid+"&sugg="+sid, function () {suggestRespond(respondSuggestAdd);});
	var contain = document.getElementById("suggresults");
	if (contain) {
		contain.deleteRow(idx);
	}
}

function bumpSuggest(sid, pid, dir, directORrecipricol) {
    //alert(directORrecipricol);
	requestChange("/suggest.php", "mode=bump&prod="+pid+"&sugg="+sid+"&dir="+dir+"&type="+directORrecipricol, function () {suggestRespond(respondSuggestBump);});
}

function respondSuggestSearch() {
	/// build list items, insert into #suggresults
	removeSimilarWaiting();
	var theListContainer = document.getElementById("suggresults");
	if (theListContainer) {
		/// if existing results, clear out list
		if (theListContainer.tBodies.length > 0) {
			for (var b=theListContainer.tBodies.length-1; b>=0; b--) {
				var theBody = theListContainer.tBodies[b];
				if (theBody.rows.length > 0) {
					for (var i=theBody.rows.length-1; i>=0; i--) {
						theBody.deleteRow(i);
					}
				}
			}
		}
		var theList = req.responseXML.getElementsByTagName("product");
		if (theList && theList.length > 0) {
			var searchMain = req.responseXML.getElementsByTagName("search")[0];
			var prodid = searchMain.getAttribute("for");
			var theNewBody = document.createElement("tbody");
			theListContainer.appendChild(theNewBody);
			for (var i=0; i<theList.length; i++) {
// 				var theListItem = document.createElement("option");
				var theListItem = theNewBody.insertRow(i); // -1
// 				theListItem.setAttribute("value", theList[i].getAttribute("pid"));
// 				theListItem.setAttribute("title", theList[i].getAttribute("descr"));
				var sid = theList[i].getAttribute("pid");
				var theItemTitle = theListItem.insertCell(-1);
					/// we can't simply create the closure in this loop because  of js rules for closure references, 
					/// but constructing the onclick string this way coerces the values properly
				theItemTitle.setAttribute("onclick", "makeSuggest("+prodid+", "+sid+", this.parentNode.rowIndex)"); // hard-coding the row-index at construct-time makes deletions after the first break: +theListItem.rowIndex+
				theItemTitle.appendChild(document.createTextNode(theList[i].firstChild.nodeValue));
				var licenseString = (theList[i].hasAttribute("lic")) ? " ["+theList[i].getAttribute("lic")+"]" : "";
				var theItemDescr = theListItem.insertCell(-1);
				theItemDescr.className = "descr";
				theItemDescr.appendChild(document.createTextNode(theList[i].getAttribute("descr")  + licenseString));
//				console.log("add %o", theListItem);
//				theListContainer.appendChild(theListItem);
			}
		}
		theListContainer.style.display = "block";		
	}
}


function respondSuggestBump() {
	/// update count for bumped product
	var theResponse = req.responseXML.getElementsByTagName("similar")[0];
	if (theResponse) {
		var theVoteTotal = document.getElementById("suggVote_"+theResponse.getAttribute("suggest"));
		if (theVoteTotal) {
			theVoteTotal.replaceChild(document.createTextNode(theResponse.getAttribute("votes")), theVoteTotal.firstChild);
				///  disable voting control
// 			var theVoteTriggerUp = document.getElementById("suggBumpUp_"+theResponse.getAttribute("suggest"));
// 			if (theVoteTriggerUp) {
// 				theVoteTriggerUp.removeAttribute("onclick");
// 			}
			var bump = theResponse.getAttribute("bump");
			if (bump == "up") {
				// disable controls, mark up
				markBumpUp(document.getElementById("suggBumpUp_"+theResponse.getAttribute("suggest")));
				disableBumpCtl(document.getElementById("suggBumpDown_"+theResponse.getAttribute("suggest")));
			} else if (bump == "down") {
				// disable controls, mark down
				disableBumpCtl(document.getElementById("suggBumpUp_"+theResponse.getAttribute("suggest")));
				markBumpDown(document.getElementById("suggBumpDown_"+theResponse.getAttribute("suggest")));
			} else {
				disableBumpCtl(document.getElementById("suggBumpUp_"+theResponse.getAttribute("suggest")));
				disableBumpCtl(document.getElementById("suggBumpDown_"+theResponse.getAttribute("suggest")));
			}
		}
	}
}

function respondSuggestAdd() {
	/// add to bottom of #sugglist (we don't want to do this now)
	var theResponse = req.responseXML.getElementsByTagName("similar")[0];
	var existingVote = document.getElementById("suggVote_"+theResponse.getAttribute("suggest"));
	if (existingVote) {
		/// already exists, so don't insert now row
		existingVote.replaceChild(document.createTextNode(theResponse.getAttribute("votes")), existingVote.firstChild);
		// flash row where vote changed
		var theFader = new Fader(existingVote.parentNode);
		theFader.setEndColor(233,242,255); // match background
		theFader.calcSteps();
		theFader.fade();
		
	} else {
		var theListContainer = document.getElementById("sugglist");
		var theNewItem = document.createElement("li");
		var theNewTitle = document.createElement("a");
		theNewTitle.setAttribute("href", theResponse.getAttribute("link"));
		theNewTitle.appendChild(document.createTextNode(theResponse.firstChild.nodeValue));
		theNewTitle.id = "suggitem_"+theResponse.getAttribute("suggest");
		var theBumpUpImage = createBumpImage("/images/bumpUp.png", "agree");
		var theBumpDownImage = createBumpImage("/images/bumpDown.png", "disagree");		
		var theNewBumpUp = document.createElement("span");
		theNewBumpUp.id = "suggBumpUp_"+theResponse.getAttribute("suggest");
//		theNewBumpUp.onclick = function() { bumpSuggest(theResponse.getAttribute("suggest"), theResponse.getAttribute("orig"), "up"); };
		theNewBumpUp.className = "bumpSugg";
		theNewBumpUp.appendChild(theBumpUpImage);
		var theNewBumpDown = document.createElement("span");
		theNewBumpDown.id = "suggBumpDown_"+theResponse.getAttribute("suggest");
//		theNewBumpDown.onclick = function() { bumpSuggest(theResponse.getAttribute("suggest"), theResponse.getAttribute("orig"), "down"); };
		theNewBumpDown.className = "bumpSugg";
		theNewBumpDown.appendChild(theBumpDownImage);
		var theNewVotes = document.createElement("span");
		theNewVotes.id = "suggVote_"+theResponse.getAttribute("suggest");
		theNewVotes.appendChild(document.createTextNode(theResponse.getAttribute("votes")));

		theNewItem.appendChild(theNewTitle);
		theNewItem.appendChild(document.createTextNode(" (votes: "));
		theNewItem.appendChild(theNewVotes);
		theNewItem.appendChild(document.createTextNode(") "));
		theNewItem.appendChild(theNewBumpUp);
		theNewItem.appendChild(theNewBumpDown);
		theListContainer.appendChild(theNewItem); 
	}
}

function disableBumpCtl(trig) {
	if (trig) {
		trig.removeAttribute("onclick");
			/// we don't need to do this if action isn't originally included via respondSuggestAdd
// 		if (trig.onclick) {
// 			trig.onclick = null;
// 		}
	}
}

function markBumpCtl(trig, src) {
	disableBumpCtl(trig);
	if (trig.hasChildNodes()) {
		trig.firstChild.setAttribute("src", src);
		trig.firstChild.className = "selected";
	}
}

function markBumpUp(trig) {
	markBumpCtl(trig, "/images/bumpUp_off.png");
}

function markBumpDown(trig) {
	markBumpCtl(trig, "/images/bumpDown_off.png");
}

function createBumpImage(src, alt) {
	var theImage = document.createElement("img");
	theImage.setAttribute("src", src);
	if (alt) {
		theImage.setAttribute("alt", alt);
	}
	return theImage;
}

function placeSimilarWaiting() {
	var theSuggestResults = document.getElementById("suggresults");
	var theWaiting = document.createElement("div");
	theWaiting.id = "suggestWaiting";
	var theSpinner = document.createElement("img");
	theSpinner.className = "spin";
	theSpinner.setAttribute("src", "/watch/bigSpinner.gif");
	theWaiting.appendChild(document.createTextNode("Searching..."));
	theWaiting.appendChild(theSpinner);
	var theParent = theSuggestResults.parentNode;
	theParent.insertBefore(theWaiting, theSuggestResults);
}

function removeSimilarWaiting() {
	var theWaiting = document.getElementById("suggestWaiting");
	try {
		if (theWaiting) {
			var theParent = theWaiting.parentNode;
			theParent.removeChild(theWaiting);
		}
	} catch (m) {}
}
