var AutoSuggest = Class.create();

AutoSuggest.prototype = {
	SelectedIndex: -1,
	QueryDelimiter: "?",
	SearchOptions: {},
	initialize: function (AsYouTypeBox, ResultDiv, onEnter) {
		this.AsYouTypeBox = AsYouTypeBox;	// ID of the text box/textare
		this.ResultDiv = ResultDiv;			// ID of the DIV element where the suggestion list is inserted.
		this.prepare();

		$(this.AsYouTypeBox).observe('keyup', this.filter.bindAsEventListener(this));

		if (onEnter) {
			this.onEnter = onEnter;
		}
	},

	prepare: function () {
		$(this.ResultDiv).hide();
		$(this.AsYouTypeBox).value = "";
		this.SelectedIndex = -1;
	},

	setFocus: function () {
		$(this.AsYouTypeBox).focus();
	},

	setFilter: function (FilterUrl, parseItemFunction) {
		this.FilterUrl = FilterUrl;
		if (FilterUrl.indexOf("?") > 0) {
			this.QueryDelimiter = "&";
		}
		this.parseItemFunction = parseItemFunction;
	},

	filter:	function (event) {
		var AsYouTypeBox = $(this.AsYouTypeBox);

		//var keyPressed  = (window.event) ?    // MSIE or Firefox?
		//	window.event.keyCode : e.keyCode;
		var keyPressed = event.which || event.keyCode;

		// Do not filter when these keys are pressed.
		if (keyPressed == Event.KEY_UP || keyPressed == Event.KEY_DOWN) {
			this.selectByArrow(keyPressed);
			return false;
		}

		var rows = 0;

		/*
		var criteria = $F(AsYouTypeBox).replace(/\r/g,'').split('\n');
		if (criteria.length <= 10) {
			row_num = criteria.length;
		} else {
			row_num = 10;
		}
		var textarea_row_height = row_num * 16 + 4;
		*/

		if(keyPressed == Event.KEY_RETURN || keyPressed == 14){
			// When user selects item with arrow keys, [Enter] should be
			// handled as item selection, not as a new line.
			if (this.SelectedIndex > -1) {
				var objLi = $("result_list_" + this.SelectedIndex);
				if (objLi) {
					//select(objLi.getAttribute("value"), true);
					this.select(event, true);
					this.SelectedIndex = -1;
					return true;
				}
			} else {
				//AsYouTypeBox.rows = row_num;
				//AsYouTypeBox.setStyle({height: textarea_row_height + "px"});
				if (this.onEnter) {
					this.onEnter();
					return true;
				}
			}
			/*
			if (this.onEnter) {
				this.onEnter();
				return true;
			}
			*/
		}

		//var criterion = criteria[criteria.length - 1].strip();
		var criterion = $F(AsYouTypeBox).strip().toLowerCase();
		if (criterion == "") {
			$(this.ResultDiv).hide();
			return true;
		}
		
		/*
		var parameters = $H({
			criteria: criterion,
			list_count: this.list_count
		}).toQueryString();
		*/
		var parameters = $H({
			criteria: criterion,
			start_at: 0,
			num_species:100		// At this moment, auto scroll is not implemented.
		});
		parameters = parameters.merge($H(this.SearchOptions)).toQueryString();

		// this.FilterUrl should be set in setFilter()
		new Ajax.Request(this.FilterUrl + this.QueryDelimiter + parameters,
			{
				method: 'GET',
				onSuccess: this.parse.bindAsEventListener(this)
			});

		// Determine Result list div position
		var offset = Position.cumulativeOffset(AsYouTypeBox);
		var height_adjust = AsYouTypeBox.getHeight() + 4;	// 4 is an arbitrary buffer
		$(this.ResultDiv).setStyle({left: offset[0] + "px", top: (offset[1] + height_adjust) + "px"});
		this.SelectedIndex = -1;

		return true;
	},

	selectByArrow: function (keyPressed) {
		var objDiv = $(this.ResultDiv);
		var direction = 0;
		if (objDiv.style.display == "none") {
			return false;
		}

		switch(keyPressed) {
			case Event.KEY_ESC:
				//alert("Esc pressed");
				break;
			case Event.KEY_LEFT:
				break;
			case Event.KEY_RIGHT:
				break;
			case Event.KEY_UP:
				direction = -1;
				break;
			case Event.KEY_DOWN:
				direction = 1;
				break;
			default:
		}

		if (direction != 0) {
			if (this.SelectedIndex > -1) {
				$("result_list_" + this.SelectedIndex).className = "result_list_li";
			}

			this.SelectedIndex += direction;
			var objLi = $("result_list_" + this.SelectedIndex);
			if (objLi) {
				objLi.className = "result_list_li_selected";
			} else {
				if (direction > 0) {
					this.SelectedIndex -= direction;
				}
			}
		}
	},

	parse: function (oj) {
		// this.FilterUrl (usually getSpecies(?)) return JSON list
		var species_info  = eval("(" + oj.responseText + ")");
		var species_list = species_info.species_list;
		close_button = true;	// Should be provided externally...

		var objDiv = $(this.ResultDiv);
		objDiv.update("");

		if (species_list.length == 0) {
			var innerText = "(no result found)";
		} else {
			var result_list = "";

			var ul = $(document.createElement('UL'));
			ul.className = "result_list_ul";

			for (i = 0; i < species_list.length; i++) {
				// parseItemFunction should return {value:..., label:...}
				var item = this.parseItemFunction(species_list[i]);
				id = "result_list_" + i;
				if (Ext.isIE) {
					// IE has a bug that setAttribute fails.
					// So add value=... here.
					var li = $(document.createElement('<LI value="' + item.value + '">'));
				} else {
					var li = $(document.createElement('LI'));
					li.setAttribute('value', item.value);
				}
				li.id = id;
				li.className = "result_list_li";
				li.update(item.label);
				li.observe("click", this.select.bindAsEventListener(this, false));

				ul.appendChild(li);
			}

			var aDiv = $(document.createElement("DIV"));
			var innerText = "<hr>";
			innerText += '<table width="390"><tr>';
			//innerText += '<td>List first <input id="list_count" type="text" size="2" value="' + this.list_count + '"> matches</td>';
			if (close_button) {
				innerText += '<td align="right"><a href="javascript:void(0)" onclick="$(\'' + this.ResultDiv + '\').hide();">Close</a></td>';
			}
			innerText += '</tr></table>';
			aDiv.update(innerText);
		}

		objDiv.appendChild(ul);
		objDiv.appendChild(aDiv);

		objDiv.show();
		return true;
	},


	select: function (e, selectByEnter) {
		var AsYouTypeBox = $F(this.AsYouTypeBox);

		if (selectByEnter) {
			var ItemSelected = $("result_list_" + this.SelectedIndex);
			// When selected by [Enter], eliminate \n entered by [Enter]
			lastComma = AsYouTypeBox.lastIndexOf("\n");
			AsYouTypeBox = AsYouTypeBox.substring(0, lastComma - 1);
		} else {
			var ItemSelected = Event.element(e);
		}
		var ValueSelected = ItemSelected.getAttribute('value');

		//if (criteriaTextBox.value.indexOf(",") > 0) {
		if (AsYouTypeBox.indexOf("\n") > 0) {
			lastComma = AsYouTypeBox.lastIndexOf("\n");
			$(this.AsYouTypeBox).value = AsYouTypeBox.substring(0, lastComma + 1) + ValueSelected;
		} else {
			$(this.AsYouTypeBox).value = ValueSelected;
		}
		
		$(this.ResultDiv).hide();
		
		if (this.onEnter) {
			this.onEnter();
			return true;
		}
	}
}


/***** This function is called by AutoSuggest.parse for species search *****/
function parseSpecies(item) {
	// Item is a dictionary containing keys such as scientific_name, records, common_name, sp_tsn, pic_url, obis_taxa
	var scientific = item.scientific_name;
	var label = scientific;
	if (item.common_name != "") {
		label += " (" + item.common_name + ")";
	}
	return {value: scientific, label: label};
}


/***** This function is called by AutoSuggest.parse for dataset search *****/
function parseDataset(item) {
	/*
	var dataset_info = item.split(';');
	dataset_id = dataset_info[0];
	dataset_name = dataset_info[1];
	*/
	var dataset_id = item.id;
	var dataset_name = item.name_short;
	var label = dataset_name + " (ID: " + dataset_id + ")";
	//return {value: dataset_id, label: label};
	return {value: dataset_name, label: label};
}