
//var os = document.getElementById('outspace');

/*

<form method="POST" action="<?=$_SERVER['REQUEST_URI']?>"><table>
<form method="POST" action="" onSubmit="return false"><table>
	<tr><th colspan="2"><textarea id="outspace" rows=10 cols=50></textarea></th></tr>

<script language="javascript1.2" src="ajax_searchlist.js"></script>

	<tr><th>Search For:</th><td><input type="text" size="30"
	 name="search" value="" id="searchlistinput" /></td></tr>
	 name="search" value="<?=htmlentities($_POST['search'])?>"
	 id="searchlistinput" /></td></tr>
	<script> sli1 = new SimilarsSearchBox('searchlistinput','/searchlist/groups/','member_id'); </script>
	<tr><td colspan="2"><input type="submit" name="searchgroups" value="Search Groups"></td></tr>

	<input type="text" name="member_id" value="" />
</table></form>

*/



// shortcut func for show/hide the listbox
function shlistbox (f,yn) { f.listbox.style.display = (yn ? 'block' : 'none'); }

// shortcut func for swapping text input is safe/unsafe
function sutextinput (f,yn) { f.box.className = (yn ?
 f.box.className.replace(/\bsearchlisttext\b/, ' searchlistchanged')
  : f.box.className.replace(/\bsearchlistchanged\b/, ' searchlisttext')); }



// func for clearing the similars list
function clearSimilars (f) { shlistbox(f,false); f.idx = -1;
 while (f.list.hasChildNodes()) { f.list.removeChild(f.list.lastChild); } }


// do the actual search list box drawing after we have the list
var mofuncs = [];  // reuse the functions created for each listindex, rather than remaking (memory handling...) on each draw
function drawSimilars (f, similarslist)
{
	// have to reset each time we redraw the list
	//  and clean out any existing list items
	clearSimilars(f);

	// build the html for each similar
	for (var i = 0; i < similarslist.length; i++)
	{
		// this is the line item for this term
		//  but we need to make sure it's not disabled
		var sLI = document.createElement('li');
		sLI.listDisabled = (similarslist[i].count > 0 ? false : true);

		// if this line item is disabled, it lacks mousing features
		if (!sLI.listDisabled)
		{
			// create a mousing version of the up/down arrow key highlighting
			if (!mofuncs[i]) { mofuncs[i] = new Function('f', 'f.idx = '+i); }
			sLI.listIndex = i; sLI.onmouseover = function()
			 { highlightSimilar(f, mofuncs[this.listIndex]); };

			// create a link to use the mouse directly to these results
			var sLIa = document.createElement('a');
			sLIa.innerHTML = similarslist[i].term;
			// note that the search box goes somewhere, the find box fills a hidden input
			//   FIXME FIX ME -- I have *no* idea but for some reason, the mouse clicks won't go through!
			if (!f.hIn) { sLIa.href = similarslist[i].url; } else
			{
				// interestingly, onclick sometimes fails because the list hides before the up part of the click event happens
				sLIa.href = '#'; sLIa.onmousedown = function ()
				{
					var c = f.list.childNodes[this.parentNode.listIndex].lastChild;
					f.hIn.value = c.count; f.box.value = c.innerHTML; sutextinput(f,false);
					// we can call an additional function on the returned data, to take additional actions, when desired
					if (f.setfunc) { f.setfunc(c.count); }
				}; sLIa.onclick = returnfalse;  // we still need click to not redirect the page, just in case
			}
			sLIa.count = similarslist[i].count;
			sLI.appendChild(sLIa);
		}

		// if disabled, the text goes directly into the line item
		else { sLI.innerHTML = similarslist[i].term; }

		// add this line item to the list
		f.list.appendChild(sLI);
	}

	// and finally display it -- and mark it as not expecting changes
	shlistbox(f,true); f.changes = false;
}


// send this value to the server to get the similars list -- but only if we expect the results have changed
//  we need the two funcs because as an event call, the one arg works fine,
//  but calling it directly, e.g. from checkKeys, this == the window...
function showSimilars (e) { this.select(); showSimilars2(e, this.similarslistobject); }
function showSimilars2 (e,f)// + '/' + vCode
 { if (f.changes) { sendAJAXrequest(f.ajaxpage, function (data) { drawSimilars(f, data); }, 't=' + encodeURIComponent(f.box.value)); } else { shlistbox(f,true); } }



// hide/remove the similars list
function hideSimilars (e)
{
	// shortcut link back to avoid event closures
	var f = this.similarslistobject;

	// we have to delay for a split second,
	//  in case this comes from a click on one of the links
	// (the click will only get looked for after the blur happens
	//  and without the box there, the click never happens!)
	// HOWEVER, this creates a new problem: obj ceases to exist
	//  if the page changes, so we need the try/catch
	setTimeout(function() { try { if (f.list) { if (f.changes) { clearSimilars(f); } else { shlistbox(f,false); } } } catch (r) {} }, 100);
}


// turn off current highlighting, highlight new item
function highlightSimilar (f, edgefunc)
{
	// unhighlight the old item
	if (f.idx >= 0) { f.list.childNodes[f.idx].className = ''; }

	// try the next/prev item, but if it's disabled,
	//  go one more until you find an undisabled one in the list
	// NOTE: if the edgefunc comes after orig assignment,
	//  you'll crash the browser when nothing is selected yet (origIndex == -1)
	edgefunc(f); origIndex = f.idx;
	while (f.list.childNodes[f.idx].listDisabled)
	 { edgefunc(f); if (origIndex == f.idx) { break; } }

	// make sure we found an undisabled item in the list
	if (!f.list.childNodes[f.idx].listDisabled)
	{
		f.list.childNodes[f.idx].className = 'searchlisthighlight';
		f.box.value = f.list.childNodes[f.idx].lastChild.innerHTML;
		if (f.hIn) { f.hIn.value = f.list.childNodes[f.idx].lastChild.count; }
		sutextinput(f,false);  // we found a valid option and selected it
		if (f.setfunc) { f.setfunc(f.list.childNodes[f.idx].lastChild.count); }
	}

	// these arrow keystrokes should be ignored
	return false;
}

// highlight previous item
function prevSimilar (f) { if (--f.idx < 0) { f.idx = f.list.childNodes.length-1; } }

// highlight next item
function nextSimilar (f) { if (++f.idx >= f.list.childNodes.length) { f.idx = 0; } }


// take action on keystrokes in searchbox
function preventDefault (e) { if (e.preventDefault()) { e.preventDefault(); } return false; }
function checkSearchKeys (e)
{
	// shortcut link back to avoid event closures
	var f = this.similarslistobject;

	// generic IE compatibility
	if (!e) { e = window.event; }

	// up/down step through similars
	if (e.keyCode == 38) { return highlightSimilar(f,prevSimilar); }  // up
	if (e.keyCode == 40) { return highlightSimilar(f,nextSimilar); }  // down

	// tabbing through the form, we want to skip the dropdowns
	//  ~ http://stackoverflow.com/questions/3362/capturing-tab-key-in-text-box
//	if (e.keyCode == 9) { var n = f.box; while (n = n.nextSibling) { if ((n.tagName == 'input' && n.type != 'hidden') || (n.tagName == 'select')) { f.box.blur(); n.focus(); return preventDefault(e); } } }

	// all other keys pressed BUT ENTER should be processed
	//  note the need to call the complete showSimilars func, with f,
	//  since it won't be an event attached call, and thus "this" will be the window, not the input box
	if (e.keyCode != 13) { f.changes = true; sutextinput(f,true); showSimilars2(e,f); }

	// enter tells us to load that option, if an option has been selected ... for search box
	//  -- find box is diff, we will fill hidden input w/ selected option's id (from count, stored in href as anchor!),
	//   or if only one option in list, even when nothing is selected, use that one option's id -- and fill the search text input with the term!
	else { if (!f.hIn && f.idx >= 0) { window.location = f.list.childNodes[f.idx].lastChild.href; return preventDefault(e); }
	 else if (f.hIn && f.list.lastChild) { f.box.blur(); if (f.idx >= 0) { f.hIn.value = f.list.childNodes[f.idx].lastChild.count; }
	  else { var c = f.list.childNodes[0].lastChild; f.hIn.value = c.count; f.box.value = c.innerHTML; } return preventDefault(e); } }

	// normal keystrokes should definitely be allowed
	return true;
}







// closure making func -- easier to pass dynamic html objects to event handlers
//  might need this:  http://laurens.vd.oever.nl/weblog/items2005/closures/
//  use like so: 	this.box.onblur = eventClosure(hideSimilars, this);
//function eventClosure (func, obj) { return function (e) { func(e, obj); }; }



function SimilarsSearchBox (idName, ajaxpage, hIn, isvalid, setfunc)
{
	// get the search input box
	this.box = document.getElementById(idName);

	// remember the page to submit this input to
	this.ajaxpage = ajaxpage;

	// is this a search box (going to a diff page) -- hIn not submitted (null/undefined)
	//  or a find box (filling a hidden input field) -- hIn is string to id of hidden field
	this.hIn = (typeof(hIn) != 'undefined' ? hIn : false);
	if (!this.hIn) { sutextinput = returnfalse; }  // no highlighting safe/unsafe, it's just a search helper
	else { this.box.className += ' searchlisttext'; this.hIn = (typeof(this.hIn) != 'string'
	 ? this.hIn : (this.box.form[this.hIn] ? this.box.form[this.hIn] : document.getElementById(this.hIn))); }

	// we might want to take extra action when selecting from the list
	//  e.g. display additional info about the selected option somewhere else on the screen
	this.setfunc = (typeof(setfunc) != 'undefined' ? setfunc : false);

	// link back to this object for easy referencing
	//  this avoids the need for event function closures
	this.box.similarslistobject = this;

	// create the actual space where the similars get shown
	this.listbox = document.createElement('div');
	this.listbox.className = 'searchlistbox';

	// the list where all the suggestions go
	this.list = document.createElement('ul');
	this.list.className = 'nonlist';
	shlistbox(this,false); this.idx = -1;  // initialize drop list to merely hidden, with nothing selected yet
	this.changes = true;  // when true, we need to calculate the dropdown for currently entered text

	// if it is a non-valid (empty) field to start, it is unsafe and needs to be highlighted as such
	if (typeof(isvalid) == 'undefined' || !isvalid) { sutextinput(this,true); }

	// now put the list and listbox on to the page
	this.listbox.appendChild(this.list);
	this.box.parentNode.appendChild(this.listbox);

	// assign all the event handlers
	this.box.onfocus = showSimilars;
	this.box.onblur = hideSimilars;
	// it has to be keyup, not keydown --
	//  keydown somehow breaks things when backspace (at least) is used
	this.box.onkeyup = checkSearchKeys;
}

