/**
* (c) Viatecla 2009
* Based on code by:
* Natalia Bazhenova - http://www.fh54.de/input_suggest
*/

function addLocationSuggest(inputControlId, searchServiceUrl, keyInputControlId, planeImageUrl, worldImageUrl, cityImageUrl){
    new LocationSuggest(inputControlId, searchServiceUrl, keyInputControlId, planeImageUrl, worldImageUrl, cityImageUrl);
}
    
function LocationSuggest(inputControlId, searchServiceUrl, keyInputControlId, planeImageUrl, worldImageUrl, cityImageUrl) {
    this._suggestBoxList = null;
    this._suggestBoxList = document.createElement("div");
	if (this._suggestBoxList == null || this._suggestBoxList == false) //otherwise nothing happens
	     return;
    
    this._searchServiceUrl = searchServiceUrl;
    
    this._selectedLocationIndex = -1;
    this._locationsArray = null;
    this._inputControl = null; //the main input text element
    this._keyInputControl = null;
    this._searchString = "";
    this._suggestBoxStyle = "suggestBox";
    this._itemImageStyle = "itemImage";
    this._suggestBoxItemStyle = "suggestBoxItem";
    this._suggestBoxSelectedItemStyle = "suggestBoxSelectedItem";
    this._suggestBoxItemTextStyle = "suggestBoxItemText";
    this._iFrameHelperStyle = "iframeHelper";
    this._itemPadding = 10;
    this._searchCache = {};
    this._countryStartSeparator = "{";
    this._countryEndSeparator = "}";
    

    if(planeImageUrl != null)
        this._planeImageUrl = planeImageUrl;
    else 
        this._planeImageUrl = "/LocationSuggest/Common/images/plane.png";
    
    if(worldImageUrl != null)  
        this._worldImageUrl = worldImageUrl;
    else
        this._worldImageUrl = "/LocationSuggest/Common/images/world.png";
    
    if(cityImageUrl)
        this._cityImageUrl = cityImageUrl;
    else
        this._cityImageUrl = "/LocationSuggest/Common/images/city.png";
    
	//main input control
	this._inputControl = document.getElementById(inputControlId);
	if(this._inputControl == null)
	    this._inputControl = document.getElementsByName(inputControlId)[0];

	//hidden input control
	if(keyInputControlId){
	    this._keyInputControl = document.getElementById(keyInputControlId);
	    if(this._keyInputControl == null)
	        this._keyInputControl = document.getElementsByName(keyInputControlId)[0];
	}

	this._inputControl.setAttribute("autocomplete", "Off");	
	this._inputControl.onkeydown = this.CreateDelegate(this.OnInputControlKeyDown);
	this._inputControl.onkeyup = this.CreateDelegate(this.OnInputControlKeyUp);
	this._inputControl.onblur  = this.CreateDelegate(this.OnInputControlBlur);
    
    //Helper iframe
    this._frame = document.createElement("iframe");
	this._frame.className = this._iFrameHelperStyle;
	this._frame.style.display = "none";
	document.body.appendChild(this._frame);
	
    this._suggestBoxList.className = this._suggestBoxStyle;
	this._suggestBoxList.style.display = "none";	
	document.body.appendChild(this._suggestBoxList);
	
	//keeps the previous subscrived methods
	this.old = (window.onresize) ? window.onresize : function () {};
	window.onresize = this.CreateDelegate(function () {this.old(); this.RepositionSuggestBox();});
	
	this.RepositionSuggestBox();
} 


LocationSuggest.prototype = {
    PositionIFrame : function (div, frm){
	    //var div = document.getElementById(divid);
	    //var frm = document.getElementById(frmid);
	    frm.style.left = div.style.left;
	    frm.style.top = div.style.top;
	    frm.style.height = div.offsetHeight + "px";
	    frm.style.width = div.offsetWidth + "px";
	    frm.style.display = "";
    },

    
    CreateDelegate: function(method){
        var _instance = this;
        return function() { return method.apply(_instance, arguments); }
    },
    
    RepositionSuggestBox : function(){
    	//find coords where the suggest box will appear    	
	    var pos2 = this.FindPos(this._inputControl);
	    pos2.push(this._inputControl.offsetHeight);
	    //pos2.push(this._inputControl.offsetWidth);
    	
	    this._suggestBoxList.style.top = (pos2[1] + pos2[2]) + 'px';
	    this._suggestBoxList.style.left = pos2[0] + 'px';
	    
	    this.PositionIFrame(this._suggestBoxList, this._frame);
    },
    
    OnInputControlBlur : function(e)
    {
        this.HideSuggestBox(); 
    },
    
    OnInputControlKeyDown : function(e){
    		if (!e) 
		    e = window.event;
		    
	    if (e.keyCode == 40){ // down arrow
    	    this.HighlightNext();
	    }
	    else if(e.keyCode == 38){ 	//Up arrow
	        this.HighlightPrevious();
	    }
	    //else if(e.keyCode == 37 || e.keyCode == 39){ //Left or right arrow
        //}
	    else if(e.keyCode == 27){ //ESC key
            this.HideSuggestBox();
	        	    
    	    e.cancelBubble = true;
	        if (e.stopPropagation) e.stopPropagation();
	        if (e.preventDefault) e.preventDefault();
	        else e.returnValue = false;
	    }
	    else if(e.keyCode == 13){ //Enter key
            this.SelectItem();
            
    	    e.cancelBubble = true;
	        if (e.stopPropagation) e.stopPropagation();
	        if (e.preventDefault) e.preventDefault();
            else e.returnValue = false;
	    }
	    else if(e.keyCode == 9){ //TAB key
            this.SelectItem();
	    }
    },
    
    OnInputControlKeyUp : function(e){
		if (!e) 
		    e = window.event;
            
		var item = e.target;
		if(!item)
		    item = e.srcElement;
		
		if(item.value == "" ){
		    this.HideSuggestBox();
            this.ClearSuggestBox();
		}
		else if((item.value != this._searchString)){
		    if(this._keyInputControl)
		        this._keyInputControl.value = '';
		    this.Search(item.value,item);
		}
    },

    ClearSuggestBox : function() {
        //Clears all child nodes
        while (this._suggestBoxList.childNodes[0])
            this._suggestBoxList.removeChild(this._suggestBoxList.childNodes[0]);        
    },
    
    HideSuggestBox : function() {
        this.RemoveCurrentHighlight();
	    this._suggestBoxList.style.display = "none";
	    this._selectedLocationIndex = -1;
	    this._searchString = this._inputControl.value;
	    
	    
	    this._frame.style.display = "none";
    },

    ShowSuggestBox : function() {
        this.ClearSuggestBox();
		this._suggestBoxList.style.display = "none";
        this._frame.style.display = "none";
                    
	    if (this._locationsArray == null || this._locationsArray.length == 0)
            return;
    	
	    for(i = 0 ; i < this._locationsArray.length ; i++) {

            var level = this._locationsArray[i][0];        
            var root = document.createElement("div");
     
            root.className = this._suggestBoxItemStyle;
		    root.onmouseover = this.CreateDelegate(this.OnSuggestBoxMouseOver);
		    root.onmousedown = this.CreateDelegate(this.OnMouseDown);
            
            var country = this._locationsArray[i][4];
            var location = this._locationsArray[i][3];

		    var imageControl = this.CreateImageControl(this._locationsArray[i][1], level);
            root.appendChild(imageControl);
            
            location = location.replace(
	            new RegExp(this._searchString, 'ig'),
	            function(q) { return "<em>" + q + "</em>"; }
	        );
    	    	    
            var d2 = document.createElement("div");
            d2.className = this._suggestBoxItemTextStyle;           
		    d2.style.cssText = "padding-left:" + (level * this._itemPadding) + "px";
            
            var locationDiv = document.createElement("div");
            locationDiv.innerHTML = location;
            d2.appendChild(locationDiv);
            
            if(country != ""){
                var countryDiv = document.createElement("small");
                countryDiv.innerHTML = country;
                d2.appendChild(countryDiv);
    		}
    		
		    root.appendChild(d2);
    		
		    this._suggestBoxList.appendChild(root);
	    }
    	
		var windowWidth = document.documentElement.clientWidth;
        this._selectedLocationIndex = -1;
	    this._suggestBoxList.style.display = "";
		
		this.PositionIFrame(this._suggestBoxList, this._frame);
		
		//if IE then resize event is triggered, if not and if the window width has changed, force suggestBox reposition
		if(windowWidth != document.documentElement.clientWidth)
			this.RepositionSuggestBox();
    },
    
    OnMouseDown : function(e){
        if (!e) 
		    e = window.event;
        
        if(this.IsItemClickable(this._selectedLocationIndex))
    	    this.SelectItem();
        else{
            e.cancelBubble = true;
	        if (e.stopPropagation) e.stopPropagation();
	        if (e.preventDefault) e.preventDefault();
            else e.returnValue = false;  
        }        
    },
     
    CreateImageControl : function(imageType, padding){
        var image = document.createElement("img");

        var url = imageType == "TP" ? this._planeImageUrl : imageType == "CI" ? this._cityImageUrl : this._worldImageUrl;
        image.style.cssText = "padding-left:" + (padding * this._itemPadding) + "px";
        image.className = this._itemImageStyle;           
            
        image.setAttribute("src", url);
        return image;
    },
     
    // Source: http://www.quirksmode.org/js/findpos.html
    FindPos : function(obj) {
	    var curleft = curtop = 0;
	    if (obj.offsetParent) {
		    curleft = obj.offsetLeft
		    curtop = obj.offsetTop
		    while (obj = obj.offsetParent) {
			    curleft += obj.offsetLeft
			    curtop += obj.offsetTop
		    }
	    } 
	    return [curleft,curtop];
    }, 

    ProcessLocations : function(citiesString){
        if(citiesString == null || citiesString == "")
            return null;
            
        var locationsArray = citiesString.split("|");
        var array = new Array();
        
        for(i = 0; i < locationsArray.length; i++)
        {
    	    if(locationsArray[i] == "" || locationsArray[i] == " ")
	            continue;
    	    
            var location = new Array();
            j = -1;
            while(locationsArray[i].charAt(++j) == "-");
            
            location[0] = locationsArray[i].substring(0, j).length;
            location[1] = locationsArray[i].substring(j, j + 2);
            location[2] = locationsArray[i].substring(j + 2, j + 3) == 1;
            location[3] = this.GetLocationWithIataToUpper(this.CapitalizeText(this.GetLocationWithoutCountry(locationsArray[i].substring(j + 3))));
            location[4] = this.GetCountryFromLocation(locationsArray[i].substring(j + 3))
            
            array.push(location);
        }
        
        return array;
    },
     
    IsItemClickable : function(index){
        return this._locationsArray[index][2];
    },
    
    Search : function(searchString,poItem){ 
        this._searchString = searchString;
            
        var result = this._searchCache[searchString];
        if(result){
            this._locationsArray = this.ProcessLocations(result);
            this.ShowSuggestBox();
            return;
        }
            
        var xhr; 
        
        try {  xhr = new ActiveXObject('Msxml2.XMLHTTP'); }
        catch (e) 
        {
            try {   xhr = new ActiveXObject('Microsoft.XMLHTTP'); }
            catch (e2) 
            {
              try {  xhr = new XMLHttpRequest();     }
              catch (e3) {  xhr = false;   }
            }
         }
      
        xhr.onreadystatechange = this.CreateDelegate(function(){  
            if(xhr.readyState == 4){
                if(xhr.status == 200){ 
                    //this._searchCache[this._searchString] = xhr.responseText;
                    this._searchCache[searchString] = xhr.responseText;
                    if( poItem.value == searchString){
                      this._locationsArray = this.ProcessLocations(xhr.responseText);
                      this.ShowSuggestBox(); 
                    }
                }
        //else 
        //    document.getElementById(id).value = "Error code " + xhr.status;
            }
        }); 
        
        xhr.open("GET", this._searchServiceUrl + encodeURI(searchString),  true); 
        xhr.send(null); 
    },
     
    OnSuggestBoxMouseOver : function(e) {
     	if (!e)
     	    e = window.event;
    	
        var item = e.target;
        if(!item)
            item = e.srcElement;

        var index = this.GetLocationIndex(item);
        if(index != -1)
            this.HighlightItem(index); 
        
        //Prevents event bubbling   
        e.cancelBubble = true;
        if (e.stopPropagation) e.stopPropagation();
        if (e.preventDefault) e.preventDefault();
        else e.returnValue = false;  

    },
     
    CapitalizeText : function(text){
        var names = text.toLowerCase(text).split(" ");
        var newText = "";
        var i = 0;
        for(i = 0; i < names.length; i++){
            newText += names[i].substring(0,1).toUpperCase() + names[i].substring(1,names[i].length) + ((i == names.length-1) ? '' : ' ');
        }
        
        return newText;
    },
 
    GetCountryFromLocation : function(location){
        var start = location.lastIndexOf(this._countryStartSeparator) + 1;
        if(start == 0)
            return "";
            
         var end = location.lastIndexOf(this._countryEndSeparator);
         end = end == -1 ? location.length -1 : end;
         return location.substring(start, end);
    },
 
    GetLocationWithoutCountry : function(location){
        var end = location.lastIndexOf(this._countryStartSeparator);
        end = end == -1 ? location.length : end;
        
        return location.substring(0, end);
    },
    
     GetLocationWithIataToUpper : function(location){
    ///Return the location with the IATA code in upper case
        var index = location.lastIndexOf("(");
        if (index == -1)
            return location;
            
        return location.substring(0, index) + location.substring(index).toUpperCase();
        
    },
    
    GetLocationWithoutIata : function(location){
    ///Return the location without the IATA code
        var index = location.lastIndexOf("(");
        if (index == -1)
            return location;
            
        return location.substring(0, index - 1);
        
    },
    
    GetIataFromLocation : function(location){
    ///Return IATA code from the location string
        var index = location.lastIndexOf("(");
        if (index == -1)
            return location;
            
        return location.substring(index + 1, location.length - 1);
    },
    
    SelectItem : function(){
        if(this._locationsArray == null || this._selectedLocationIndex == -1)
            return;
        
        this._inputControl.value = this.GetLocationWithoutIata(this._locationsArray[this._selectedLocationIndex][3]);

        if(this._keyInputControl)
            this._keyInputControl.value = this.GetIataFromLocation(this._locationsArray[this._selectedLocationIndex][3]);
        
        this.HideSuggestBox();
    },
 
    HighlightNext : function(){
        if (this._suggestBoxList.childNodes.length == 0)
            return;

        this._suggestBoxList.style.display = "";

        var nextItem = this.GetNextItem(this._selectedLocationIndex);
        while(nextItem != -1 && !this.IsItemClickable(nextItem))
            nextItem = this.GetNextItem(nextItem);
            
        this.HighlightItem(nextItem);
    },
 
    HighlightPrevious : function(){
        if (this._suggestBoxList.childNodes.length == 0)
            return;

        this._suggestBoxList.style.display = "";
        
        var previousItem = this.GetPreviousItem(this._selectedLocationIndex);
        while(previousItem != -1 && !this.IsItemClickable(previousItem))
            previousItem = this.GetPreviousItem(previousItem);
            
        this.HighlightItem(previousItem);
    },
     
    GetPreviousItem : function(itemIndex){
        if(itemIndex <= -1)
            return this._suggestBoxList.childNodes.length - 1;
        else
            return itemIndex - 1;
    },
    
    GetNextItem : function(itemIndex){
        if(itemIndex >= this._suggestBoxList.childNodes.length - 1)
            return -1;
        else
            return itemIndex + 1;
    },
 
    HighlightItem : function(newSelectionIndex){
        if(this._selectedLocationIndex == newSelectionIndex)
            return;
            
        this.RemoveCurrentHighlight();
        
        if(newSelectionIndex != -1 && this.IsItemClickable(newSelectionIndex)){
            this._suggestBoxList.childNodes[newSelectionIndex].className = this._suggestBoxSelectedItemStyle;
        }
        this._selectedLocationIndex = newSelectionIndex;
    },
        
    RemoveCurrentHighlight : function(){
        if(this._selectedLocationIndex != -1)
            this._suggestBoxList.childNodes[this._selectedLocationIndex].className = this._suggestBoxItemStyle;
    },
 
    GetLocationIndex : function(divElement){
        for(var i = 0; i < this._suggestBoxList.childNodes.length; i++)
            if(this._suggestBoxList.childNodes[i] == divElement)
                return i;
            
        return -1;
    }
}
