// Type Ahead JS
// Class constructor
function SHACTypeAhead(el, url, ent) {
					if ((!ent) || (ent < 2)) ent = 2;
	el.shactaObj = this;
	this.element = el; // input element
	this.timerID = null; // Timer to be used
	this.lastValue = null; // Last value when checked for text changed
	this.currentlyShowing = null; // Currently showing suggestions
	this.hasFocus = false; 
	this.preventClosing = false; // Prevent suggestion list closing when lost focus because item in list was selected
	// For items
	this.showingSuggestions = false;
	this.maxEntries = ent; // Max entries to show
	this.selectedItem = null;
	this.itemCount = 0;
	this.rangeLow = 0;
	this.rangeHigh = 0;
					this.requestUrl = url;
	
	// Constants for classes, makes it easer to change
	this.constants = {
		"selectedClass" : "selected",
		"unSelectedClass" : "unSelected",
		"scrollClass" : "scroll",
		"scrollDisabledClass" : "scroll scrollDisabled",
		"invisible" : "invisible",
		"container" : "container",
		"containerIframe" : "containerIframe",
		"suggestionsElement" : "suggestions",
		"searchedText" : "searchedText"
	};
	// Events
	el.onkeyup = function(evt) { return this.shactaObj.keyUp(evt); }
	el.onkeydown = function(evt) { return this.shactaObj.keyDown(evt); }
	el.onblur =  function(evt) { return this.shactaObj.focusLost(evt); }
	el.onfocus =  function(evt) { return this.shactaObj.focusGained(evt); }
}

// Helper functions, to construct names and HTML
SHACTypeAhead.prototype.getSuggestionElement = function(i) {
	return document.getElementById(this.element.id + "__item__" + i);
}

// ************ HTML ******************
SHACTypeAhead.prototype.constructSuggestionHTML = function(d) {
	// put searched text in a span
	// this first thing, creates a Regular expression like /mad/
	var myRegExp = new RegExp(this.currentlyShowing, 'gi'); //gi are the options for replacing everywhere and non-case sensitive
	var myLocation = d.display.replace(myRegExp
							,'<span class="' + this.constants["searchedText"] + '">' + this.currentlyShowing + '</span>');
	var myHtml = '<table width="200" border="0"><tr><td width="95%" class="selectedTA" style="font-size:9pt;"><a name="ancTypeAhead" style="text-decoration:none; cursor:pointer;">' + myLocation 
				 + '</a></td><td width="5%" class="selectedTA"><img src="/car-hire/images/flags/' + d.display.substring(d.display.length - 2,d.display.length).toUpperCase() + '.JPG"></td></tr></table>';
	return myHtml;
}

SHACTypeAhead.prototype.constructScrollHTML = function(i) {
	var ret = "";
	if (i == 1) { // go down
		ret = "&or;";
	}
	else { //go up
		ret = "&and;";
	}
	return ret;
}


// ************ EVENTS ******************


// Executes when content changed, then calls the timer to prevent multiple submissions
SHACTypeAhead.prototype.keyUp = function(evt) {
	if (!evt) evt = event;
	var kc = evt.keyCode;
					// Do not react for enter, tab, up or down. That is done in keyDown
					if ((kc != 38) && (kc != 40) && (kc != 13) && (kc != 9)) {
							this.textChanged(this.element);
	}
}
SHACTypeAhead.prototype.keyDown = function(evt) {
	if (!evt) evt = event;
	var kc = evt.keyCode;
	// Check key code 
	switch (kc){
		case 38: this.goUp(); return false; break;
		case 40: this.goDown(); return false; break;
		case 13: case 9:
			if (this.showingSuggestions) {
				this.chooseSuggestion(this.selectedItem);
				return false;
			}
			else return true;
		break;
	}
}
// Focus - related events
SHACTypeAhead.prototype.focusLost = function(evt) {
	// If lost focus because user clicked on the suggestion box, don't close it
	if (this.preventClosing) {
		this.preventClosing = false;
	}
	else {
		this.hasFocus = false;
		this.deleteSuggestionBox();
	}
}
SHACTypeAhead.prototype.focusGained = function(evt) {
	this.hasFocus = true;
}

// Executes when content changed, then calls the timer to prevent multiple submissions
SHACTypeAhead.prototype.textChanged = function(el) {
	var el = this.element;
	var val = el.value;
	if (val == "") {
							if (this.timerID) clearTimeout(this.timerID);
							this.deleteSuggestionBox();
							return;
					}
	if (val != this.lastValue) {
		// Clear timeout if called
		this.lastValue = val;
		if (this.timerID) clearTimeout(this.timerID);
		this.timerID = setTimeout( "document.getElementById('" + el.id + "').shactaObj.getSuggestions();", 500);
	}
}

// ************ FUNCTIONS ******************
			SHACTypeAhead.prototype.returnFocusToInput = function() {
					document.getElementById(this.element.id).focus();
					var el = this.element;
					// IE looses selection, position, so reposition at the end of the input
					if(el.createTextRange) { 
							var range = el.createTextRange(); 
							range.move("character", el.value.length); 
							range.select(); 
					}                         
			}

// Calls the server if it's not the same that already is showing
SHACTypeAhead.prototype.getSuggestions = function() {
	var el = this.element;
	// Don't try to get empty string
	if (el.value == "") {
							this.deleteSuggestionBox();
							return;
					}
	if (el.value != this.currentlyShowing) {
		// Get httprequest object - different for IE and mozilla
		var req = null;
		try { req = new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) {}
		if (! req) try { req = new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) {}
	if (! req) try { req = new XMLHttpRequest(); } catch(e) {}
		if (! req) {
			alert("Your Browser Doesnt support this functionality");
			return;
		}
		// Get the data page in an asynchronous call
		req.open("GET", this.requestUrl + "?name=" + el.value, true);
		el.shactaObj.requestObject = null;
		req.onreadystatechange = function() {
			onSumResponse(el.id);
		}
		try{el.shactaObj.requestObject = req;} catch(e) {};
		req.send(null);
		// Remember request object
	}
}

SHACTypeAhead.prototype.showSuggestions = function(data) {
	var elementId = this.element.id;
					// Dont show if there is no focus
					if (! this.hasFocus) return;
	// If no data, hide suggestions if available 
	if (data.total == 0) {
		this.deleteSuggestionBox();
	}
	else { // There is data!
							// Don't show if value changed
							if (data.search != this.element.value) return;
							this.currentlyShowing = data.search;
		// Create the suggestions element if it doesn't exist already
		this.showingSuggestions = true;
		var container = document.getElementById(this.element.id + "__container");
		var created = false;
		if (container) {
			// Make container visible
			document.getElementById(this.element.id + "__container").innerHTML = "";
			container.className = this.constants["container"]; 
		}
		else {
			container = document.createElement("div");
			container.id = this.element.id + "__container";
			container.className = this.constants["container"]; 
			created = true;
			container.onmousedown = function() {
				document.getElementById(elementId).shactaObj.preventClosing = true;
				// Prevent deleting suggestion box when clicking here
			}
			
		}
		// Also an iframe is needed for IE 6 bug
		var containerIframe = document.getElementById(this.element.id + "__containerIframe");
		if (!containerIframe) {
			containerIframe = document.createElement("iframe");
			containerIframe.id = this.element.id + "__containerIframe";
		}
		containerIframe.className = "containerIframe";
		// Element for scrolling up
		var scrollEl = document.createElement("div");
		scrollEl.id = this.element.id + "__scrollup";
		scrollEl.className = this.constants["scrollDisabledClass"];
		scrollEl.innerHTML = this.constructScrollHTML(-1);
		scrollEl.onclick = function() { 
			document.getElementById(elementId).shactaObj.scrollUp();
			document.getElementById(elementId).shactaObj.returnFocusToInput();
			//document.getElementById(elementId).focus();
		}
		container.appendChild(scrollEl);
		
		// Add elements inside
		var i = 0;
		var arrayValues = data["data"];
		while(arrayValues[i]){
			var newDiv = document.createElement("div");
			newDiv.innerHTML = this.constructSuggestionHTML(arrayValues[i]);
			newDiv.id = this.element.id + "__item__" + i;
			if (i == 0) {
				newDiv.className = this.constants["selectedClass"];
			}
			else {
				newDiv.className = this.constants["unSelectedClass"];
			}
			// If it doesn't fit on the range, make it invisible
			if (i >= this.maxEntries) {
				newDiv.className += " " + this.constants["invisible"];
			}
			// Save text in div attribute
			newDiv.shactaText = arrayValues[i].display
			
			newDiv.onclick = function() {
				document.getElementById(elementId).shactaObj.chooseSuggestion( this.id.split("__")[2] );
				document.getElementById(elementId).shactaObj.returnFocusToInput();
				//document.getElementById(elementId).focus();
			}
			container.appendChild(newDiv);
			i++;
		}
		
		// Element for scrolling down
		scrollEl = document.createElement("div");
		scrollEl.id = this.element.id + "__scrolldown";
		// Visible if more items than max entry
		if (i > this.maxEntries) {
			scrollEl.className = this.constants["scrollClass"];
		}
		else {
			scrollEl.className = this.constants["scrollDisabledClass"];
		}
		scrollEl.innerHTML = this.constructScrollHTML(1);
		scrollEl.onclick = function() { 
			document.getElementById(elementId).shactaObj.scrollDown();
									document.getElementById(elementId).shactaObj.returnFocusToInput();
		}
		container.appendChild(scrollEl);
		// Update selected item, total and range
		this.selectedItem = 0;
		this.itemCount = i;
		this.rangeLow = 0;
		if (this.itemCount > this.maxEntries) {
			this.rangeHigh = this.maxEntries - 1;
		}
		else {
			this.rangeHigh = this.itemCount - 1;
		}
		// Attach container
		if (created) {
			document.body.appendChild(containerIframe);
			document.body.appendChild(container);
		}
		// Get positions for suggestions div
		var top = 0;
		var left = 0;
		var obj = this.element;
		// Get cross-browser left & top
		if (obj.offsetParent) {
			left += obj.offsetLeft
			top += obj.offsetTop
			while (obj = obj.offsetParent) {
				left += obj.offsetLeft
				top += obj.offsetTop
			}
		}
		containerIframe.style.display = "none";
		container.style.top = (top + this.element.offsetHeight) +  "px";
		containerIframe.style.top = (top + this.element.offsetHeight) +  "px";
		container.style.left = left + "px";
		containerIframe.style.left = left + "px";
							var width = container.offsetWidth;
		// If width is lesser than input box, adjust width to that size
		if (container.offsetWidth < this.element.offsetWidth) {
									width = this.element.offsetWidth;
		} // If width is lesser than input box
							for(i = 0; i < container.childNodes.length;i++){
									// The "-2" is because of borders, not being considered in width
									container.childNodes[i].style.width = (width - 2) + "px";
							}
		containerIframe.style.width = (container.offsetWidth - 2 ) + "px";
		containerIframe.style.height = (container.offsetHeight - 2 ) + "px";
		containerIframe.style.display = "block";
		
	} // If there is data
}

// Delete suggestion box and its content
SHACTypeAhead.prototype.deleteSuggestionBox = function() {
					this.lastValue = null;
	this.selectedItem = null;
	this.itemCount = 0;
	this.showingSuggestions = false;
					this.currentlyShowing = null;
	var container = document.getElementById(this.element.id + "__container");
	if (container) {
		container.parentNode.removeChild(container);
	}
	var containerIframe = document.getElementById(this.element.id + "__containerIframe");
	if (containerIframe) {
		containerIframe.parentNode.removeChild(containerIframe);
	}
}

// Functions for moving UP and DOWN on the selected list
SHACTypeAhead.prototype.goUp = function(){
	// if suggestions box not showing, then show it (if available)
	if (!this.showingSuggestions) {
		var container = document.getElementById(this.element.id + "__container");
		if (container) {
			container.className = this.constants["container"]; 
			this.showingSuggestions = true;
		}
		return;
	}
	// Select previous item (do nothing if currently on first)
	if (this.selectedItem == 0) return;
	if (this.selectedItem == this.rangeLow) this.scrollUp();
	this.getSuggestionElement(this.selectedItem).className = this.constants["unSelectedClass"];
	this.selectedItem --;
	this.getSuggestionElement(this.selectedItem).className = this.constants["selectedClass"];
}
SHACTypeAhead.prototype.goDown = function(){
	if (!this.showingSuggestions) {
		var container = document.getElementById(this.element.id + "__container");
		if (container) {
			container.className = this.constants["container"]; 
			this.showingSuggestions = true;
		}
		return;
	}
	if (!this.showingSuggestions) return;
	if (this.selectedItem == (this.itemCount - 1)) return;
	if (this.selectedItem == this.rangeHigh) this.scrollDown();
	this.getSuggestionElement(this.selectedItem).className = this.constants["unSelectedClass"];
	this.selectedItem++;
	this.getSuggestionElement(this.selectedItem).className = this.constants["selectedClass"];
}			

// For selecting an item (showing its text)
SHACTypeAhead.prototype.chooseSuggestion = function(i) {
		// Select the item if not selected yet
		if (i != this.selectedItem) {
			this.getSuggestionElement(this.selectedItem).className = this.constants["unSelectedClass"];
			this.selectedItem = i;
			this.getSuggestionElement(this.selectedItem).className = this.constants["selectedClass"];
		}
		// Get its text and show it 
		var text = this.getSelectedText();
		//just show the location only - do not include country nor city
		if(text.lastIndexOf('[')==-1)
			text = text.substring(text.indexOf(',') + 1, text.lastIndexOf(','));
		else
			text = text.substring(text.indexOf(',') + 1, text.lastIndexOf('['));
							
		this.element.value = text;
		
		// Allow the window to set the Country if necessary 
		if (window.SetCountry) {
			var fulltext = this.getSelectedText();
			window.SetCountry(fulltext.substring(fulltext.lastIndexOf(',') + 1,fulltext.length));
		}
		
		if (window.SetLocation) {
			window.SetLocation(text);
		}
		
		this.deleteSuggestionBox();
}

// Returns text from selected suggestion item
SHACTypeAhead.prototype.getSelectedText = function () {
	return this.getSuggestionElement(this.selectedItem).shactaText;
}
// Scrolling functions
SHACTypeAhead.prototype.scrollUp = function () {
	if (this.rangeLow == 0) return; // If at the beginning, don't scroll anymore
	// Show 1 item, hide 1 item
	this.getSuggestionElement(this.rangeLow - 1).className = this.constants["unSelectedClass"];
	this.getSuggestionElement(this.rangeHigh).className = this.constants["unSelectedClass"] + " " + this.constants["invisible"];
	// If item hidden was the selected one, select next
	if (this.selectedItem == this.rangeHigh){
		this.selectedItem --;
		this.getSuggestionElement(this.selectedItem).className = this.constants["selectedClass"];
	}
	// Regenerate ranges, check if scrolling divs should be hidden
	this.rangeLow--;
	this.rangeHigh--;
	if (this.rangeLow == 0) {
		document.getElementById(this.element.id + "__scrollup").className = this.constants["scrollDisabledClass"];
	}
	if (this.rangeHigh == (this.itemCount - 2)) {
		document.getElementById(this.element.id + "__scrolldown").className = this.constants["scrollClass"];
	}
}
SHACTypeAhead.prototype.scrollDown = function () {
	if (this.rangeHigh == (this.itemCount - 1)) return; // Dont scroll more
	// Show 1 item, hide 1 item
	this.getSuggestionElement(this.rangeHigh + 1).className = this.constants["unSelectedClass"];
	this.getSuggestionElement(this.rangeLow).className = this.constants["unSelectedClass"] + " " + this.constants["invisible"];
	// If item hidden was the selected one, select next
	if (this.selectedItem == this.rangeLow){
		this.selectedItem ++;
		this.getSuggestionElement(this.selectedItem).className = this.constants["selectedClass"];
	}
	// Regenerate ranges, check if scrolling divs should be hidden
	this.rangeLow++;
	this.rangeHigh++;
	if (this.rangeHigh == (this.itemCount - 1)) {
		document.getElementById(this.element.id + "__scrolldown").className = this.constants["scrollDisabledClass"];
	}
	if (this.rangeLow == 1) {
		document.getElementById(this.element.id + "__scrollup").className = this.constants["scrollClass"];
	}
	
}

// Checks when there's an AJAX response. Calls showSuggestions if needed
function onSumResponse(id) {
	var el = document.getElementById(id);
	var shacta = el.shactaObj;
	var req = shacta.requestObject;
	if ((! req) || (! req.readyState) || (req.readyState != 4)) return;
	var serverResponse = req.responseText;
	//alert(serverResponse);
	shacta.showSuggestions(eval(serverResponse));
}

	// DELETE! ONLY FOR DEBUG USE
function DEBUG(v) {
		document.getElementById("debug").innerHTML += v + "<br>";
}
