/* Contents:
 * -FocusSearch
 * -CheckBoxList
 * -Enumeration
 * -Hidden
 * -PickOne
 * -QBE (Query By Example)
 * -TextSuggest
 * -QBEHelper
 */

function FocusSearch(crit, critdiv, args) {
	this.crit = new Array();
	this.anchors = new Object();
	this.critFields = new Object();
	this.anchors.critdiv = critdiv;
	this.criteria = "";
	this.resultsfield = "name";
	this.previewfield = "desc";
	this.dependency = new Object();
	this.depSets = new Object();
	this.depList = new Object();
	this.targetFields = new Object();
	if(args) {
		var elem = '';
		for(elem in args) {
			if(elem.indexOf("div") >= 0)
				this.anchors[elem] = args[elem];
			else
				this[elem] = args[elem];
		}
		elem = null;
	}
	
	if((!this.initurivalue) && (document.URL.indexOf('?') >= 0))
		this.initurivalue = document.URL.substring(document.URL.indexOf('?')+1);
		
	if (this.initurivalue) {
		this.initVals = new Object();
		var inputArr = this.initurivalue.split("&");
		for(var i=0;i<inputArr.length;i++) {
			var fields = inputArr[i].split("=");
			var fieldName = decodeURIComponent(fields[0]);
			var fieldValue = decodeURIComponent(fields[1]);
			this.initVals[fieldName] = fieldValue;
		}
		inputArr = null;
		fields = null;
		fieldName = null;
		fieldValue = null;
	}
	
	for(var i=0; i < crit.length; i++) {
		this.crit[this.crit.length] = crit[i];
		if(!crit[i].value) {
			if (this.initVals && this.initVals[crit[i].field])
				this.crit[i].value = this.initVals[crit[i].field];
			else
				this.crit[i].value = "";
		}
		this.critFields[crit[i].field] = this.crit[i];
		this.crit[i].plugin = 
			new FocusSearch.pluginTypes[crit[i].fieldtype](this, i, {units: this.anchors.unitsdiv});
	}
}


FocusSearch.registerPlugin = function(name, pluginCtor) {
	if(!FocusSearch.pluginTypes)
		FocusSearch.pluginTypes = new Object();
	FocusSearch.pluginTypes[name] = pluginCtor;
}

FocusSearch.prototype.draw = function() {
	
	var drawTable = document.createElement("table");
	drawTable.engine = this;
	
	if($(this.anchors.critdiv).children("table").get().length)
		drawTable = $(this.anchors.critdiv).children("table").get(0);
	else
		$(this.anchors.critdiv).append(drawTable);
	
	/*
	EZ mod 2/22/8
	added ability to arbitrarily place input fields on html page
	using a new crit object attribute called "containerID".
	
	if plugin does not have capability to use a general container - the drawInDiv method,
	the plugin will append a row or rows to the first table found inside "#containerID"
	
	if no table is found inside "#containerID"
	focussearch will create a table for the plugin to append a row or rows to.
	
	the critdiv$ argument is still required with focusSearch as focusSearch
	still has arbitrary elements not directly related to the crit[] argument
	which focusSearch still needs to display (such as the #status div).
	*/
	//Thinking of pushing the check for a container off to the plugins
	// so FS just calls draw() no matter what on each one and doesn't 
	// need to know about drawInDiv() -KB 6-6-08
	for(var i=0; i < this.crit.length; i++) {
		if (this.crit[i].containerID) {
			if (typeof this.crit[i].plugin.drawInDiv == "function")
				this.crit[i].plugin.drawInDiv();
			else {
				if($("#" + this.crit[i].containerID).children("table").get().length == 0)
					$("#" + this.crit[i].containerID).append(document.createElement("table"));
				
				this.crit[i].plugin.draw($("#" + this.crit[i].containerID).children("table").get(0));
			}
		}
		else
			this.crit[i].plugin.draw(drawTable);
	}
	if (this.anchors.resultsdiv) {
		if (this.anchors.initdiv) {
			$(this.anchors.resultsdiv).children().hide();
			if (typeof this.anchors.initdiv == "string") {
				var div = document.createElement("div");
				$(div).addClass("init").append(this.anchors.initdiv);
				this.anchors.initdiv = div;
			}
			if (typeof this.anchors.initdiv == "object") {
				$(this.anchors.resultsdiv).append(this.anchors.initdiv);
				this.firstrun = true;
			}
		}	
		if (this.anchors.emptydiv) {
			if (typeof this.anchors.emptydiv == "string") {
				var div = document.createElement("div");
				$(div).addClass("empty").append(this.anchors.emptydiv);
				this.anchors.emptydiv = div;
			}
			if(typeof this.anchors.emptydiv == "object")
				$(this.anchors.resultsdiv).append(
				 $(this.anchors.emptydiv).hide()
				);
		}
	}

/*
	$(drawTable).append(
	 $("<tr>").append(
	  $("<th>").attr("colspan", "2").css({"text-align":"center", "visibility": "visible"}).append(
	   $("<div>").attr("id","status").text("Loading...")
	)));
*/

	drawTable = null;
	this.hashAllTargetFieldSets();
	this.initPlugins();
	this.critUpdate();
}

FocusSearch.prototype.initPlugins = function() {
	var initCrit = 0;
	for(var i=0; i<this.crit.length; i++) {
		if(this.crit[i].priority) {
			if(!initCrit)
				initCrit = this.crit[i];
			else if(this.crit[i].priority < initCrit.priority)
				initCrit = this.crit[i];
		}
	}
	if(initCrit) {
		initCrit.plugin.init();
		var engine = this;
		setTimeout(function(){engine.initPlugins();}, 1);
	}
	//Separate statement for slower processing of very low priority fields?
}

FocusSearch.prototype.critUpdate = function(plugin) {
	
	//Pre-Search
	var results = new Array();
	this.criteria = "";
	if (plugin) {
		if (this.critfunc) 
			this.critfunc(plugin);
		this.callingPlugin = plugin;
	}
	for(var i=0; i < this.crit.length; i++) {
		if(this.crit[i].value) {
			this.criteria += this.crit[i].value + ",";
		}
	}
	
	if (this.targets) {
		this.clearSearchResultHash();
		//Search
		var i = 0;
		var j = 0;
		var foundFl = true;
		for(var i=0; i < this.targets.length; i++) {
			foundFl = true;
			for(var j=0; j < this.crit.length; j++) {
				if(!this.crit[j].plugin.doesMatch(this.targets[i])) {
					foundFl = false;
					break;
				}
			}
			if (foundFl) {
				results.push(i);
				this.appendToSearchResultsHash(i);
			}
		}
		
		foundFl = null;
		i = null;
		j = null;
	}
	if (this.clearResults && this.anchors.resultsdiv)
			this.clearResults();
	//Post-Search
	if(results.length) {
		//EZ - quick fix TODO: Put this in gracefully later
		this.drawResults(results);
		this.updatePlugins(results);
	} else {
		this.drawResults(results);
		this.updatePlugins(results);
	}
		results = null;
	if(this.anchors.resultsdiv && !$(this.anchors.resultsdiv.mvc.tbody).children(".selected").filter(".subitem").get().length)
		this.showPreview();
	if($("#loading").css("visibility") == "visible")
		$("#loading").css("visibility", "hidden");
}

FocusSearch.prototype.drawResults = function(in_data) {
		if(!this.targets || !this.anchors.resultsdiv)
			return;
		if (this.firstrun && !this.initVals) {
			delete this.firstrun;
			return;
		}
		$('.init').hide();
		var res = $(this.anchors.resultsdiv).children("table");
		if (res) {
			if ((in_data.length == 0) && ($('.empty').length > 0)) {
				//$(res).hide();		//rescompete custom
				$("#init").hide(); 		//rescompete custom
				$('.empty').show();
			}
			else {
				$(res).show();
				$('.empty').hide();
			}
			this.in_data = in_data;
			this.end = 30;
			if(this.groupfield)
				this.drawGroupResults(in_data);
			else
				this.drawRawResults();
		}
}

FocusSearch.prototype.updatePlugins = function(in_data) {
	for(var i=0; i < this.crit.length; i++) {
		if(this.callingPlugin && this.crit[i].plugin == this.callingPlugin)
			continue;
		if(in_data)
			this.crit[i].plugin.update(in_data);
		else
			this.crit[i].plugin.update();
	}
}

/*
 * Need to update to work with this.in_data and this.end -6-9-08
 */
//Draws results of search with grouping by specified category
FocusSearch.prototype.drawGroupResults = function(in_data) {
	this.drawGroupResultsContinue = 0;
	if(!this.targets || !this.anchors.resultsdiv)
		return;
	var engine = this;
	/*
$("#status").css("visibility", "visible");
*/
	//If there are open groups, inject the "subitems" back into the in_data and 
	// remember which groups were open.
	if($(engine.anchors.resultsdiv.mvc.tbody).children(".subitem").get().length) {
		$(engine.anchors.resultsdiv.mvc.tbody).children().not(
		  $(engine.anchors.resultsdiv.mvc.tbody).
		    children(".subitem").prev().not(".subitem")
		).not(".subitem").remove();
		var save = new Object();
		var temp = $(engine.anchors.resultsdiv.mvc.tbody).children(".groupitem").get();
		for(i in temp) {
			save[temp[i].selectid] = false;
			if(temp[i].className.indexOf("selected") >= 0)
				var selectMe = temp[i].selectid;
		}
		temp = null;
	}
	this.anchors.resultsdiv.empty();
	this.drawGroupContinue(0, new Object(), {"save": save, "selectMe": selectMe});
}

FocusSearch.prototype.drawGroupContinue = function(i, categoryElems, endParam) {
	this.drawGroupResultsContinue++;
	var curContinue = this.drawGroupResultsContinue;
	var engine = this;
	var end = i + 50;
	var curTarget = '';
	if(end > this.in_data.length)
		end = this.in_data.length;
	for(i; i<end; i++) {
		curTarget = this.targets[this.in_data[i]];
		if(curTarget[this.groupfield] == "")
			continue;
		//Store each item's unique id in an array according to the value in its target groupfield
		if(categoryElems[curTarget[this.groupfield]]) {
			categoryElems[curTarget[this.groupfield]].results = this.in_data[i] + "," + categoryElems[curTarget[this.groupfield]].results;
		} else {
			var label = [curTarget[this.groupfield]];
			categoryElems[curTarget[this.groupfield]] = 
				engine.anchors.resultsdiv.
					addRow(curTarget[this.groupfield],
					label,
					{
					setClass: "groupitem",
					onclick: function(id) {
						var groupChildren = new Array();
						var groupEl = $(engine.anchors.resultsdiv.mvc.tbody).
							children(".groupitem").filter(".selected").get(0);
						for(groupEl; groupEl.nextSibling &&
							  groupEl.nextSibling.className.indexOf("subitem") >= 0;
							  groupEl = groupEl.nextSibling)
							groupChildren[groupChildren.length] = groupEl.nextSibling;
						if(groupChildren.length) {
							$(groupChildren).remove();
							return false;
						}
						var subitems = categoryElems[id].results.split(",");
						if(subitems[subitems.length-1]=="")
							subitems.splice(subitems.length-1,1);
						for(var i=0;i<subitems.length;i++){
							var index = subitems[i];
							subitems[i] = engine.targets[subitems[i]];
							subitems[i].selectid = index;
						}
						subitems.sort(subitemSort);
					/*
	$("#status").css("visibility", "visible");
*/
						engine.drawSubitems(0, subitems, categoryElems, id);
					}}
				);
			categoryElems[curTarget[this.groupfield]].results = this.in_data[i] + ",";
		}
	}
	if(end == this.in_data.length)
		this.drawGroupDone(categoryElems, endParam);
	else
		setTimeout(function(){engine.drawGroupContinue(end, categoryElems, endParam);}, 1);
}

FocusSearch.prototype.drawSubitems = function(start, subitems, categoryElems, id) {
	var end = start + 25;
	var engine = this;
	var curTarget = '';
	var label = '';
	var resultTitle;
	if(end > subitems.length)
		end = subitems.length;
	for(var i = start; i < end; i++) {
		curTarget = subitems[i];
		if(curTarget && (curTarget[this.resultsfield] || this.resultsfunction)) {
			if (this.resultsfunction) {
				label = this.resultsfunction(curTarget);
			}
			else {
				label = curTarget[this.resultsfield];
			}
			if (this.resulttitlefield) {
				resultTitle = curTarget[this.resulttitlefield];
			}
			else {
				resultTitle = '';
			}
			if(i == 0) {
				subitems[i] = this.anchors.resultsdiv.addRow(
					subitems[i].selectid,
					[label],
					{
					 setClass: "subitem",
					 after: categoryElems[id],
					 onclick: function(id) {
						if(engine.anchors.previewdiv)
							engine.showPreview(engine.targets[id]);
						if(engine.pickfunc)
							engine.pickfunc(engine.targets[id]);
						},
					 ondblclick: function(id) {
						if(engine.resultdblclickfunc)
						 	return engine.resultdblclickfunc(engine.targets[id]);
					 	},
					 title: resultTitle + ''
					}
				);
			} else {
				subitems[i] = this.anchors.resultsdiv.addRow(
					subitems[i].selectid,
					[label],
					{
					 setClass: "subitem",
					 after: subitems[i-1],
					 onclick: function(id) {
						if(engine.pickfunc)
							engine.pickfunc(engine.targets[id]);
						if(engine.anchors.previewdiv)
							engine.showPreview(engine.targets[id]);
						},
					 ondblclick: function(id) {
						if(engine.resultdblclickfunc)
						 	engine.resultdblclickfunc(engine.targets[id]);
					 	},
					 title: resultTitle
					}
				);
			}
		}
	}
	if(end != subitems.length)
		setTimeout(function(){engine.drawSubitems(end, subitems, categoryElems, id);}, 1);
	else {
		/*
if($("#status").css("visibility") == "visible")
			$("#status").css("visibility", "hidden");
*/
	}
		
}

FocusSearch.prototype.drawGroupDone = function(categoryElems, param) {
	/*
 	var engine = this;
	//Reinjects groups open before a new search
	for(groupitemRow in param.save) {
		if(param.save[groupitemRow]) {
			param.selectMe = categoryElems[groupitemRow];
			continue;
		}
		if (categoryElems[groupitemRow]) {
			categoryElems[groupitemRow].onclick();
		}
	}
	if(param.selectMe) {
		$.each($(engine.anchors.resultsdiv.mvc.tbody).children().get(), 
		  function(i, row) {
			if(row.selectid == param.selectMe) {
				if(row.className.indexOf("groupitem") < 0)
					row.onclick();
				else {
					engine.anchors.resultsdiv.mvc.selectRow(row);
				}
			}			
		});
	} else
		$(engine.anchors.resultsdiv.mvc.tbody).children().removeClass("selected");
	*/
/*
	if($("#status").css("visibility") == "visible")
		$("#status").css("visibility", "hidden");
*/
}

//Draws results of search individually
FocusSearch.prototype.drawRawResults = function(i) {
	if(!this.targets || !this.anchors.resultsdiv)
		return;
	/* EZ Mod 2/6/8 */
/*
	$("#status").css("visibility", "visible");
*/
	var engine = this;
	if(!i) {
		var i = 0;
		engine.anchors.resultsdiv.empty();
	}
	var end = i + 30;
	if(end > this.in_data.length)
		end = this.in_data.length;
	for(i; i < end; i++) {
		var curTarget = engine.targets[this.in_data[i]];
		if(!curTarget)
			continue;
		engine.anchors.resultsdiv.
		addRow(this.in_data[i],
				[curTarget[engine.resultsfield].toString()],
				{onclick: function(id) {
					if (engine.pickfunc) 
						engine.pickfunc(engine.targets[id]);
					if(engine.anchors.previewdiv)
						engine.showPreview(engine.targets[id]);
					}});
	}
	if(end < this.in_data.length)
		setTimeout(function(){engine.drawRawResults(end);}, 1);
	else {/*EZ Mod 2/6/8 copied from end of group draw and removed lock test */
		/*
if($("#status").css("visibility") == "visible")
			$("#status").css("visibility", "hidden");
*/
	}
}

FocusSearch.prototype.showPreview = function(dataobj) {
	if(!this.anchors.previewdiv)
		return;
	if(!dataobj) {
		$(this.anchors.previewdiv).html("");
		return;	
	}
	$(this.anchors.previewdiv).html(dataobj[this.previewfield]);
} 

FocusSearch.prototype.cleanup = function() {
	for(var i=0; i < this.targets.length; i++) {
		for(elem in this.targets[i]) {
			if(elem.indexOf("_fs") >= 0)
				delete this.targets[i][elem];
		}
	}
}

FocusSearch.prototype.getSelected = function() {
	if(!this.anchors.resultsdiv || !this.targets)
		return;
	var engine = this;
	if(this.idfield)
		return $.map(
			$(this.anchors.resultsdiv.mvc.tbody).children(".selected").get(), 
				function(n) {
					return engine.targets[n.selectid][engine.idfield];
				}
			);
}

FocusSearch.prototype.getTargetFieldSet = function(field) {
	if (this.searchResultsHash[field]) {
		return this.searchResultsHash[field];
	} else {
		return new Object();
	}
}

FocusSearch.prototype.appendToTargetFieldSets = function(field) {
	var del = '';
	if (!this.targetFieldSets) {
		this.targetFieldSets = new Object();
	}
	if (this.critFields[field].delimiter) {
		del = this.critFields[field].delimiter;
	}
	this.targetFieldSets[field] = del;
}

FocusSearch.prototype.hashAllTargetFieldSets = function() {
	var field = '';
	for (field in this.targetFieldSets) {
		this.hashTargetField(field,this.targetFieldSets[field]);
	}
	field = null;
}

FocusSearch.prototype.hashTargetField = function(field,delimiter) {
	if (this.targetFields[field]) {
		return this.targetFields[field];
	}
	this.targetFields[field] = new Object();
	for (var i=0;i<this.targets.length;i++) {
		if (delimiter != '') {
			this.targets[i][field + "_fs"] = new Object();
			var curFieldSet = this.targets[i][field].split(delimiter);
			for (var j=0;j<curFieldSet.length;j++) {
				if (curFieldSet[j] != "") {
					this.targets[i][field + "_fs"][curFieldSet[j]] = true;
					this.targetFields[field][curFieldSet[j]] = true;
				}
			}
		}
		else {
			this.targetFields[field][this.targets[i][field]] = true;
		}
	}
	return this.targetFields[field];
}

FocusSearch.prototype.clearSearchResultHash = function() {
	this.searchResultsHash = new Object();
	this.searchResults = new Array();
}

FocusSearch.prototype.appendToSearchResultsHash = function(index) {
	var field = '';
	var fieldOption = '';
	this.searchResults.push(index);
	for (field in this.targetFieldSets) {
		if (!this.searchResultsHash[field]) {
			this.searchResultsHash[field] = new Object();
		}
		if (!this.targetFields[field]) { // finish init on field if its not done already
			this.hashTargetField(field,this.targetFieldSets[field]);
		}
		if (this.targets[index][field + "_fs"]) {
			for (fieldOption in this.targets[index][field + "_fs"]) {
				if (!this.searchResultsHash[field][fieldOption])
					this.searchResultsHash[field][fieldOption] = new Array();
				this.searchResultsHash[field][fieldOption].push(index);
			}
		}
		else {
			fieldOption = this.targets[index][field];
			if (!this.searchResultsHash[field][fieldOption])
				this.searchResultsHash[field][fieldOption] = new Array();
			this.searchResultsHash[field][fieldOption].push(index);
		}
	}
	field = null;
	fieldOption = null;
}

FocusSearch.prototype.getDependencyList = function(field) {
	if (this.depList[field]) {
		return this.depList[field];
	}
	return new Array();
}

FocusSearch.prototype.bldDependency = function(field) {
	//
	//  This will take the intersection of all dependency sets for a field
	//  and combine them into one associative array - this.dependency[field]
	//  if this.dependency[fiel] does not exists then there are no sets available
	//  to combine.
	//
	if (!this.depSets[field]) {  // not sure how it would ever get here, but just in case
		if (this.dependency[field]) {
			delete this.dependency[field];
		}
		if (this.depList[field]) {
			delete this.depList[field];
		}
		return;
	}
	
	var curSrcField = '';
	var curEnt = '';
	this.dependency[field] = new Object();
	var srcFieldCount = 0;
	for (curSrcField in this.depSets[field]) {
		srcFieldCount++;
		if (srcFieldCount == 1) {  // It would seem more ideal to start with the smallest set
			for (curEnt in this.depSets[field][curSrcField].set) { //do not "copy"; "duplicate" instead
				this.dependency[field][curEnt] = true;
			}
		}
		else {
			for (curEnt in this.dependency[field]) {
				if (! this.depSets[field][curSrcField].set[curEnt]) {
					delete this.dependency[field][curEnt];
				}
			}
		}
	}
	
	if (srcFieldCount == 0) {  // This can happen when called from clearDependency
		delete this.depSets[field];
		delete this.dependency[field];
		delete this.depList[field];
	}
	else {
		this.depList[field] = new Array();
		for (curEnt in this.dependency[field]) {
			this.depList[field].push(curEnt);
		}
		this.depList[field].sort();
	}
	return;
}

FocusSearch.prototype.setDependency = function(srcField,destField,destVals) {
	if (!this.depSets[destField]) {
		this.depSets[destField] = new Object();
	}
	if (!this.depSets[destField][srcField]) {
		this.depSets[destField][srcField] = new Object();
	}
	this.depSets[destField][srcField].set = destVals;
	this.bldDependency(destField);
	return;
}

FocusSearch.prototype.clearDependency = function(srcField) {
	var curField = '';
	for (curField in this.depSets) {
		if (this.depSets[curField][srcField]) {
			delete this.depSets[curField][srcField];
		}
		if (objectIsEmpty(this.depSets[curField])) {
			delete this.depSets[curField];
		}
		this.bldDependency(curField);
	}
	return;
}
	

function objectIsEmpty(obj) {
	for(var i in obj) 
		return false;
	return true;
}

function subitemSort(a,b) {
	return a.productNumber.localeCompare(b.productNumber);
}


/**********************************************/
/* ---------- Start Plugin Section ---------- */
/**********************************************/
function QtoolCheckBoxList(fsObj, index, param) {
	this.critObj = fsObj.crit[index];
	this.field = fsObj.crit[index].field;
	this.index = index;
	this.searchObj = fsObj;
	
	this.checkBoxSet = new Object();

	this.getValue = function(){
		var curVals = new Array();
		var entry = "";
		
		for (entry in this.checkBoxSet)
			if (this.checkBoxSet[entry].inputItem.checked)
				curVals.push(entry);
		
		if (curVals.length > 1)
			this.critObj.value = "('" + curVals.join("' or '") + "')";
		else if (curVals.length == 1)
			this.critObj.value = curVals[0];
		else
			this.critObj.value = "";
		
		return this.critObj.value;
	}
	this.delimiter = '';
	if(this.critObj.delimiter)
		this.delimiter = this.critObj.delimiter;
	this.searchObj.appendToTargetFieldSets(this.field);

	if (this.critObj.containerID)
		this.inputID = this.critObj.containerID;
	else
		this.inputID = "checkBoxList_" + this.index;
}

QtoolCheckBoxList.prototype.draw = function(parentEl) {
	$(parentEl).append(
				$("<tr>").append(
							$("<th>").attr("colspan", "2").html(this.critObj.label)
						)).append(
				$("<tr>").append(
							$("<td>").attr({colspan: "2",id: this.inputID})
						)
				);
	if(!this.critObj.priority)
		this.critObj.priority = 1;
	return $("#" + this.inputID).get(0);
}

QtoolCheckBoxList.prototype.drawInDiv = function(parentEl) {
	if(!this.critObj.priority)
		this.critObj.priority = 1;
	return $("#" + this.inputID).get(0);
}

QtoolCheckBoxList.prototype.addCheckBox = function(val,index) {
	
	if (this.checkBoxSet[val]) {
		this.checkBoxSet[val].targetIndex.push(index);
		return;
	}
	this.checkBoxSet[val] = new Object();
	
	this.checkBoxSet[val].targetIndex = new Array();
	this.checkBoxSet[val].targetIndex.push(index);
	
	this.checkBoxSet[val].entry = document.createElement("li");

	this.checkBoxSet[val].inputItem = document.createElement("input");
	this.checkBoxSet[val].inputItem.setAttribute("type","checkbox");
	this.checkBoxSet[val].inputItem.setAttribute("name",this.inputID);
	this.checkBoxSet[val].inputItem.setAttribute("value",val);
	
	var plugin = this;
	this.checkBoxSet[val].inputItem.onclick = function(event) {
		this.blur();
		plugin.getValue();
		plugin.searchObj.critUpdate(plugin);
	}

	$(this.checkBoxSet[val].entry).append(this.checkBoxSet[val].inputItem);
	$(this.checkBoxSet[val].entry).append(val);

	//$(this.listBox).append(this.checkBoxSet[val].entry);
}

QtoolCheckBoxList.prototype.init = function() {
	var checkList = new Array();
	var elem = '';
	var i = 0;
	this.listBox = document.createElement("ul");
	$("#" + this.inputID).append(this.listBox);
	if(this.searchObj.targets) {
		var targetFieldSet = this.searchObj.getTargetFieldSet(this.field);
		for(elem in targetFieldSet) {
			this.addCheckBox(elem,i);
			i++;
		}
	}
	for (elem in this.checkBoxSet)
		checkList.push(elem);
	checkList.sort();
	for (elem=0;elem < checkList.length; elem++)
		$(this.listBox).append(this.checkBoxSet[checkList[elem]].entry);
	delete this.critObj.priority;
}

QtoolCheckBoxList.prototype.update = function(in_data) {
	 if (this.critObj.mode == "any")
		return true;
	var targetFieldSet = this.searchObj.getTargetFieldSet(this.field); // Search results
	var depFieldSet = this.searchObj.getDependencyList(this.field); // Dependencies
	if(depFieldSet.length > 0) {
		var opt = '';
		var optHash = new Object();
		for(var i=0; i < depFieldSet.length; i++){
			opt = depFieldSet[i];
			/* //Use dependencies with search results
			if(targetFieldSet[opt]) {
				optHash[opt] = true;
			}
			 */
			optHash[opt] = true;
		}
		this.updateEnd(optHash);
		opt = null;
		i = null;
		optHash = null;
	} else {
		this.updateEnd(targetFieldSet);
	}
}

QtoolCheckBoxList.prototype.updateEnd = function(dependsItems){
	//if (!objectIsEmpty(dependsItems)) {
		var val = "";
		for (val in this.checkBoxSet) {
			if (!this.checkBoxSet[val].inputItem.checked) {
				if (!dependsItems[val]) {
					$(this.checkBoxSet[val].entry).hide();
				}
				else {
					$(this.checkBoxSet[val].entry).show();
				}
			}
		}
	//}
}

QtoolCheckBoxList.prototype.doesMatch = function(dataobj) {
	var list = this.critObj.value;
	var listSet = new Array();
	var candidate = new Array();
	
	if (list.length == 0)
		return true;
		
	if ((dataobj[this.field].length == 0) && (list != "None"))
		return false;
	
	//build candidate list
	if (this.critObj.delimiter) {
		candidate = dataobj[this.field].split(this.critObj.delimiter);
	}
	else {
		candidate.push(dataobj[this.field]);
	}
	
	//build selected list
	if (/^\('/.test(list)) {
		listSet = list.substring(2,list.length-2).split(/' or '/);
	}
	else {
		listSet.push(list);
	}
	
	var candIndex = "";
	var listSetIndex = "";
	for (listSetIndex in listSet) {
		var found_fl = false;
		for (candIndex in candidate) {
			if (candidate[candIndex] == listSet[listSetIndex]) {
				if (this.critObj.mode == "any")
						return true;
				else {
					found_fl = true;
					break;
				}
			}
		}
		if ((! found_fl) && (this.critObj.mode != "any")) {
			return false;
		}
	}
	if (this.critObj.mode == "any") {
		return false;
	}
	else {
		return true;
	}
}


FocusSearch.registerPlugin("checkboxlist", QtoolCheckBoxList);

function QtoolEnumeration(fsObj, index, param) {
	this.critObj = fsObj.crit[index];
	this.field = fsObj.crit[index].field;
	this.index = index;
	this.searchObj = fsObj;
	
	//this plugin has multipick aspects
	//so when multiple choices are selected
	//are we in "any" mode (group everything together with "or")
	//or are we in "all" mode (group everything together with "and")
	if (this.critObj.singlePick)
		this.singlePickFlag = this.critObj.singlePick;
	else 
		this.singlePickFlag = false;
		
	if (! this.singlePickFlag) {
		if (this.critObj.mode) {
			this.mode = this.critObj.mode;
			if ((!this.critObj.delimiter) && (this.mode != "any"))
				this.singlePickFlag = true;
		}
		else {
			if (this.critObj.delimiter)
				this.mode = "all";
			else
				this.mode = "any";  // Only thing actually tested so far - EZ
		}
	}
	else {
		this.mode = "any";
	}
	
	this.optionSet = new Object();
	this.optionList = new Array();
	this.anyFlag = false; //anyFlag is set to true if anyID is defined and found in DOM
	
	this.getValue = function(){
		var curVals = $("." + this.critObj.classSet).filter(".selected").map(function(){return this.id}).get();
		
		switch(curVals.length) {
			case 0:
				this.critObj.value = "";
				break;
			case 1:
				if ((this.anyFlag) && (curVals[0] == this.critObj.anyID))  
					this.critObj.value = "";
				else 
					this.critObj.value = curVals[0];
				break;
			default:
				this.critObj.value = "('" + curVals.join("','") + "')";
				break;
		}
		
		return this.critObj.value;
	}
	
	this.cleanSelections = function(choiceID){
		if (this.singlePickFlag) {
			$("#" + choiceID).addClass("selected");
			$("." + this.critObj.classSet).not("#" + choiceID).removeClass("selected");
		}
		else {
			if (this.anyFlag) {
				var selCount = $("." + this.critObj.classSet).filter(".selected").size();
				if ((choiceID == this.critObj.anyID) || (selCount == this.optionList.length - 1)
				|| (selCount == 0)) {
					$("." + this.critObj.classSet).not("#" + this.critObj.anyID).removeClass("selected");
					$("#" + this.critObj.anyID).addClass("selected");
				}
				else {
					$("#" + this.critObj.anyID).removeClass("selected");
				}
			}
		}
		return this.getValue();
	}
	this.delimiter = '';
	if(this.critObj.delimiter)
		this.delimiter = this.critObj.delimiter;
	this.searchObj.appendToTargetFieldSets(this.field);
	if (this.critObj.containerID)
		this.inputID = this.critObj.containerID;
	else
		this.inputID = "enumerationSet_" + this.index;
}

QtoolEnumeration.prototype.draw = function(parentEl) {
	$(parentEl).append(
				$("<tr>").append(
							$("<th>").attr("colspan", "2").html(this.critObj.label)
						)).append(
				$("<tr>").append(
							$("<td>").attr({colspan: "2",id: this.inputID})
						)
				);
	if(!this.critObj.priority)
		this.critObj.priority = 1;
	return $("#" + this.inputID).get(0);
}

QtoolEnumeration.prototype.drawInDiv = function() {
	if(!this.critObj.priority)
		this.critObj.priority = 1;
	return $("#" + this.inputID).get(0);
}

QtoolEnumeration.prototype.init = function() {
	var curID = "";
	var curIndex = "";
	var plugin = this;
	
	this.optionList = $("." + this.critObj.classSet).map(function(){return this.id}).get();
	for (curIndex in this.optionList) {
		curID = this.optionList[curIndex];
		var curElement = $("#" + curID).get(0);
		this.optionSet[curID] = new Object();
		this.optionSet[curID].element = curElement;
		curElement.onclick = function(event) {
			$(this).toggleClass("selected");
			this.blur();
			plugin.cleanSelections(this.id);
			plugin.searchObj.critUpdate(plugin);
			return false;
		}
		
		if ((this.critObj.anyID) && (this.critObj.anyID == curID))
			this.anyFlag = true;
	}
	
	if (this.critObj.defaultIDs) {
		var IDList = this.critObj.defaultIDs.split(/,/);
		for (curIndex in IDList) {
			curID = IDList[curIndex];
			if (this.optionSet[curID]) {
				$(this.optionSet[curID].element).addClass("selected");
				this.cleanSelections(curID);
			}
		}
	}

	delete this.critObj.priority;
}

QtoolEnumeration.prototype.update = function(in_data) {
	if (this.mode == "any")
		return true;
		
	var targetFieldSet = this.searchObj.getTargetFieldSet(this.field); // Search results
	var depFieldSet = this.searchObj.getDependencyList(this.field); // Dependencies
	if(depFieldSet.length > 0) {
		var opt = '';
		var optHash = new Object();
		for(var i=0; i < depFieldSet.length; i++){
			opt = depFieldSet[i];
			/* //Use dependencies with search results
			if(targetFieldSet[opt]) {
				optHash[opt] = true;
			}
			 */
			optHash[opt] = true;
		}
		this.updateEnd(optHash);
		opt = null;
		i = null;
		optHash = null;
	} else {
		this.updateEnd(targetFieldSet);
	}
}

QtoolEnumeration.prototype.updateEnd = function(dependsItems){
	//if (!objectIsEmpty(dependsItems)) {}
	// Nothing to do here, really? -KB 6-6-08
}

QtoolEnumeration.prototype.doesMatch = function(dataobj) {
	var list = this.critObj.value;
	var listSet = new Array();
	var candidate = new Array();
	
	if (list.length == 0)
		return true;
		
	if ((dataobj[this.field].length == 0) && (list != "None"))
		return false;
	
	//build candidate list
	if (this.critObj.delimiter) {
		candidate = dataobj[this.field].split(this.critObj.delimiter);
	}
	else {
		candidate.push(dataobj[this.field]);
	}
	
	//build selected list
	if (/^\('/.test(list)) { //just check'n
		listSet = list.substring(2,list.length-2).split(/','/);
	}
	else {
		listSet.push(list);
	}
	
	var candIndex = "";
	var listSetIndex = "";
	for (listSetIndex in listSet) {
		var found_fl = false;
		for (candIndex in candidate) {
			if (candidate[candIndex] == listSet[listSetIndex]) {
				if (this.mode == "any")
						return true;
				else {
					found_fl = true;
					break;
				}
			}
		}
		if ((! found_fl) && (this.mode != "any")) {
			return false;
		}
	}
	if (this.mode == "any") {
		return false;
	}
	else {
		return true;
	}
}

FocusSearch.registerPlugin("enumeration", QtoolEnumeration);

function QtoolHidden(fsObj, index, param) {
	this.critObj = fsObj.crit[index];
	this.field = fsObj.crit[index].field;
	this.index = index;
	this.searchObj = fsObj;
	this.critList = fsObj.crit[index].combine; //list of crits by field involved in this
	this.getValue = function(in_value){ 
		if((typeof in_value) != "undefined") {
			if (this.searchObj.critFields[in_value.field]) {
				this.searchObj.crit[this.index].value = '';
				for(var i=0; i < this.critList.length; i++) {
					if (!this.searchObj.critFields[this.critList[i]].value) {
						this.searchObj.crit[this.index].value = '';
						return this.searchObj.crit[this.index].value;
					}
					this.searchObj.crit[this.index].value += this.searchObj.critFields[this.critList[i]].value;
				}
			}
		}
		return this.searchObj.crit[this.index].value;
	}
	this.delimiter = '';
	if (this.critObj.delimiter) {
		this.delimiter = this.critObj.delimiter;
	}
	this.searchObj.appendToTargetFieldSets(this.field);
}


QtoolHidden.prototype.draw = function(parentEl) {
	var terms = this.searchObj.crit[this.index];
	var textEl = document.createElement("input");
	textEl.type = "hidden";
	var plugin = this;

	$(parentEl).append($(textEl));
	this.input = textEl;
	return textEl;
}

QtoolHidden.prototype.update = function(in_data) { //nothing to do here
}

QtoolHidden.prototype.doesMatch = function(dataobj) {
	if(!this.getValue())
		return true;
	if(dataobj[this.field+"_fs"]) {
		return dataobj[this.field+"_fs"][this.getValue()];
	} else {
		if(this.getValue() == dataobj[this.field])
			return true;
	}
	return false;
}

FocusSearch.registerPlugin("hidden", QtoolHidden);

function QtoolPickOne(fsObj, index, param) {
	this.critObj = fsObj.crit[index];
	this.field = this.critObj.field;
	this.index = index;
	this.searchObj = fsObj;
	this.optionItems = new Object();
	this.getValue = function(in_value){
			if((typeof in_value) != "undefined") {
				this.searchObj.crit[this.index].value = in_value;
				if (this.critObj.depends) {
					var crossField = '';
					if (this.critObj.depends[in_value]) {
						for (crossField in this.critObj.depends[in_value]) {
							this.searchObj.setDependency(this.field,crossField,this.critObj.depends[in_value][crossField]);
						}
					}
					else {
						this.searchObj.clearDependency(this.field);
					}
				}
			}
			return this.searchObj.crit[this.index].value;
	}
	this.delimiter = '';
	if (this.critObj.delimiter) {
		this.delimiter = this.critObj.delimiter;
	}
	this.searchObj.appendToTargetFieldSets(this.field);
		
}

QtoolPickOne.prototype.draw = function(parentEl) {
	var terms = this.searchObj.crit[this.index];
	var selectList = document.createElement("select");
	selectList.length = 0;
	var plugin = this;
	selectList.onchange = function(event) {
		plugin.getValue(this.value);
		plugin.indexSelect = this.selectedIndex;
		plugin.searchObj.critUpdate(plugin); }
	selectList.options[selectList.options.length] =
				new Option("Any", "");
	$(parentEl).append(
	 $("<tr>").append(
	  $("<th>").html(terms.label)
	  ).append($("<td>").append(
	   $("<div>").append(
	    $(selectList)
	))));
	this.input = selectList;
	return $(parentEl).children(/*tbody*/).children("tr").get(
			$(parentEl).children(/*tbody*/).children("tr").length - 1
			);
}

QtoolPickOne.prototype.update = function(in_data) {
	var targetFieldSet = this.searchObj.getTargetFieldSet(this.field);
	var depFieldSet = this.searchObj.getDependencyList(this.field);
	
	if (depFieldSet.length > 0) {
		var opt = '';
		var optHash = new Object();
		for (var i=0; i < depFieldSet.length; i++) {
			opt = depFieldSet[i];
			/*
			While this code is helpful in creating the 'focus'
			aspect, it turns out to be undesirable in CIVCO's
			case - not certain if it will be usefull in other
			cases, but more elaborate flags will be needed
			to parse out when to use the integration of dependencies
			with the current target set.
			
			-EZ 5/14/8
			
			if (targetFieldSet[opt]) {
				optHash[opt] = true;
			}
			*/
			optHash[opt] = true;
		}
		this.updateEnd(optHash);
		opt = null;
		i = null;
		optHash = null;
	}
	else {
		this.updateEnd(targetFieldSet);
	}
}

QtoolPickOne.prototype.updateEnd = function(optionHash) {
	var elem = '';
	var optionList = new Array();
	for (elem in optionHash) {
		if (elem) optionList.push(elem);
	}
	optionList.sort(this.optionSort);
	var selectElem = this.getValue();
	this.input.options.length = 0;
	this.input.options[this.input.options.length] = new Option("Any", "");
	for (var i=0;i<optionList.length;i++) {
		var val = optionList[i];
		if (val == selectElem)
			this.input.options[this.input.options.length] = new Option(val, val, false, true);
		else
			this.input.options[this.input.options.length] = new Option(val, val, false, false);
	}
}
		
QtoolPickOne.prototype.doesMatch = function(dataobj) {
	var val = this.getValue();
	if (val == '') {
		return true;
	}
	if(dataobj[this.field+"_fs"]) {
		return dataobj[this.field+"_fs"][val];
	} else {
		if(val == dataobj[this.field])
			return true;
	}
	return false;
}	

QtoolPickOne.prototype.optionSort = function(a,b) {
	if (a == 'Any') return -1;
	if (b== 'Any') return 1;
		while (a != "") {
		var chars = a.match(/^[^0-9]+/);
		if (chars[0].toLowerCase() != b.match(/^[^0-9]+/)[0].toLowerCase()) 
			return a.toLowerCase().localeCompare(b.toLowerCase());
		a = a.substring(chars[0].length);
		b = b.substring(chars[0].length);
		chars = a.match(/^[0-9]+/);
		if (chars[0] != b.match(/^[0-9]+/)[0]) {
			return parseInt(chars[0]) < parseInt(b.match(/^[0-9]+/)[0]) ? -1 : 1;
		}
		a = a.substring(chars[0].length);
		b = b.substring(chars[0].length);
	}
	return -1;
}


FocusSearch.registerPlugin("pickone", QtoolPickOne);

function QtoolQBE(fsObj, index, param) {
	this.critObj = fsObj.crit[index];
	this.field = fsObj.crit[index].field;
	this.index = index;
	this.searchObj = fsObj;
	this.getValue = function(in_value){ 
			if((typeof in_value) != "undefined")
				this.searchObj.crit[this.index].value = in_value;
			return this.searchObj.crit[this.index].value;}
}

QtoolQBE.prototype.draw = function(parentEl) {
	var terms = this.searchObj.crit[this.index];
	var textEl = document.createElement("input");
	textEl.type = "text";
	var plugin = this;
	textEl.onchange = function (event) {
		plugin.getValue(this.value);
		plugin.searchObj.critUpdate(plugin);
	}
	$(parentEl).append(
	 $("<tr>").append(
	  $("<th>").html(terms.label)
	 ).append($("<td>").append(
		$("<div>").append(
		 $(textEl)
	))));
	this.input = textEl;
	if(this.getValue()) {
		this.input.value = this.getValue();
	}
	
	return $(parentEl).children(/*tbody*/).children("tr").get(
			$(parentEl).children(/*tbody*/).children("tr").length - 1
			);
}

QtoolQBE.prototype.drawInDiv = function() {
	var terms = this.searchObj.crit[this.index];
	var textEl = $("#" + this.critObj.containerID).get(0);
	var plugin = this;
	textEl.onfocus = function (event) {
		qbeKeyElement = this;
		this.qbeKeyEvent = new Date();
	}
	//IE doesn't fire onkeypress for backspace or delete
	textEl.onkeydown = function(event) {
		if($.browser.msie) {
			if(window.event.keyCode == 8 || window.event.keyCode == 46) {
				this.onkeypress(window.event);
				
			}
		}
	}
	textEl.onkeypress = function (event) {
		this.qbeKeyEvent = new Date();
		var timestamp = this.qbeKeyEvent.getTime();
		var qbeElem = this;
		setTimeout(function(){qbetimeout(timestamp, qbeElem);},1000);
	}
	textEl.onchange = function (event) {
		plugin.getValue(this.value);
		plugin.searchObj.critUpdate(plugin);
	}
	this.input = textEl;
	if(this.getValue()) {
		this.input.value = this.getValue();
	}
	
	return this.input;
}

function qbetimeout(timestamp, qbeElem) {
	if(timestamp == qbeElem.qbeKeyEvent.getTime()){
		qbeElem.onchange();
	}
}

QtoolQBE.prototype.update = function(in_data) {
}

QtoolQBE.prototype.doesMatch = function(dataobj) {
	if(!this.getValue()) {
		return true;
	}
	var fieldSet = this.field.split(',');

	for (var fieldIndex=0;fieldIndex < fieldSet.length;fieldIndex++) {
		if(dataobj[fieldSet[fieldIndex]].toLowerCase().indexOf(this.getValue().toLowerCase()) >=0)
			return true;
	}
	return false;
}

FocusSearch.registerPlugin("qbe", QtoolQBE);
FocusSearch.registerPlugin("string", QtoolQBE);
FocusSearch.registerPlugin("number", QtoolQBE);
FocusSearch.registerPlugin("date", QtoolQBE);

// Requires AutoComplete
function QtoolSuggest(fsObj, index, param) {
	this.critObj = fsObj.crit[index];
	this.field = this.critObj.field;
	this.index = index;
	this.searchObj = fsObj;
	this.getValue = function(in_value){ 
			if((typeof in_value) == "undefined") {
				return this.searchObj.crit[this.index].value;
			}
			var foundList = new Array();
			var tempStr = in_value;
			while(this.autocomp.db.regex.test(tempStr))
				tempStr = tempStr.replace(this.autocomp.db.regex, "");
			this.autocomp.db.getStrings(tempStr, "", foundList);
			if(foundList.length == 1 ||
			  (foundList.length > 1 && foundList[0].toLowerCase() == tempStr.toLowerCase())){
				in_value = this.autocomp.db.transTable[foundList[0]];
				in_value = typeof in_value == "undefined" ? "" : in_value;  //In case there is an actual "" value in AutoComplete's DB
				this.searchObj.crit[this.index].value = in_value;
				this.input.value = in_value;
			} else {
				this.searchObj.crit[this.index].value = "";
				this.input.value = "";
			}
			if (this.critObj.depends) {
				var crossField = '';
				if (this.critObj.depends[in_value]) {
					for (crossField in this.critObj.depends[in_value]) {
						this.searchObj.setDependency(this.field,crossField,this.critObj.depends[in_value][crossField]);
					}
				}
				else {
					this.searchObj.clearDependency(this.field);
				}
			}
			return this.searchObj.crit[this.index].value;
	};
	this.delimiter = '';
	if (this.critObj.delimiter) {
		this.delimiter = this.critObj.delimiter;
	}	
	this.searchObj.appendToTargetFieldSets(this.field);

}

QtoolSuggest.prototype.draw = function(parentEl) {
	var terms = this.searchObj.crit[this.index];
	var textEl = document.createElement("input");
	textEl.type = "text";
	var plugin = this;
	textEl.onchange = function (event) {
		plugin.getValue(this.value);
		plugin.searchObj.critUpdate(plugin);
	}
	var oDiv = document.createElement("div");
	oDiv.className = "suggestionBox";
	$(document.body).append(oDiv);
	$(parentEl).append(
	 $("<tr>").append(
	  $("<th>").html(terms.label)).append(
	  $("<td>").append(
		$("<nobr></nobr>").append(
		   $(textEl)).append(
		   $("<a></a>").text("▼").attr("href","#").attr("class","dropdown")
		   .css("text-decoration","none").css("color","white")
			.click(function() {
				if(plugin.searchObj.targets) {
					var acDivs = $(".suggestionBox").get();
					$.each(acDivs, function(i, n) {
							if(n.AutoComplete != plugin.autocomp)
								n.AutoComplete.hide();
					});
					if(oDiv.AutoComplete.oParDiv.style.display == "block") {
						plugin.autocomp.hide();
					}
					else {
						if (textEl.value) {
							var foundList = new Array();
							plugin.autocomp.db.getStrings(textEl.value, "", foundList);
							plugin.autocomp.showResults(foundList);
						}
						else {
							plugin.autocomp.showAll();
						}
						textEl.focus();
						return false;
					}
				}
				this.blur();
				return false;
			})
		)
	  )
	));
	$(document).click(function(event) { 
		if(plugin.searchObj.targets) {
			if(oDiv.AutoComplete.oParDiv.style.display == "block" && 
				event.target != $(textEl).siblings("a").get(0))
				plugin.autocomp.hide(); 
		}
	});
	this.input = textEl;
	if(this.fieldArr)
		this.autocomp = new AutoComplete(this.fieldArr, this.input, oDiv);
	else
		this.autocomp = new AutoComplete(["",""], this.input, oDiv);
	if(this.getValue()) {
		this.input.value = this.getValue();
	}
	if (this.searchObj.initVals && this.searchObj.initVals[this.field]) {
		var val = this.searchObj.initVals[this.field].replace(this.autocomp.db.regex, "").toLowerCase();
		var regex = this.autocomp.db.regex;
		while(regex.test(val))
			val = val.replace(regex,"");
		var foundResult = false;
		for(elem in this.critObj.depends) {
			var temp = elem.replace(this.autocomp.db.regex, "").toLowerCase();
			while(regex.test(temp))
				temp = temp.replace(regex,"");
			if (val == temp) {
				this.searchObj.crit[this.index].value = elem;
				this.input.value = elem;

				if (this.critObj.depends) {
					var crossField = '';
					if (this.critObj.depends[elem]) {
						for (crossField in this.critObj.depends[elem]) {
							this.searchObj.setDependency(this.field,crossField,this.critObj.depends[elem][crossField]);
						}
					}
					else {
						this.searchObj.clearDependency(this.field);
					}
				}
				foundResult = true;
				break;
			}
		}
		this.searchObj.initVals[this.field] = false;
		if (!foundResult) {
			this.searchObj.crit[this.index].value = "";
			this.input.value = "";
		}
	}
	return $(parentEl).children(/*tbody*/).children("tr").get(
			$(parentEl).children(/*tbody*/).children("tr").length - 1
			);
}

QtoolSuggest.prototype.drawInDiv = function(){
	var terms = this.searchObj.crit[this.index];
	var textEl = $("#" + this.critObj.containerID).get(0);
	var plugin = this;
	textEl.onchange = function (event) {
		plugin.getValue(this.value);
		plugin.searchObj.critUpdate(plugin);
	}
	//No "showAll" button for now. Should we assume the <a> is given as well? -KB 6-6-08
	var oDiv = document.createElement("div");
	oDiv.className = "suggestionBox";
	$(document.body).append(oDiv);
	$(document).click(function(event){
		if (plugin.searchObj.targets) {
			if (oDiv.AutoComplete.oParDiv.style.display == "block" &&
			event.target != $(textEl).siblings("a").get(0)) 
				plugin.autocomp.hide();
		}
	});
	this.input = textEl;
	this.autocomp = new AutoComplete(["",""], this.input, oDiv);
	if(this.getValue()) {
		this.input.value = this.getValue();
	}
	
	return this.input;
}

QtoolSuggest.prototype.update = function(in_data) {
	var targetFieldSet = this.searchObj.getTargetFieldSet(this.field);
	var depFieldSet = this.searchObj.getDependencyList(this.field);
	
	if (depFieldSet.length > 0) {
		var opt = '';
		var optHash = new Object();
		for (var i=0; i < depFieldSet.length; i++) {
			opt = depFieldSet[i];
			/*
			While this code is helpful in creating the 'focus'
			aspect, it turns out to be undesirable in CIVCO's
			case - not certain if it will be usefull in other
			cases, but more elaborate flags will be needed
			to parse out when to use the integration of dependencies
			with the current target set.
			
			-EZ 5/14/8
			
			if (targetFieldSet[opt]) {
				optHash[opt] = true;
			}
			*/
			optHash[opt] = true;
		}
		this.updateEnd(optHash);
		opt = null;
		i = null;
		optHash = null;
	}
	else {
		this.updateEnd(targetFieldSet);
	}
}

QtoolSuggest.prototype.updateEnd = function(dependsItems) {
	if(!objectIsEmpty(dependsItems)) {
		this.autocomp.db = new AutoCompleteDB(this.critObj.displayvals);
		for(elem in dependsItems)
			this.autocomp.db.add(elem);
	} else {
		this.autocomp.db = new AutoCompleteDB();
	}
}


QtoolSuggest.prototype.doesMatch = function(dataobj) {
	
	var curVal = this.getValue();
	if ((!curVal) || (curVal == ''))
		return true;

	var curItem = dataobj[this.field];
	if (!dataobj[this.field + "_fs"]) {
		if (curItem.indexOf(curVal) >= 0) {
			return true;
		}
		else {
			return false;
		}
	}

	if (dataobj[this.field + "_fs"][curVal]) {
		return true;
	}
/*
	the suggestion box itself drives the selection to the
	case required so this is not necessary
	-EZ 5/15/8
	
	for (curItem in dataobj[this.field + "_fs"]) {
		if (curItem.toLowerCase().indexOf(curVal) >= 0) {
			return true;
		}
	}
*/
	return false;
}
FocusSearch.registerPlugin("textsuggest", QtoolSuggest);

function QtoolQBEHelper(fsObj, index, param) {
	this.critObj = fsObj.crit[index];
	this.field = fsObj.crit[index].field;
	this.index = index;
	this.searchObj = fsObj;
	this.helpers = this.critObj.helpers;
	this.getValue = function(in_value){ 
			if((typeof in_value) != "undefined")
				this.searchObj.crit[this.index].value = in_value;
			return this.searchObj.crit[this.index].value;}
}

QtoolQBEHelper.prototype.draw = function(parentEl) {
	var terms = this.searchObj.crit[this.index];
	var textEl = document.createElement("input");
	textEl.type = "text";
	var plugin = this;
	textEl.onchange = function(event){
		plugin.getValue(this.value);
		plugin.searchObj.critUpdate(plugin);
	}
	$(parentEl).append(
	 $("<tr>").append(
	  $("<th>").html(terms.label)
	 ).append($("<td>").append(
		$("<nobr></nobr>").append(
		 $(textEl)))));
 	this.input = textEl;
	if (this.helpers) {
		var selectList = document.createElement("select");
		selectList.options[0] = new Option("--Shortcuts--", "", true);
		var i = 1;
		for (elem in this.helpers) {
			var temp = new Option(elem, this.helpers[elem], false);
			temp.title = elem;
			selectList.options[i++] = temp;
		}
		selectList.onchange = function(event){
			plugin.getValue(this.value);
			textEl.value = this.value;
			plugin.searchObj.critUpdate(plugin);
		}
		$(textEl).parents("nobr").eq(0).append(selectList);
		this.inputSelect = selectList;
	}
	if(this.getValue()) {
		this.input.value = this.getValue();
	}
	
	return $(parentEl).children(/*tbody*/).children("tr").get(
			$(parentEl).children(/*tbody*/).children("tr").length - 1
			);
}

QtoolQBEHelper.prototype.drawInDiv = function() {
	var terms = this.searchObj.crit[this.index];
	var textEl = $("#" + this.critObj.containerID).get(0);
	var plugin = this;
	textEl.onfocus = function (event) {
		qbeKeyElement = this;
		this.qbeKeyEventDone = true;
		this.qbeKeyEvent = new Date();
	}
	//IE doesn't fire onkeypress for backspace or delete
	textEl.onkeydown = function(event) {
		if($.browser.msie) {
			if(window.event.keyCode == 8 || window.event.keyCode == 46) {
				this.onkeypress(window.event);
				
			}
		}
	}
	textEl.onkeypress = function (event) {
		this.qbeKeyEvent = new Date();
		this.qbeKeyEventDone = false;
		setTimeout(
			function() {
				var curTime = new Date();
				if ((qbeKeyElement.qbeKeyEvent.getTime() + 1000) <= curTime.getTime())
					qbeKeyElement.onchange();
			},1000);
	}
	textEl.onchange = function (event) {
		if (!qbeKeyElement.qbeKeyEventDone) {
			qbeKeyElement.qbeKeyEventDone = true;
			plugin.getValue(this.value);
			plugin.searchObj.critUpdate(plugin);
		}
	}
	this.input = textEl;
	if(this.getValue()) {
		this.input.value = this.getValue();
	}
	
	return this.input;
}

QtoolQBEHelper.prototype.update = function(in_data) {
}

QtoolQBEHelper.prototype.reset = function(which){
	if (which == "text") {
		this.input.value = "";
		this.value = "";
	}
	if (which == "select") {
		if (!this.inputSelect) 
			return;
		this.inputSelect.selectedIndex = 0;
	}
}

QtoolQBEHelper.prototype.doesMatch = function(dataobj) {
	if(!this.getValue()) {
		return true;
	}
	if(dataobj[this.field].toLowerCase().indexOf(this.getValue().toLowerCase()) >=0)
		return true;
	return false;
}

FocusSearch.prototype.resetHelper = function() {
	for(var i = 0; i< this.crit.length; i++){
		if(typeof this.crit[i].plugin.reset == "function")
			this.crit[i].plugin.reset("select");
	}
}

FocusSearch.prototype.resetQBE = function() {
	for(var i = 0; i< this.crit.length; i++){
		if(typeof this.crit[i].plugin.reset == "function")
			this.crit[i].plugin.reset("text");
	}
}

FocusSearch.registerPlugin("qbehelper", QtoolQBEHelper);
