// Constructor for an auto-complete text-box.
// Takes the id of the text-box as a parameter, as well as the function to call to populate the drop down
function AutoCompleteTextBox( textboxid, callback ) {
	this.textbox = document.getElementById( textboxid );
	this.listbox = document.createElement("SELECT");
	this.listboxContainer = document.createElement("DIV");
	this.listboxContainer.appendChild(this.listbox);
	this.listboxContainer.style.position = "absolute";
	this.populateListboxCallback = callback(this);

	this.popupAdded = false;
	this.visible = false;

	var me = this;
	this.textbox.onkeydown = function(e) { return me.onKeyDown(e) };
	if (this.textbox.captureEvents) this.textbox.captureEvents(Events.ONKEYDOWN);
	this.textbox.onkeyup = function(e) { return me.onKeyUp(e) };
	if (this.textbox.captureEvents) this.textbox.captureEvents(Events.ONKEYUP);
	this.textbox.onkeypress = function(e) { return me.onKeyPress(e) };
	if (this.textbox.captureEvents) this.textbox.captureEvents(Events.ONKEYPRESS);
	this.textbox.onfocus = function(e) { return me.onFocus(e) };
	if (this.textbox.captureEvents) this.textbox.captureEvents(Events.ONFOCUS);
}

// function called when the user presses a keyboard key
AutoCompleteTextBox.prototype.onKeyDown = function(e) {
		var code;
		if (!e) var e = window.event;
		if (e.keyCode) code = e.keyCode;
		else if (e.which) code = e.which;
	
	    //if ( code == KeyCodes.KEY_ENTER ) {
	    //    this.enterKey( );
	    //} 
	    if ( code == KeyCodes.KEY_TAB ) {
	        this.tabKey( );
	    } else if ( code == KeyCodes.KEY_DOWN ) {
	        this.downKey( );
	    } else if ( code == KeyCodes.KEY_UP ) {
	        this.upKey( );
	    } else if ( code == KeyCodes.KEY_ESCAPE ) {
	        this.escapeKey( );
	    }
	}

AutoCompleteTextBox.prototype.onKeyUp = function(e) {
	var code;
	if (!e) var e = window.event;
	if (e.keyCode) code = e.keyCode;
	else if (e.which) code = e.which;

    switch ( code ) {
        case KeyCodes.KEY_ALT:
        case KeyCodes.KEY_CTRL:
        case KeyCodes.KEY_DOWN:
        case KeyCodes.KEY_END:
        case KeyCodes.KEY_ENTER:
        case KeyCodes.KEY_ESCAPE:
        case KeyCodes.KEY_HOME:
        case KeyCodes.KEY_LEFT:
        case KeyCodes.KEY_PAGEDOWN:
        case KeyCodes.KEY_PAGEUP:
        case KeyCodes.KEY_RIGHT:
        case KeyCodes.KEY_SHIFT:
        case KeyCodes.KEY_TAB:
        case KeyCodes.KEY_UP:
            break;
        default:
            this.otherKey( code );
            break;
    }
}

// A key was pressed
AutoCompleteTextBox.prototype.onKeyPress = function(e) {
	if (this.onkeypress != null)
		return this.onkeypress(e);
}

// The textbox received focus
AutoCompleteTextBox.prototype.onFocus = function(e) {
	if (this.onfocus != null)
		return this.onfocus(e);
}

// Give the focus to the textbox
AutoCompleteTextBox.prototype.setFocus = function () {
	if ( this.textbox.focus )
		this.textbox.focus();
	else if ( this.textbox.__anchor && this.textbox.__anchor.focus)
		this.textbox.__anchor.focus();
}

// Select all the text in the textbox
AutoCompleteTextBox.prototype.selectAll = function ( ) {
	// Internet Explorer
	if ( this.textbox.createTextRange ) {
    	try {
	      var tr = this.textbox.createTextRange();
	      tr.collapse(true);
	      tr.moveStart('character', 0);
	      tr.moveEnd('character', this.getText().length);
	      tr.select();
	    } catch (e) {
	    }
	} else if ( this.textbox.setSelectionRange ) {
		this.textbox.setSelectionRange(0, this.getText().length);
    }
}

// The down key was pressed.
AutoCompleteTextBox.prototype.downKey = function() {
    var selectedIndex = this.listbox.selectedIndex;
    selectedIndex++;
    if ( selectedIndex >= this.listbox.options.length ) {
        selectedIndex = 0;
    }
    this.listbox.selectedIndex = selectedIndex;
    this.updateTextBox();
}

// The up key was pressed.
AutoCompleteTextBox.prototype.upKey = function() {
    var selectedIndex = this.listbox.selectedIndex;
    selectedIndex--;
    if ( selectedIndex < 0 ) {
        selectedIndex = this.listbox.options.length - 1;
    }
    this.listbox.selectedIndex = selectedIndex;
    this.updateTextBox();
}

// The enter key was pressed.
AutoCompleteTextBox.prototype.enterKey = function( ) {
    this.complete( );
}

// The tab key was pressed.
AutoCompleteTextBox.prototype.tabKey = function( ) {
    this.complete( );
}

// The escape key was pressed.
AutoCompleteTextBox.prototype.escapeKey = function( ) {
	this.listbox.options.length = 0;
	this.listboxContainer.style.display = "none";
    this.visible = false;
}

// Returns the text in the textbox
AutoCompleteTextBox.prototype.getText = function( ) {
	return this.textbox.value;
}

// Sets the text in the textbox
AutoCompleteTextBox.prototype.setText = function( text ) {
	this.textbox.value = text;
}

// Any other non-special key was pressed.
AutoCompleteTextBox.prototype.otherKey = function( code ) {
	var text = this.getText( );
    // Update the existing choices in the list box to reflect the user's entry.
    this.filterChoices( text );

    // If any text was entered, start an async callback.
    if ( text.length > 0 ) {
		this.populateListboxCallback();
    }
}

// Hides/shows the choice box as needed.
// Assumes all choices are currently valid.
AutoCompleteTextBox.prototype.hideChoicesIfNeeded = function( text ) {
    // Hide the list box under any of these conditions:
    // - the text box is empty
    // - there are no matching choices
    // - there is only one choice that exactly matches the text box entry
    // Show the list box under any other condition.
    if ( 0 == text.length || 0 == this.listbox.options.length
            || ( 1 == this.listbox.options.length && this.listbox.options[0].value == text ) ) {
        this.listbox.options.length = 0;
        this.listboxContainer.style.display = "none";
        this.visible = false;
    } else {
        this.listbox.selectedIndex = -1;
        this.listbox.size = Math.max(this.listbox.options.length + 1, 20);

        if ( !this.popupAdded ) {
        	document.body.appendChild(this.listboxContainer);
            this.popupAdded = true;
        }
        this.listboxContainer.style.display = "block";
        this.visible = true;
        var textPosition = findPos(this.textbox);
        var listLeft = textPosition.left;
        var listTop = textPosition.top + this.textbox.offsetHeight;

        this.setPopupPosition(listLeft, listTop);
        var offsetWidth = this.textbox.offsetWidth;
        this.listbox.style.width = offsetWidth + "px";
    }
}

// repositions the dropdown
AutoCompleteTextBox.prototype.setPopupPosition = function(left, top) {
    var h = this.listboxContainer;
    if ((left == -1) && (top == -1)) {
      h.style.left = "";
      h.style.top = "";
      h.style.position = "static";
    } else {
      h.style.position = "absolute";
      h.style.left = left + "px";
      h.style.top = top + "px";
    }
}
  
// Removes all items in the choices menu that do not start with the specified text.
AutoCompleteTextBox.prototype.filterChoices = function( text ) {
    var i = 0;
    while ( i < this.listbox.options.length ) {
        if ( this.listbox.options[i].text.toLowerCase( ).indexOf(text.toLowerCase( ) ) == 0 ) {
            ++i;
        } else {
            this.listbox.remove(i);
        }
    }
    this.hideChoicesIfNeeded( text );
}

// Update the choices menu using the provided matches and entered text.
AutoCompleteTextBox.prototype.setChoices = function( matches, filterText ) {
    this.listbox.options.length = 0;
    for ( var i = 0; i < matches.length; i++ ) {
        if ( matches[i] != null ) {
			var newOption = document.createElement('option');
			newOption.text = matches[i];
        	try {
	            this.listbox.add( newOption, null );
        	} catch (ex) {
        		this.listbox.add( newOption );
        	}
        }
    }
    this.filterChoices( filterText );
}

AutoCompleteTextBox.prototype.updateTextBox = function ( ) {
	if ( this.visible && this.listbox.options.length > 0 ) {
        this.setText(this.listbox.options[this.listbox.selectedIndex].text);
    }
}

// add selected item to textbox
AutoCompleteTextBox.prototype.complete = function( ) {
    this.updateTextBox();
    this.listbox.options.length = 0;
    this.listboxContainer.style.display = "none";
    this.visible = false;
}
