var getElement = function (id) { return (document.all ? document.all[id] : document.getElementById(id)); };

var boxClass = "suggestBox";
var headerClass = "suggestHeader";
var itemClass = "suggestItem";
var itemOverClass = "suggestItemOver";
var valueClass = "suggestValue";
var moreClass = "suggestMore";

var ExtraWidth = 2; // Factor to increase knockout window above textbox
var form = null;
var submitFunction = null;
var txtbox = null;
var iatabox = null;
var url = null;
var fullUrl = null; 	// url, including locale
var cache = {};
var text = "";
var lastVal = "";
var closing = false;
var hasXml = false;
var req = null;
var currentText = "";
var currentKeyCode = "";
var currentIndex = -1;
var currentItem = null;
var rowCount = -1;
var suggestRows = null; // an array of div elements
var itemTagName = "div";
var popup = null; 	// a reference to the suggest popup
var locale = null;
var lastKeyCode = -1; // last key pressed
var activeCalls = 0;
var hideFrame = null; // IFrame.
var isKeyPressed = false;
var isMorePressed = false;
var isVisible = false;
var loadingElement = null;
var fullSearch = false;
var isFullSearch = false;
var hideFullSearch = false;
var bCheckInput = false;
var suggestCallback = null;
var bNoBlur = false;
var contentElement = null;

var keys = {
	TAB: 9,
	ENTER: 13,
	ESC: 27,
	UP: 38,
	DOWN: 40
};

var strings = {
	noairports: TXT_NO_AIRPORTS,
	topsection: TOP_SECTION,
	bottomsection: BOTTOM_SECTION,
	findplaces: TXT_FIND_PLACES,
	extraparams: EXTRA_PARAMS,
	fullparams: FULL_PARAMS
};

function SetStrings(noairports, topsection, bottomsection, findplaces, extraparams, fullparams) {
	strings.noairports = noairports;
	strings.topsection = topsection;
	strings.bottomsection = bottomsection;
	strings.findplaces = findplaces;
	strings.extraparams = extraparams;
	strings.fullparams = fullparams;
}

function UnInstall() {
	var elem;
	if ((elem = getElement("completeDiv"))) {
		if (elem && elem.parentNode) { elem.parentNode.removeChild(elem); }
	}
	if ((elem = getElement("hideFrame"))) {
		if (elem && elem.parentNode) { elem.parentNode.removeChild(elem); }
	}
	lastVal = "";
	closing = false;
	text = "";
	currentText = "";
	currentKeyCode = "";
	currentIndex = -1;
	currentItem = null;
	rowCount = -1;
	suggestRows = null;
	itemTagName = "div";
	form = null;
	popup = null;
	iatabox = null;
	locale = null;
	lastKeyCode = -1;
	hasXml = false;
	fullUrl = null;
	url = null;
	activeCalls = 0;
	hideFrame = null;
	isFullSearch = fullSearch;
	hideFullSearch = false;
	bNoBlur = false;
	contentElement = null;
	SetStrings(TXT_NO_AIRPORTS, TOP_SECTION, BOTTOM_SECTION, TXT_FIND_PLACES, EXTRA_PARAMS, FULL_PARAMS);
}

// Called from the page
function InstallACBasic(frm, fld, sb, pn, rl, img, sf, scale, hideFull, content) {
	if (txtbox == fld && hideFullSearch == hideFull) { return; }
	UnInstall();
	if (txtbox != fld && loadingElement) { loadingElement.style.display = "none"; }
	if (contentElement) { contentElement.style.display = "none"; }
	form = frm;
	txtbox = fld;
	iatabox = sb;
	url = pn;
	if (!rl) { rl = "en"; }
	locale = urlEncodeString(rl);
	loadingElement = img;
	if (scale) { ExtraWidth = scale; }
	submitFunction = sf;
	hideFullSearch = hideFull;
	contentElement = content;
	setupSuggest();
}

function InstallAC(frm, fld, sb, pn, rl, img, sf, scale) {
	InstallACBasic(frm, fld, sb, pn, rl, img, sf, scale, false, null)
}

var commonItems = null;
function AddCommon(arr) {
	if (!commonItems)
		commonItems = [];

	commonItems.push(arr);
}

// handles document keydown
function keydown(event) {
	if (!event && window.event) {
		event = window.event;
	}
	if (event) {
		lastKeyCode = event.keyCode;
	}
}

function resize() {
	setPopupDimensions();
}

function setPopupDimensions() {
	try {
		if (popup && !contentElement) {
			popup.style.left = getPopupLeft(txtbox) + "px";
			popup.style.top = getPopupTop(txtbox) + txtbox.offsetHeight - 1 + "px";
			popup.style.width = getPopupWidth() + "px"

			if (popup.hideFrame) {
				popup.hideFrame.style.left = popup.style.left;
				popup.hideFrame.style.top = popup.style.top;
				popup.hideFrame.style.width = popup.style.width;
			}
		}
	}
	catch (ex) { }
}

function getPopupWidth() {
	return (txtbox.offsetWidth) * ExtraWidth;
}

function setupSuggest() {
	if (GetHttpObject()) { hasXml = true; }
	else { hasXml = false; }

	fullUrl = "" + url + "?hl=" + locale;

	txtbox.autocomplete = "off";
	txtbox.onblur = textboxBlur;

	if (txtbox.createTextRange) { txtbox.onkeyup = new Function("return keyup(event);"); }
	else { txtbox.onkeyup = keyup; }

	window.

	txtbox.onkeypress = function (e) {
		var key;
		if (window.event) { key = window.event.keyCode; }
		else { key = e.which; }
		return (key != keys.ENTER);
	};

	txtbox.onsubmit = closeSuggest;
	text = txtbox.value;
	lastVal = text;
	cacheResult("", 0, [], [], [], []);

	if (!popup) { createPopup(); }
	if (contentElement) { contentElement.appendChild(popup); }

	window.onresize = resize;
	document.onkeydown = keydown;
}

function createPopup() {
	popup = document.createElement("DIV");
	popup.id = "completeDiv";
	popup.className = boxClass;
	popup.style.display = "none";
	if (!contentElement) {
		popup.style.zIndex = "100";
		popup.style.position = "absolute";
		setPopupDimensions();
	}
	document.body.appendChild(popup);

	if (!contentElement && !popup.hideFrame && BrowserNeedIFrame()) {
		// IFRAME to hide dropdown lists
		hideFrame = document.createElement("IFRAME");
		hideFrame.id = "hideFrame";
		hideFrame.style.border = "0px";
		hideFrame.style.zIndex = "99";
		hideFrame.style.position = "absolute";
		hideFrame.style.display = "none";
		setPopupDimensions();
		document.body.appendChild(hideFrame);
		popup.hideFrame = hideFrame;
	}
}

function clearPopup() {
	if (popup) {
		popup.innerHTML = "";
		setPopupDimensions();
	}
}

// Hide the drop down box
function hideSuggest() {
	if (contentElement) { contentElement.style.display = "none"; }
	var box = getElement("completeDiv");
	if (box) {
		box.style.display = "none";
		if (box.hideFrame)
			box.hideFrame.style.display = "none";
	}
	isVisible = false;
}

// Show the drop down box
function showSuggest() {
	if (!isVisible) {
		if (contentElement) { contentElement.style.display = ""; }
		var box = getElement("completeDiv");
		if (box) {
			setPopupDimensions();
			box.style.display = "";
			if (box.hideFrame)
				box.hideFrame.style.display = "";
		}
		isVisible = true;
	}
}

function focusTextbox() {
	try {
		if (null != txtbox) {
			var pos = txtbox.value.length;
			if (txtbox.setSelectionRange) {
				txtbox.setSelectionRange(pos, pos);
			}
			else if (txtbox.createTextRange) {
				var textRange = txtbox.createTextRange();
				textRange.moveStart("character", pos);
				textRange.collapse();
				textRange.select();
			}
			txtbox.focus();
		}
	} catch (e) { }
}

// textbox onblur
function textboxBlur(event) {
	if (!event && window.event) { event = window.event; }
	if (bNoBlur) {
		bNoBlur = false;
		focusTextbox();
		return true;
	}
	bCheckInput = false;
	abortSuggest();
	tryCallback();
	hideSuggest();
	if (lastKeyCode == keys.TAB) {
		lastKeyCode = -1;
	}
}

// this is called onKeyup of the textbox
function keyup(e) {
	bCheckInput = true;
	setTimeout("checkInput()", 100);
	currentKeyCode = e.keyCode;
	return processKeyUp(currentKeyCode);
}

function getItemText(itm) {
	if (!itm) { return null; }
	if (itm.displayString) {
		var value = itm.displayString;
		if (itm.displayString == "&nbsp;") { return ""; }
		else { return itm.displayString; }
	}
	else { return ""; }
}

function getItemValue(itm) {
	if (!itm) { return null; }
	if (itm.valueString) { return itm.valueString; }
	else { return ""; }
}

// Save a result to the cache object
function cacheResult(itemKey, type, itemNames, itemValues, itemTypes, itemCountries) {
	var newItem = { type: type, names: itemNames, values: itemValues, types: itemTypes, countries: itemCountries };
	itemKey = itemKey.toLowerCase();
	cache[itemKey] = newItem;
}

function sendRPCDone(itemkey, searchType, itemStrings, itemValues, itemTypes, itemCountries) {
	if (activeCalls > 0)
		activeCalls--;

	cacheResult(itemkey, searchType, itemStrings, itemValues, itemTypes, itemCountries); // cache the result

	popup.displayStrings = itemStrings; // City
	popup.valueStrings = itemValues; // IATA
	popup.typeStrings = itemTypes; 	// Airport flag
	popup.countryStrings = itemCountries; 	// Country codes

	// render drop down
	render(popup, popup.displayStrings, popup.valueStrings, popup.typeStrings, popup.countryStrings);
	getSuggestRows(popup);
	if (popup.displayStrings.length > 0) {
		popup.height = (popup.offsetHeight ? popup.offsetHeight : popup.style.pixelHeight);
		if (popup.hideFrame) { popup.hideFrame.height = popup.height; }
	} else {
		hideSuggest();
	}
}

// Called when a key is pressed
function processKeyUp(keyCode) {
	var origText = text;
	text = txtbox.value;
	if (navigateList(keyCode) && keyCode != 0) {
		if (text.indexOf(origText) != 0) { clearPopup(); }
		if (iatabox) { iatabox.value = ""; }
		isKeyPressed = true;
		getSuggestRows(popup);
		return true;
	}
	return false;
}

// used close the suggest
function closeSuggest() {
	tryCallback();
	closing = true;
	hideSuggest();
	return false;
}

function tryCallback() {
	if (suggestCallback) {
		var textVal = txtbox.value;
		var iataVal = (iatabox ? iatabox.value : "");
		suggestCallback(txtbox, textVal, iataVal);
	}
}

function urlEncodeString(val) {
	if (encodeURIComponent) {
		return encodeURIComponent(val);
	}
	if (escape) {
		return escape(val)
	}
}

// Calculates the time to wait before checking if the text has changed
function getCallbackTime(num) {
	var t = 100;
	for (var i = 1; i <= (num - 2) / 2; i++) {
		t = t * 2;
	}
	t = t + 50;
	return t;
}

function getCommonItems(val) {
	if (!commonItems)
		return null;

	var names = [];
	var iatas = [];
	var types = [];
	var countries = [];
	var commonItem = null;
	var thisVal = val.toLowerCase();

	for (var i = 0, len = commonItems.length; i < len; i++) {
		var thisName = commonItems[i][0].toString().substring(0, val.length).toLowerCase();
		var thisIATA = commonItems[i][1].toString().toLowerCase();
		if (thisName == thisVal || thisIATA == thisVal) {
			names.push(commonItems[i][0]);
			iatas.push(commonItems[i][1]);
			types.push(commonItems[i][2]);
			if (commonItems[i].length > 3) { countries.push(commonItems[i][3]); }

			commonItem = { type: 0, names: names, values: iatas, types: types, countries: countries };
		}
	}
	return commonItem;
}

// this function is polled every 100 milliseconds
// once the text changes and the length exceeds three
// then make a call to the server.
function checkInput() {
	if (isMorePressed || (isKeyPressed && lastVal != text && text.length > 2)) {
		if (!closing) {
			var searchKey = text.toLowerCase();
			var searchText = urlEncodeString(searchKey);
			var cacheItem = (isMorePressed ? null : cache[searchKey]);
			if (!isMorePressed && !cacheItem)
				cacheItem = getCommonItems(text);

			var isValidCache = (!isMorePressed && cacheItem && cacheItem.type == (isFullSearch ? 1 : 0));
			if (isValidCache) {
				// cached data found so use that
				abortSuggest();
				sendRPCDone(text, cacheItem.type, cacheItem.names, cacheItem.values, cacheItem.types, cacheItem.countries);
			}
			else {
				// no cache found, make remote call
				activeCalls++;
				if (hasXml) { doQuery(searchText); }
			}
			txtbox.focus()
			txtbox.value = txtbox.value;
		}
		isMorePressed = false;
		closing = false;
	}
	lastVal = text;
	isKeyPressed = false;
	if (bCheckInput) { setTimeout("checkInput()", getCallbackTime(activeCalls)); }
	return true
};

// Called on mousedown of the div
function itemClick() {
	abortSuggest();
	textVal = getItemText(this);
	iataVal = getItemValue(this);
	updateSuggestBox(textVal, iataVal);
	closing = true;
	closeSuggest();
	focusTextbox();
};

// Called on mousedown of the more places div
function moreItemClick() {
	abortSuggest();
	if (loadingElement) { loadingElement.style.display = ""; }
	if (contentElement) { contentElement.style.display = ""; }
	strings.extraparams = strings.fullparams.replace("&amp;", "&");
	isFullSearch = true;
	isMorePressed = true;
	bNoBlur = true;
	focusTextbox();
}

// called on mouse over the div
function itemRollover() {
	if (currentItem) {
		currentItem.className = (currentItem.offCss ? currentItem.offCss : itemClass);
	}
	this.className = (this.onCss ? this.onCss : itemOverClass);
}

// called on mouseout of the div
function itemRollout() {
	this.className = (this.offCss ? this.offCss : itemClass);
}

//handles moving up and down
function setCurrentItem(index, step) {
	if (!suggestRows || rowCount <= 0)
		return;

	index += step;
	if (index >= rowCount) { index = rowCount - 1; }
	if (currentIndex != -1 && index != currentIndex) { currentIndex = -1; }

	if (index < 0) {
		currentIndex = -1;
		text = currentText;
		updateSuggestBox(currentText, "");
		if (currentItem) { currentItem.className = currentItem.offCss; }
		return;
	}

	if (suggestRows[index].itemType == 3) {
		if (rowCount > index + 1) { setCurrentItem(index, step); }
		else { currentIndex = -1; }
		return;
	}

	currentIndex = index;

	if (currentItem) { currentItem.className = currentItem.offCss; }
	currentItem = suggestRows[index];
	if (currentItem) { currentItem.className = currentItem.onCss; }

	showSuggest();

	if (currentItem.itemType < 3) {
		text = currentText;
		textVal = getItemText(currentItem);
		iataVal = getItemValue(currentItem);
		updateSuggestBox(textVal, iataVal);
	}
	else {
		text = currentText;
		updateSuggestBox(currentText, "");
	}
}

//handles UP + DOWN Keys
function navigateList(keyCode) {
	if (keyCode == keys.UP) {
		if (isVisible) { setCurrentItem(currentIndex, -1); }
		else if (rowCount > 0) { showSuggest(); }
		return false;
	} else if (keyCode == keys.DOWN) {
		if (isVisible) { setCurrentItem(currentIndex, 1); }
		else if (rowCount > 0) { showSuggest(); }
		return false;
	} else if (keyCode == keys.ENTER) {
		if (currentItem && currentItem.itemType == 4 && currentItem.func) { currentItem.func(); }
		else if (isVisible) { closeSuggest(); }
		else if (submitFunction) { UnInstall(); submitFunction(); }
		return false;
	} else if (keyCode == keys.ESC) {
		if (isVisible) { closeSuggest(); }
		return false;
	} else if (keyCode == keys.TAB) {
		return false;
	}
	return true;
}

function getSuggestRows(pop) {
	suggestRows = getSuggestItems(pop);
	rowCount = suggestRows.length;
	currentText = text;

	if (text == "" || rowCount == 0) { hideSuggest(); }
	else { showSuggest(); }

	currentIndex = -1;
	currentItem = null;
}

function getPopupLeft(elem) {
	return getPopupOffset(elem, "offsetLeft");
}

function getPopupTop(elem) {
	return getPopupOffset(elem, "offsetTop");
}

function getPopupOffset(elem, prop) {
	var val = 0;
	while (elem) {
		var doAdd = true;
		if (elem.currentStyle && elem.currentStyle.position == "absolute") { doAdd = false; }
		if (doAdd) { val += elem[prop]; }
		elem = elem.offsetParent;
	}
	return val;
}

// populates the div with headers and options
function render(itm, itemStrings, itemValues, itemTypes, itemCountries) {
	while (itm.childNodes.length > 0) { itm.removeChild(itm.childNodes[0]); }
	var header1Shown = false;
	var header2Shown = false;
	if (itemStrings.length == 0) {
		itemStrings.push(strings.noairports);
		itemValues.push("");
		itemTypes.push(3);
	}
	var maxRows = (typeof MAX_ROWS != "undefined" ? MAX_ROWS : 20);
	for (var f = 0, len = itemStrings.length; f < len && f < maxRows; ++f) {
		if (!header1Shown && (itemTypes[f] == 1 || itemTypes[f] == 3)) {
			header1Shown = true;
			var header = document.createElement("DIV");
			header.innerHTML = "<B>" + strings.topsection + "</B>";
			header.className = headerClass;
			itm.appendChild(header);
		}
		if (!header2Shown && itemTypes[f] == 0) {
			header2Shown = true;
			var header = document.createElement("DIV");
			header.innerHTML = "<B>" + strings.bottomsection + "</B>";
			header.className = headerClass;
			itm.appendChild(header);
		}

		var click = (itemTypes[f] != 3 ? itemClick : null);
		var hover = (itemTypes[f] != 3 ? itemOverClass : itemClass);
		var country = (itemCountries ? itemCountries[f] : null);
		itemDiv = createItem(itemStrings[f], itemValues[f], itemTypes[f], country, itemClass, hover, click);
		itm.appendChild(itemDiv);
	}
	if (!isFullSearch && !hideFullSearch) {
		var itemDiv = createItem(strings.findplaces, "", 4, null, moreClass, itemOverClass, moreItemClick);
		itm.appendChild(itemDiv);
	}
}

function createItem(txt, val, type, country, offCss, onCss, click) {
	var itemDiv = document.createElement("DIV");
	itemDiv.className = offCss;
	itemDiv.style.overflow = "hidden";
	itemDiv.displayString = txt;
	itemDiv.valueString = (type == 1 ? val : null);
	itemDiv.itemType = type;
	itemDiv.onCss = onCss;
	itemDiv.offCss = offCss;

	if (click != null) {
		itemDiv.onmousedown = click;
		itemDiv.func = click;
	}

	itemDiv.onmouseover = itemRollover;
	itemDiv.onmouseout = itemRollout;

	if (val && val.length > 0) {
		var displaySpan = document.createElement("SPAN");
		displaySpan.style.width = "86%";
		displaySpan.style.cssFloat = "left";
		displaySpan.style.display = "inline-block";
		displaySpan.innerHTML = txt;

		var valueSpan = document.createElement("SPAN");
		valueSpan.className = valueClass;
		valueSpan.style.width = "12%";
		valueSpan.style.cssFloat = "left";
		valueSpan.style.display = "inline-block";
		valueSpan.innerHTML = val;

		itemDiv.appendChild(displaySpan);
		itemDiv.appendChild(valueSpan);
	}
	else {
		itemDiv.innerHTML = txt;
	}
	return itemDiv;
}

// gets a reference to the xml http object
function GetHttpObject() {
	var obj = null;
	if (window.XMLHttpRequest) {
		obj = new XMLHttpRequest();
	}
	else if (window.ActiveXObject) {
		try { obj = new ActiveXObject("Msxml2.XMLHTTP"); }
		catch (e) {
			try { obj = new ActiveXObject("Microsoft.XMLHTTP"); }
			catch (oc) { obj = null; }
		}
	}
	return obj;
}

// make a request to the server
function doQuery(val) {
	abortSuggest();
	req = GetHttpObject();
	if (req) {
		if (loadingElement) { loadingElement.style.display = ""; }
		if (contentElement) { contentElement.style.display = ""; }
		req.open("GET", fullUrl + strings.extraparams + "&js=true&qu=" + val, true);
		req.onreadystatechange = function () {
			try {
				if (req.readyState == 4) {
					if (loadingElement) { loadingElement.style.display = "none"; }
					if (!req.responseText || req.responseText.charAt(0) == "<") {
						activeCalls--;
					}
					else {
						showSuggest();
						eval(req.responseText);
					}
				}
			}
			catch (ex) { }
		};
		req.send(null);
	}
}

function abortSuggest() {
	if (req && req.readyState != 0) {
		req.abort();
		req = null;
		if (loadingElement) { loadingElement.style.display = "none"; }
	}
}

function updateSuggestBox(textVal, iataVal) {
	setTextbox(textVal);
	setIata(iataVal);
}

function setTextbox(val) {
	lastVal = val;
	if (txtbox) { txtbox.value = val; }
}

function setIata(val) {
	if (iatabox) { iatabox.value = val; }
}

function getSuggestItems(pop) {
	var tempRows = [];
	arr = pop.getElementsByTagName(itemTagName);
	for (var i = 0, len = arr.length; i < len; i++) {
		if (arr[i].displayString != null)
			tempRows.push(arr[i]);
	}
	return tempRows;
}

function BrowserNeedIFrame() {
	var agent = navigator.userAgent;
	var arrNeedsFrame = ["MSIE"];
	for (var i = 0, len = arrNeedsFrame.length; i < len; i++) {
		if (agent.indexOf(arrNeedsFrame[i]) != -1) { return true; }
	}
	return false;
}

function GetItemById(id) { return (document.all ? document.all[id] : document.getElementById(id)); }

function addEvent(obj, type, fn) {
	if (obj.attachEvent) { obj.attachEvent('on' + type, fn); }
	else if (obj.addEventListener) { obj.addEventListener(type, fn, false); }
} 

