/** 
 * Constructor for QueryContainer
 */

function QueryContainer(initquery, initmatches) {
    this.query = initquery;
    this.matches = new Array();
    var count = 0;
    for (var i=0;i<initmatches.length;i++) {
        if (initmatches[i].name.substring(0,initquery.length).toLowerCase()==initquery.toLowerCase()) {
            this.matches[count] = initmatches[i];
            count++;
        }
    }
}

/**
 * Constructor for QuerySuggester.
 */
function QuerySuggester() {
    this.id = querySuggesters.length;
    querySuggesters[this.id] = this;
}

QuerySuggester.prototype.useInlineSuggestion = true;                // Whether or not to display the first suggestion as marked text within the search-box
QuerySuggester.prototype.clearInlineSuggestionBeforeSubmit = false; // Whether or not to remove inline suggestions before submitting

// Public functions

/**
 * Initialize the query-suggester.
 *
 * @param suggestionUrl the url to fetch suggestions from, will append the query string to it
 * @param formId        the id of the form that should be submitted if the user clicks a suggestion
 * @param tooltipId     the id of the div used to display the suggestsions
 */
QuerySuggester.prototype.initialize = function(contentToFill, nameField, shortField) {
    this.__enabled = true;
    this.__contentToFill = contentToFill;
    this.__nameField = (nameField && (nameField.length>0))?this.byId(nameField):false;
    this.__shortField = (shortField && (shortField.length>0))?this.byId(shortField):false;
};

/**
 * Set the id of the textarea where debug-output is written. Initially, there is no such
 * textarea assigned to the suggester.
 *
 * @param debugAreaID the id of the textarea to print debug messages to, or boolean false
                      to disable debugging
 */
QuerySuggester.prototype.setDebugAreaId = function(debugAreaId) {
    this.__debugAreaId = debugAreaId;
};

/**
 * Set the id of the input-field to do completion for. Not really neccessary to call, as
 * the id is sent to the key handling methods.
 *
 * @param queryId the id of the search box
 */
QuerySuggester.prototype.setQueryId = function(queryId) {
    this.__queryId = queryId;
    this.__query = this.byId(queryId);
};

// Overridable functions

/**
 * Returns the url to visit to obtain suggestions for a query. By default appends the
 * query to the suggestionUrl member. Override for different behavior.
 *
 * @param quer the query for which to fetch suggestions
 * @return the url that will return the suggestions
 */
QuerySuggester.prototype.getSuggestionUrl = function(query) {
    return encodeURIComponent(query);
};

/**
 * Called when the search form should be submitted (usually because of mouse clik on one
 * of the suggestions in the list). By default submits the form specified by the formId
 * parameter of the initialize() function. Override for different behavior.
 */
QuerySuggester.prototype.submitForm = function() {
    //this.__form.submit();
};

// Input event handlers

/**
 * Event handler for key up events.
 */
QuerySuggester.prototype.keyUp = function(event, field, viewdiv) {
    this.__tooltip = this.byId(viewdiv);
    if (!this.__enabled) return;
    else if (field != this.__queryId) this.setQueryId(field);
    resetIframe();
    if (event) {
        if (this.__timeout) {
            clearTimeout(this.__timeout);
            this.__timeout = false;
        }
        if (event.ctrlKey || event.altKey) {
            return;
        }
        var timeout = 100;
        this.__deletePressed = false;
        switch (event.keyCode) {
            case 9 : // Tab
            case 27 : // Escape
                this.hide();
                return;
            case 8 : // Backspace
            case 46 : // Delete
                this.__deletePressed = true;
                timeout = 200;
                break;
            case 13 : // Enter
                this.hide();
                return;
            case 16 : // Shift
            case 17 : // Ctrl
            case 18 : // Alt
            case 20 : // Caps Lock
            case 33 : // Page up
            case 34 : // Page down
            case 35 : // End
            case 36 : // Home
            case 37 : // Arrow left
            case 38 : // Arrow up
            case 39 : // Arrow right
            case 40 : // Arrow down
            case 45 : // Insert
                return;
            default :
                timeout = 100;
                break;
        }
        this.__index = -1;
        var qc = this;
        this.__timeout = setTimeout(function() {qc.fetchAndDisplaySuggestions();}, timeout);
   }
};

/**
 * Some keys also require keyDown handlers, because they never give a key up event. For
 * instance, pressing the 'tab' key will typically cause focus to leave the search input
 * box, causing the key up event to be sent to another component.
 */
QuerySuggester.prototype.keyDown = function(event, field, viewdiv, addOnclickParam) {
addOnClick = addOnclickParam;
    this.__tooltip = this.byId(viewdiv);
    if (!this.__enabled) return;
    else if (field != this.__queryId) this.setQueryId(field);
    resetIframe();
    if (event && event.keyCode) {
        switch (event.keyCode) {
            case 9 : // Tab
                this.hide();
                break;
            case 13 : // Enter
                if (this.__index == -1) this.clearInlineSuggestion();
                return false;
                break;
            case 38 : // Up-arrow
                if (this.__index >= 0) this.updateSuggestions(this.__index--, -2);
                break;
            case 40 : // Down-arrow
                if (this.__index < this.__terms.length - 1) this.updateSuggestions(this.__index++, -2);
                break;
        }
    }
};

QuerySuggester.prototype.mouseOver = function(index) {
    if (!this.__enabled) return;
    var previous = this.__mouseIndex >= 0 ? this.__mouseIndex : this.__index;
    this.__mouseIndex = index;
    this.updateSuggestions(-2, previous);
};

QuerySuggester.prototype.mouseOut = function(index) {
    if (!this.__enabled) return;
    var previous = this.__mouseIndex;
    this.__mouseIndex = -1;
    this.updateSuggestions(-2, previous);
};

QuerySuggester.prototype.mouseClick = function(index) {
    if (!this.__enabled) return;
    if (index >= 0) {
        if (this.__nameField) {
            this.__nameField.value = this.__terms[index].name;
        }
        if (this.__shortField) {
            this.__shortField.value = this.__terms[index].short;
        }
		this.__tooltip.innerHTML = "";
        /*this.hide();*/
    } else {
        this.hide();
    }
};

// Functions for retrieving suggestions

QuerySuggester.prototype.fetchAndDisplaySuggestions = function() {
    var val = this.__query.value;
    if (this.canHandleRanges()) {
        val = val.substring(0, this.getCaretPosition());
    }
    if (val.length == 0) {
	this.__tooltip.innerHTML = "";
        /*this.hide();*/
        this.__prev = val;
        return;
    } else {
        val = val.replace(new RegExp("\\\\", "g"), "\\\\");
    }
    this.__prev = val;
    if (this.__cache[this.getSuggestionUrl(val)]) {
        this.debug("cache: " + val);
        this.displaySuggestions(this.__cache[this.getSuggestionUrl(val)], this.__prev);
    } else {
        this.debug("query: '" + val + "'");
        this.fetchSuggestion(val);
    }
};

QuerySuggester.prototype.fetchSuggestion = function(query) {
    var qc = new QueryContainer(query,this.__contentToFill);
    this.parseSuggestions(qc);
};

// Functions for displaying suggestions

QuerySuggester.prototype.parseSuggestions = function(qc) {
    if (qc.matches.length<=0) return;
    var params = qc.matches;
    this.displaySuggestions(params,qc.query);
};

QuerySuggester.prototype.displaySuggestions = function(matches, query) {
    if (matches.length < 1) {
        this.noSuggestions();
        return;
    }
    if (this.__tooltip && this.__query) {
        this.__tooltip.innerHTML = "";
        this.buildSuggestionsHtml(matches);
        this.show();
        this.showInlineSuggestions(query);
    }
};

QuerySuggester.prototype.buildSuggestionsHtml = function(matches) {
    var text = "<br/><br/><div class=\"divider\"></div>";
    var length = matches.length;
    this.__terms = new Array(length);
    for (var i = 0; i < length; ++i) {
        /*text += "<div id=\"tooltip_" + i + "\" onmouseover=\"mouseOver(" + this.id + "," + i + ")\" onmouseout=\"mouseOut(" + this.id + "," + i + ")\" onclick=\"mouseClick(" + this.id + "," + i + ")\" style=\"cursor: pointer; background-color:#fff; color:#808080;\">" +
                matches[i].name+
                "</div>\n";*/
				        text += "<a href=\"#\" onclick=\"mouseClick(" + this.id + "," + i + "); focusOnButton()";
						/*if(addOnClick) 
						{
							text += "document.getElementById('" + searchbuttonid + "').click();";
						}	use if typeahead link needs to throw click event - doesnt work in ie7 like this. Debug function mouseclick*/					 
						text += "\">" + matches[i].name + "</a><br/>";
				
        this.__terms[i] = matches[i];
    }   
    this.__tooltip.innerHTML = text;
/*    var iframeelem = document.getElementById(this.__tooltip.id + "_iframe");
    iframeelem.style.height = (this.__terms.length * 13) + "px";
*/};

QuerySuggester.prototype.showInlineSuggestions = function(query) {
    if (this.__terms.length > 0 && this.__query.value == query && !this.__deletePressed && this.useInlineSuggestion) {
        this.__original = this.__query.value;
        if (this.canHandleRanges()) {
            this.__query.value = this.__terms[0];
            this.selectRange(this.__original.length, this.__query.value.length);
        }
    }
};

QuerySuggester.prototype.updateSuggestions = function(previousIndex, previousMouseIndex) {
    var previous = this.byId("tooltip_" + previousIndex);
    var previousMouse = this.byId("tooltip_" + previousMouseIndex);
    var current = this.byId("tooltip_" + this.__index);
    var currentMouse = this.byId("tooltip_" + this.__mouseIndex);
    if (previous) {
        if (previousIndex != this.__mouseIndex) {
            previous.style.backgroundColor = "#fff";
            previous.style.color = "#808080";
        }
    }
    if (current) {       
        this.__query.value = this.__terms[this.__index].name;
        current.style.backgroundColor = "#00c";
        current.style.color = "#fff";
        if (this.canHandleRanges()) {
            this.selectRange(this.__original.length, this.__query.value.length);
        }
    }
    if (previousMouse && previousMouseIndex != this.__index) {
        previousMouse.style.backgroundColor = "#fff";
        previousMouse.style.color = "#808080";
    }
    if (currentMouse) {
        currentMouse.style.backgroundColor = "#00c";
        currentMouse.style.color = "#fff";
    }
};

/**
 * Called when the list of matches returned is empty. Default implementation will simply
 * hide the list of suggestions. Override for custom behavior.
 */
QuerySuggester.prototype.noSuggestions = function() {
    this.hide();
};

QuerySuggester.prototype.show = function() {

    if (this.__tooltip && this.__query) {
        /*this.__tooltip.style.width =  "200px";
		this.__tooltip.style.height =  "100px";*/
        this.__tooltip.style.visibility = "visible";
		/*this.__tooltip.style.overflow = "auto";*/
		
		
 /*       var iframeelem = document.getElementById(this.__tooltip.id + "_iframe");
        iframeelem.style.left = this.findPosX(this.__query) - 1 + "px";
        iframeelem.style.top = this.findPosY(this.__query) + this.__query.offsetHeight + "px";
        iframeelem.style.width = this.__query.offsetWidth + "px";
        iframeelem.style.visibility = "visible";
        alert(this.__tooltip.style.left + " " + this.__tooltip.style.top + " " + this.__tooltip.style.width + " " + this.__tooltip.style.height);
 */   }
};

QuerySuggester.prototype.hide = function() {
    if (this.__tooltip) {
        this.__terms = new Array();
        this.__tooltip.style.visibility = "hidden";
/*        var iframeelem = this.byId(this.__tooltip.id + "_iframe");
        iframeelem.style.visibility = "hidden";        
 */   }
};

// Text-selection helper-functions

QuerySuggester.prototype.canHandleRanges = function() {
      return false;
//    return this.__query.createTextRange || this.__query.setSelectionRange;
};

QuerySuggester.prototype.selectRange = function(from, to) {
    if (this.__query.createTextRange) {
        var t = this.__query.createTextRange();
        t.moveStart("character", from);
        t.select();
    } else if (this.__query.setSelectionRange) {
        this.__query.setSelectionRange(from, to);
    } else {
        this.debug("Couldn't select range.");
    }
};

QuerySuggester.prototype.getCaretPosition = function() {
    if (document.selection) {
        var range = document.selection.createRange().duplicate();
        range.collapse(true);
        range.moveStart("character", -1000);
        return range.text.length;
    } else if (this.__query.setSelectionRange) {
        return this.__query.selectionStart;
    } else {
        this.debug("Couldn't find caret position.");
        return this.__query.value.length;
    }
};

QuerySuggester.prototype.clearInlineSuggestion = function() {
    if (this.__query && this.canHandleRanges() && this.clearInlineSuggestionBeforeSubmit) {
        this.__query.value = this.__query.value.substring(0, this.getCaretPosition());
    }
};

// General helper-functions

QuerySuggester.prototype.findPosX = function(obj) {
    var curleft = 0;
    if (obj.offsetParent) {
        while (obj.offsetParent) {
            curleft += obj.offsetLeft;
            obj = obj.offsetParent;
        }
    } else if (obj.x)
        curleft += obj.x;
    return curleft;
};

QuerySuggester.prototype.findPosY = function(obj) {
    var curtop = 0;
    if (obj.offsetParent) {
        while (obj.offsetParent) {
            curtop += obj.offsetTop
            obj = obj.offsetParent;
        }
    } else if (obj.y) {
        curtop += obj.y;
    }
    return curtop;
};

QuerySuggester.prototype.byId = function(id) {
    var element = document.getElementById ? document.getElementById(id) : false;
    return element && element != null ? element : false;
};

QuerySuggester.prototype.debug = function(message) {
    // alert(message);
};

// Private members

QuerySuggester.prototype.__suggestionUrl = false;   // The url to fetch suggestions from
QuerySuggester.prototype.__form = false;            // The form
QuerySuggester.prototype.__query = false;           // The query input field
QuerySuggester.prototype.__queryId = false;         // The id of the query input field
QuerySuggester.prototype.__tooltip = false;         // The tooltip div
QuerySuggester.prototype.__debugAreaId = false;     // Text-area for debugging

QuerySuggester.prototype.__timeout = false;         // The current timeout
QuerySuggester.prototype.__prev = "";               // The previously sent term
QuerySuggester.prototype.__original = "";           // The term before panning into the suggestions
QuerySuggester.prototype.__index = -1;              // The index of the text cursor in the list of suggestions
QuerySuggester.prototype.__mouseIndex = -1;         // The position of the mouse in the list of suggestions
QuerySuggester.prototype.__terms = new Array();     // The list of suggestions
QuerySuggester.prototype.__cache = new Array();     // A result-cache
QuerySuggester.prototype.__enabled = false;
QuerySuggester.prototype.__deletePressed = false;   // Delete or backspace has been pressed
QuerySuggester.prototype.__contentToFill = new Array();
QuerySuggester.prototype.__nameField = false;
QuerySuggester.prototype.__shortField = false;


// Global stuff


// Global array of all instantiated query-suggesters
var querySuggesters = new Array();

// Global mouse-handling function
function mouseOver(id, index) {
    if (id >= 0 && id < querySuggesters.length) {
        querySuggesters[id].mouseOver(index);
    }
}

// Global mouse-handling function
function mouseOut(id, index) {
    if (id >= 0 && id < querySuggesters.length) {
        querySuggesters[id].mouseOut(index);
    }
}

// Global mouse-handling function
function mouseClick(id, index) {
    if (id >= 0 && id < querySuggesters.length) {
        querySuggesters[id].mouseClick(index);
    } else if (id == -1 && index == -1) {
        for (var i = 0; i < querySuggesters.length; ++i) {
            querySuggesters[i].mouseClick(index);
        }
    }
}

// Resets the iframe
function resetIframe() {
}

var addOnClick = "true";