var keywordsRequest; // XMLHttpRequest

var KEYWORD_LENGTH=3; // Minimum chars before auto completion
var AUTOCOMPLETE_MAX = 10;
var VARIANT_NO_AIRPORTS=true;

var KEY_ENTER= 13;
var KEY_ESC  = 27;
var KEY_LEFT = 37;
var KEY_UP   = 38;
var KEY_RIGHT= 39;
var KEY_DOWN = 40;
var KEY_F1   = 112;
var KEY_PLUS = 43;
var KEY_MINUS= 45;
var KEY_DELETE = 46;
var KEY_BACKSPACE = 8;
var KEY_TAB = 9;

var DB_TYPE_CODE = 1;
var DB_TYPE_AIRPORT = 2;
var DB_TYPE_CITY = 3;

function SetVariant(val) {
    VARIANT_NO_AIRPORTS = val;
}

//--------------------------------------------
//   UI Events and Inputs
//
//--------------------------------------------
function SetInputFilter(input, filterFunc) {
//    var input  = document.getElementById(id);
    if (!input) {
        alert("Error(SetInputFilter): no such element : "+input);
        return;
    }

    return new InputFilter(input, filterFunc);
}

function InputFilter(input, filterFunc) {
    this.filterFunc = filterFunc;
    this.attachedInput = input;

//    input.onkeyup = this.filter.bind2(this, true);
    input.onkeypress = this.filterKeys.bind(this);
//    input.onkeypress = new Function("return keypressed()");
    input.onblur  = this.filterBlur.bind2(this, false);
}

// InputFilter member functions
InputFilter.prototype.filterBlur = function(infocus) {
    this.filterFunc(this.attachedInput, infocus);
};

InputFilter.prototype.filterKeys = function(evt) {
    if (!evt) {
        if (event)
            evt = event;
    }

    var ret = this.filterFunc(this.attachedInput, evt);

    try {
        evt.returnValue = ret;
    } catch(e) {
    }

    return ret;
};


//--------------------------------------------
//   Autocompletion Object
//
// ac_name: Name/Id of the input element for auto complete.
// func:    Function which returns the current set of matches
// trigger: Function to be called when the user selects something
// args:    User defined
//--------------------------------------------
function AutoComplete(input, func, trigger, args) {
    try {
//        var input = document.getElementById(ac_name);
        if (!input) {
            alert("Error(AutoComplete): no such element : "+input);
            return;
        }

        input.value = '';

        // Create the auto completion table
        var display = document.createElement('table');
        var tbody = document.createElement('tbody');
        var tr = document.createElement('tr');
        var td = document.createElement('td');
        
        display.appendChild(tbody);
        tbody.appendChild(tr);
        tr.appendChild(td);
        
        // Setup the auto completion table
        display.style.visibility = 'hidden';
        display.style.position   = 'absolute';
        display.style.top        = '0px';
        display.style.left       = '0px';
        display.style.margin     = '0px';
        display.style.zIndex     = 1000;
        display.border           = '0px';
        display.cellPadding      = '0px';
        display.cellSpacing      = '3px';
        display.className        = 'autocomplete';
        display.id               = 'autocomplete';
        display.onfocus          = displayFocused;

        document.body.appendChild(display);
        
        this.input = input;
        this.display = display;
        this.args = args;
        this.func = func;
        this.selected = 0;
        this.trigger = trigger;

        this.active  = false;

        this.objid = 1;
        
        display.my_children = new Array;
        
        var x = findPosX(input);
        var y = findPosY(input) + input.offsetHeight + 1;
        
        display.style.left = x+'px';
        display.style.top = y+'px';
        
        input.onkeyup = this.keypressed.bind(this);
        input.onblur  = this.blurred.bind(this);
        input.onfocus  = this.focused.bind(this);
    } catch(e) {
        alert("AutoComplete failed: "+e.message);
        return null;
    }
        
    return this;
}

// AutoComplete member functions
AutoComplete.prototype.clear = function() {
    this.clearDisplay();
    this.input.value = '';
    this.input.info = null;
};

AutoComplete.prototype.selection = function() {
    return this.input.info;
};

AutoComplete.prototype.setFocus = function() {
    this.active = true;
    setTimeout(this.setFocusInternal.bind(this), 200);
};

AutoComplete.prototype.setFocusInternal = function() {
    this.input.focus();
    this.input.select();
};


AutoComplete.prototype.highlight = function(idx) {
    var ac = this;
    var cnt = ac.display.my_children.length;

    idx = parseInt(idx);

    // make sure idx is sane
    idx = (idx+cnt) % cnt;

    for (var i=0; i<ac.display.my_children.length; i++) {
        if (idx == i) {
            ac.display.my_children[i].className = "autocomplete_highlight";
        } else {
            ac.display.my_children[i].className = "";
        }
    }

    // Save the new element
    ac.selected = idx;
    ac.matchValue = ac.display.my_children[idx].matchDisplay;
    ac.input.info = ac.display.my_children[idx].matchInfo;
}

AutoComplete.prototype.keypressed  = function(e) {
    e = (e)?e:((event)?event:null);
    if (!e)
        return;

    try {
        return this.keypressed1(e);
    } catch(err) {
//        alert("Error Caught in ac_keypressed: "+err.message);
    }
}

function displayFocused() {
//    alert('Display Focused');
}

AutoComplete.prototype.blurred     = function(e) {
    var ac = this;
    if (ac.matchValue) {
        ac.input.value = ac.matchValue;
        ac.trigger();
    }

    this.active = false;    
    setTimeout(this.clearDisplay.bind(this), 200);
};

AutoComplete.prototype.focused     = function(e) {
    this.active = true;
    this.input.select();
};

// Request loading the autocompletion list for a given keyword
AutoComplete.prototype.loadkeywords = function(url, keyword) {
    var req;
    var ac = this;

    var oldkey = this.currentKeyword;
    var newkey = keyword;

    var ol = oldkey?oldkey.length:0;
    var nl = newkey.length;

    if (oldkey && ol <= nl && oldkey == newkey.substring(0, ol)) {
//        alert(this.currentKeyword);
//        this.currentKeyword = newkey;
        this.update(this.currentMatches, newkey);

        return req;
    }


    try {
        req = new ActiveXObject("Msxml2.XMLHTTP");
    } catch (e) {
        try {
            req = new ActiveXObject("Microsoft.XMLHTTP");
        } catch (E) {
            req = false;
        }
    }
    if (!req && typeof XMLHttpRequest!='undefined') {
        req = new XMLHttpRequest();
    }    

    if(req) {
        this.keywordsRequest = req;
        this.requestedKeyword = keyword;
		req.onreadystatechange = ac.keywordsLoaded.bind(ac);

        // To fix permission problem when URL domain in 
        // location bar is not the same as the URL in
        // <base> tag

        if (htmlBase)
            url = htmlBase + url;

        //alert(url);
        //alert(encodeURI(url));
		req.open("GET", encodeURI(url), true);
		req.send("");
	}

    return req;
}

// Callback when the keyword list has been loaded.
AutoComplete.prototype.keywordsLoaded = function() {
    var dbreq = this.keywordsRequest;
    var xmldoc;

    // only if req shows "loaded"
    if (dbreq.readyState == 4) {
        if (dbreq.status == 0 || 
            dbreq.status == 200) {
            xmldoc = dbreq.responseXML;
         } else {
            alert("There was a problem retrieving the XML data:\n" +
                dbreq.statusText);
         }
    }

    if (xmldoc) {
        var airports = xmldoc.getElementsByTagName('airport');
//        alert(airports.length);
        this.currentKeyword = this.requestedKeyword;
        this.currentMatches = airports;
        this.update(airports, this.currentKeyword);
    }

}

AutoComplete.prototype.keypressed1 = function(e) {
    var objid = 1;
    var ac = this;
    if (!ac)
        return;

    var code =  e.keyCode? e.keyCode : e.charCode;
    var input = ac.input;
    var keyword = this.getKeyword();

    switch (code) {
    case KEY_UP:
        ac.highlight(ac.selected-1);
        break;

    case KEY_DOWN:
        ac.highlight(ac.selected+1);
        break;

    case KEY_ENTER:
        ac.input.value = ac.matchValue;
        ac.clearDisplay();
        ac.trigger();
        break;

    case KEY_ESC:
        ac.clearDisplay();
        break;

    default:
        if (ac.matchValue || 1) {
            if (keyword != ac.matchValue)
                ac.input.info = null;
        }

        if (keyword.length >= KEYWORD_LENGTH) {
//            ac.clearDisplay();
            
            if (!keyword.match(/^\s*$/)) {
                var url = ac.func(ac, keyword);
                if (url)
                    ac.loadkeywords(url, keyword);
            }
        } else if (keyword.length == 0) {
            ac.clear();
        }

        break;
    }
};

AutoComplete.prototype.getKeyword = function() {
    var keyword = this.input.value;

    if (keyword.match(/^\s*(.*)$/)) {
        return RegExp.$1;
    }

    return keyword;
};

AutoComplete.prototype.selectCompletion = function(i) {
    var ac = this;

    ac.input.value = ac.matchValue;
    ac.clearDisplay();
    ac.trigger();
    return false;
};

// TODO
function ac_hover() {
    var ac = this;
}

AutoComplete.prototype.clearDisplay = function() {
    var ac = this;

    ac.selected = -1;
    ac.matchValue = '';

    var input = ac.input;
    var display = ac.display;

    var tbody = display.getElementsByTagName('tbody')[0];

    hide_element(display);

    while (display.my_children.length > 0) {
        tbody.removeChild(pop(display.my_children));
    }
};

AutoComplete.prototype.update = function(matches, keyword) {
    var i, n;
    var ac = this;
    var display = ac.display;
    var xmlinfo = ac.args;
    var aitem, tr, td;
    var tbody = display.getElementsByTagName('tbody')[0];
    var myreg = new RegExp("^"+keyword+"", "i");
    var citiesOnly = (keyword.length == KEYWORD_LENGTH)? true: false;

    var cityHash = new Object;
    var codeHash = new Object;
    var airportHash = new Object;
    var hashOfHash = new Object;

    hashOfHash[DB_TYPE_CODE] = codeHash;
    hashOfHash[DB_TYPE_CITY] = cityHash;
    hashOfHash[DB_TYPE_AIRPORT] = airportHash;

    ac.clearDisplay();
    ac.matches = matches;
    ac.selected = 0;
    for (i=0, n=0; i<matches.length && n<AUTOCOMPLETE_MAX; i++) {
        var mykey = matches[i].getAttribute('display');
        var type = matches[i].getAttribute('type');
        var canon = matches[i].getAttribute('canon');
        var displayThis = false;

        if (!citiesOnly) {
            if (type == DB_TYPE_CITY) {
                if (!hashOfHash[type][canon])
                    displayThis = true;
            } else {
                displayThis = true;
            }
        } else {
            if (VARIANT_NO_AIRPORTS) {
                if (type != DB_TYPE_AIRPORT && !hashOfHash[type][canon]) 
                    displayThis = true;
            } else {
                if (!hashOfHash[type][canon]) 
                    displayThis = true;
            }
        }

        if (displayThis && myreg.exec(mykey)) {
            tr = document.createElement('tr');
            td = document.createElement('td');
            
            var a =document.createElement('a');
            a.href="#";
            a.onclick = ac.selectCompletion.bind2(ac, n);
            a.onmouseover = ac.highlight.bind2(ac, n);
//new Function("ac_highlight('"+i+"');");
            a.innerHTML = mykey;
            a.className = 'MenuSelect';
            td.appendChild(a);
            
            tr.appendChild(td);
            tbody.appendChild(tr);
            display.my_children.push(tr);
            tr.matchDisplay = mykey;
            tr.matchInfo = matches[i];
            hashOfHash[type][canon] = true;
            
            n++;
        }
    }

    if (display.my_children.length) {
        if (this.active) {
            show_element(this.display);
        } else {
            hide_element(this.display);
        }
        if (this.selected >= 0)
            this.highlight(this.selected);

        if (!this.active) {
//            this.selectCompletion(this.selected);
            this.input.value = this.matchValue;
        }
    }
}

