/* ---------------------------------------[AutoSuggest]---------------------------------------- */

// AutoSuggest constructor
function AutoSuggest(oTextbox, sDataSource) {
	this.cursor = -1; // Current item index in the suggestions list
	this.typeAhead = false; // Defines if suggestions must autocomplete text in the textbox
	this.layer = null; // Div element, representing suggestions dropdown list
	this.dataSource = sDataSource || "autosuggest.php"; // Data source URI
	this.visualisation = null; // Visual effects function appears between suggestions request and response from server 
	this.textbox = oTextbox;
	if (typeof XMLHttpRequest != "undefined")
		this.http = new XMLHttpRequest();
	else if (typeof ActiveXObject != "undefined")
		this.http = new ActiveXObject("MSXML2.XmlHttp");

	this.init();
}

// Creates callback functions for AutoSuggest events
AutoSuggest.prototype.init = function () {
	var oThis = this;
	this.textbox.onkeyup = function (oEvent) {
		if (!oEvent) oEvent = window.event;
		oThis.handleKeyUp(oEvent);
	};
	this.textbox.onkeydown = function (oEvent) {
		if (!oEvent) oEvent = window.event;
		oThis.handleKeyDown(oEvent);
	};
	this.textbox.onblur = function () {
		oThis.hideSuggestions();
	};
	this.createDropDown();
};

AutoSuggest.prototype.createDropDown = function () {
    this.layer = document.createElement("div");
    this.layer.className = "suggestions";
    this.layer.style.visibility = "hidden";
    this.layer.style.width = this.textbox.offsetWidth;
    document.body.appendChild(this.layer);
    var oThis = this;
    this.layer.onmousedown =
    this.layer.onmouseup =
    this.layer.onmouseover = function (oEvent) {
        oEvent = oEvent || window.event;
        oTarget = oEvent.target || oEvent.srcElement;
        //if ("suggestions" != oTarget.className)
        //{
	        if (oEvent.type == "mousedown")
	        {
	            oThis.textbox.value = oTarget.title;
	            oThis.hideSuggestions();
	        }
	        else if (oEvent.type == "mouseover")
	            oThis.highlightSuggestion(oTarget);
	        else
	        	oThis.textbox.focus();
        //}
    };
};

// Put suggestions in the dropdown list and make it visible
AutoSuggest.prototype.showSuggestions = function (aSuggestions, startItem) {

    var oDiv = null;
    this.layer.innerHTML = "";
	startItem = startItem || 0;

	var itemWidth = (this.layer.offsetHeight < this.textbox.offsetHeight * aSuggestions.length)? this.textbox.offsetWidth - 22 : this.textbox.offsetWidth - 6;
    for (var i = startItem; i < aSuggestions.length; i++) {
        oDiv = document.createElement("div");
        oDiv.title = aSuggestions[i];
        oDiv.style.width = itemWidth + "px";
        oDiv.style.height = this.textbox.offsetHeight + "px";
        oDiv.style.textOverflow = "ellipsis";
        oDiv.style.overflow = "hidden";
        var re = new RegExp("(" + this.textbox.value + ")", "i");
        oDiv.innerHTML = aSuggestions[i].replace(re, "<b>$1</b>");
        this.layer.appendChild(oDiv);
    }

    this.layer.style.left = this.getLeft() + "px";
    this.layer.style.top = (this.getTop()+this.textbox.offsetHeight) + "px";
    this.layer.style.visibility = "visible";
    
    /*var oNode = this.layer.childNodes[2];
    alert(oNode.style.display);*/
};

// Make suggestions dropdown list invisible
AutoSuggest.prototype.hideSuggestions = function () {
    this.layer.style.visibility = "hidden";
    this.cursor = -1;
};

AutoSuggest.prototype.previousSuggestion = function () {
    var cSuggestionNodes = this.layer.childNodes;

    if (cSuggestionNodes.length > 0 && this.cursor > 0) {
        var oNode = cSuggestionNodes[--this.cursor];
        this.highlightSuggestion(oNode);
        this.textbox.value = oNode.title;
    }
};

AutoSuggest.prototype.nextSuggestion = function () {
    var cSuggestionNodes = this.layer.childNodes;
	
    if (cSuggestionNodes.length > 0 && this.cursor < cSuggestionNodes.length-1) {
        var oNode = cSuggestionNodes[++this.cursor];
        this.highlightSuggestion(oNode);
        this.textbox.value = oNode.title;
    }
};

AutoSuggest.prototype.highlightSuggestion = function (oSuggestionNode) {

    for (var i=0; i < this.layer.childNodes.length; i++) {
        var oNode = this.layer.childNodes[i];
        if (oNode == oSuggestionNode) {
            oNode.className = "current";
            oNode.scrollIntoView(false);
        } else if (oNode.className == "current") {
            oNode.className = "";
        }
    }
};

// Complete typed text with current suggestion (used only if typeAhead property is true)
AutoSuggest.prototype.doTypeAhead = function (sSuggestion) {
    if (this.textbox.createTextRange || this.textbox.setSelectionRange) {
        var iLen = this.textbox.value.length;
        this.textbox.value = sSuggestion;
        this.selectRange(iLen, sSuggestion.length);
    }
};

// Select text range in the textbox. Used by typeAhead methhod
AutoSuggest.prototype.selectRange = function (iStart, iLength) {
    if (this.textbox.createTextRange) {
        var oRange = this.textbox.createTextRange();
        oRange.moveStart("character", iStart);
        oRange.moveEnd("character", iLength - this.textbox.value.length);
        oRange.select();
    } else if (this.textbox.setSelectionRange) {
        this.textbox.setSelectionRange(iStart, iLength);
    }

    this.textbox.focus();
};

AutoSuggest.prototype.autosuggest = function (aSuggestions) {
	if (aSuggestions)
	{
	    if (aSuggestions.length > 0) {
	        this.showSuggestions(aSuggestions);
	        if (this.typeAhead) {
	            this.doTypeAhead(aSuggestions[0]);
	        }
	    } else {
	        this.hideSuggestions();
	    }
	}
};

AutoSuggest.prototype.handleKeyUp = function (oEvent) {

    var iKeyCode = oEvent.keyCode;

    if (iKeyCode == 8 || iKeyCode == 46) {
        this.getData();

    } else if (iKeyCode < 32 || (iKeyCode >= 33 && iKeyCode <= 46) || (iKeyCode >= 112 && iKeyCode <= 123)) {
        //ignore
    } else {
       this.getData();
    }
};

AutoSuggest.prototype.handleKeyDown = function (oEvent) {
    switch(oEvent.keyCode) {
        case 38: //up arrow
            this.previousSuggestion();
            break;
        case 40: //down arrow
            this.nextSuggestion();
            break;
        case 13: //enter
            this.hideSuggestions();
            break;
        case 27: //esc
            this.hideSuggestions();
            return false;
            break;
    }
};

AutoSuggest.prototype.getLeft = function () {

    var oNode = this.textbox;
    var iLeft = 0;

    while(oNode.tagName != "BODY") {
        iLeft += oNode.offsetLeft;
        oNode = oNode.offsetParent;
    }

    return iLeft;
};

AutoSuggest.prototype.getTop = function () {

    var oNode = this.textbox;
    var iTop = 0;

    while(oNode.tagName != "BODY") {
        iTop += oNode.offsetTop;
        oNode = oNode.offsetParent;
    }

    return iTop;
};

// Requests data from server and starts AutoSuggest redraw on server response
AutoSuggest.prototype.getData = function () {
    var oThis = this;
	var oHttp = this.http;
	if (oHttp.readyState != 0)
		oHttp.abort();
	var sURL = this.dataSource + "?userInput=" + encodeURIComponent(this.textbox.value);
	if (this.visualization) 
		this.visualization(true);
	oHttp.open("get", sURL , true);
	oHttp.onreadystatechange = function () {
		if (oHttp.readyState == 4)
		{
			var aSuggestions = eval(oHttp.responseText);
			oThis.autosuggest(aSuggestions);
			if (oThis.visualization)
				oThis.visualization(false);
		}
	};
	oHttp.send(null);
};
