var TextSuggest = Class.create({
 
    initialize: function(anId, options) {
        this.id          = anId;
        var browser      = navigator.userAgent.toLowerCase();
        this.isIE        = browser.indexOf("msie") != -1;
        this.isOpera     = browser.indexOf("opera")!= -1;
        this.isSafari    = browser.indexOf("safari")!= -1;
        this.textInput   = $(this.id);
        this.suggestions = [];
        this.setOptions(options);
        this.injectSuggestBehavior();
    },
    
    setOptions: function(options) {
        this.options = {
                        suggestDivClassName: 'suggestDiv',
                        suggestionClassName: 'suggestion',
                        matchClassName     : 'match',
                        matchTextWidth     : true,
                        selectionColor     : '#F6F3F3',
                        matchAnywhere      : false,
                        count              : 10,
                        newItemLabel       : 'neu'
                       };
        Object.extend(this.options, options);
    },

    injectSuggestBehavior: function() {
        if (this.isIE) {
            this.textInput.autocomplete = "off";
        }

        var keyEventHandler = new TextSuggestKeyHandler(this);
        new Insertion.After(this.textInput,'<input type="text" id="'+this.id+'_preventtsubmit'+'" style="display:none;"/>');
        new Insertion.After(this.textInput,'<input type="hidden" name="'+this.id+'_hidden'+'" id="'+this.id+'_hidden'+'"/>');

        this.createSuggestionsDiv();
    },

    handleTextInput: function() {
        var previousRequest    = this.lastRequestString;
        this.lastRequestString = this.textInput.value;
     
        if (this.lastRequestString == "") {
            this.hideSuggestions();
        }
        else if (this.lastRequestString != previousRequest) {
            this.sendRequestForSuggestions();
        }
    },

    moveSelectionUp: function() {
        if (this.selectedIndex > 0) {
            this.updateSelection(this.selectedIndex - 1);
        }
    },

    moveSelectionDown: function() {
        if (this.selectedIndex < (this.suggestions.length - 1)) {
            this.updateSelection(this.selectedIndex+1);
        }
    },

    updateSelection: function(n) {
  
        var span = $(this.id + "_" + this.selectedIndex);
        
        if (span){
            span.style.backgroundColor = "";
        }
        this.selectedIndex = n;
        var span = $(this.id + "_" + this.selectedIndex);
        if (span){
            span.style.backgroundColor = this.options.selectionColor;
        }
    },

    sendRequestForSuggestions: function() {
        if (this.handlingRequest) {
            this.pendingRequest = true;
            return;
        }
        this.handlingRequest = true;
        this.callAjax();
    },

    ajaxUpdate: function(ajaxResponse) {
        this.createSuggestions(ajaxResponse.responseXML);        
        
        if (this.suggestions.length == 0) {
            this.hideSuggestions();
            $(this.id + "_hidden").value = "";
        }
        else {
            this.updateSuggestionsDiv();
            
            this.showSuggestions();
              
            this.updateSelection(0);
        }
        

        this.handlingRequest = false;

        if (this.pendingRequest) {
            this.pendingRequest    = false;
            this.lastRequestString = this.textInput.value;
            this.sendRequestForSuggestions();
        }
    },

    setInputFromSelection: function() {
        var hiddenInput = $(this.id + "_hidden");
        var suggestion  = this.suggestions[ this.selectedIndex ];

        this.textInput.value = suggestion.text;
        hiddenInput.value    = suggestion.value;
        this.hideSuggestions();
    },

    showSuggestions: function() {
        var divStyle = this.suggestionsDiv.style;
       
        if (divStyle.display == '') {
         
            return;
        }
        this.positionSuggestionsDiv();
        
        divStyle.display = '';
    },

    positionSuggestionsDiv: function() {
        
        var textPos = Element.cumulativeOffset(this.textInput);
        
        var divStyle = this.suggestionsDiv.style;
        divStyle.top  = (textPos[1] + this.textInput.offsetHeight) + "px";
        divStyle.left = textPos[0] + "px";
 
        if (this.options.matchTextWidth) {
            divStyle.width = this.textInput.offsetWidth;
        }
    },

    hideSuggestions: function() {
        this.suggestionsDiv.style.display = 'none';
    },

    createSuggestionsDiv: function() {
        this.suggestionsDiv = document.createElement("div");
        this.suggestionsDiv.className = this.options.suggestDivClassName;

        var divStyle = this.suggestionsDiv.style;
        divStyle.position = 'static';
        divStyle.zIndex   = 101;
        divStyle.display  = "none";
        divStyle.border   = '1px solid black';

        this.textInput.parentNode.appendChild(this.suggestionsDiv);
    },

    updateSuggestionsDiv: function() {
        this.suggestionsDiv.innerHTML = "";
        var suggestLines = this.createSuggestionSpans();
        for (var i = 0 ; i < suggestLines.length ; i++) {
            this.suggestionsDiv.appendChild(suggestLines[i]);
        }
    },

    createSuggestionSpans: function() {
        var regExpFlags = 'i';
        var startRegExp = "^";
        if (this.options.matchAnywhere) {
            startRegExp = '';
        }
        var regExp  = new RegExp(startRegExp + this.lastRequestString, regExpFlags);


        if (!this.contains(this.lastRequestString,this.suggestions)) {
            var tmpsuggestions = [];
            tmpsuggestions.push({ text: this.lastRequestString, value: 'neu' });
            for (var i = 0 ; i < this.suggestions.length ; i++) {
                tmpsuggestions.push(this.suggestions[i]);
            }
            this.suggestions=tmpsuggestions;
        }

        var suggestionSpans = [];
        for (var i = 0 ; i < this.suggestions.length ; i++) {
            suggestionSpans.push(this.createSuggestionSpan(i, regExp))
        }
        return suggestionSpans;
    },
   
    createSuggestionSpan: function(n, regExp) {
        var suggestion = this.suggestions[n];

        var suggestionSpan = document.createElement("div");
        suggestionSpan.className = this.options.suggestionClassName;
        suggestionSpan.style.width   = '100%';
        suggestionSpan.style.display = 'block';
        suggestionSpan.style.position = 'relative';
        suggestionSpan.style.textAlign   = 'left';
      
        suggestionSpan.id            = this.id + "_" + n;
        suggestionSpan.onmouseover   = this.mouseoverHandler.bindAsEventListener(this);
        suggestionSpan.onclick       = this.itemClickHandler.bindAsEventListener(this);

        if (this.options.maxLength) {
            suggestion.text = suggestion.text.truncate(this.options.maxLength);
        }
        
        var textValues = this.splitTextValues(suggestion.text,
                                              this.lastRequestString.length,
                                              regExp);


        var suggestionSpanOpt = document.createElement("span");
        suggestionSpanOpt.style.position   = 'absolute';
        suggestionSpanOpt.style.textAlign   = 'right';
        suggestionSpanOpt.style.right = '0px';
        suggestionSpanOpt.style.color = '#000000';
        suggestionSpanOpt.id            = this.id + "_opt_" + n;
        if (suggestion.value=='neu') {
            suggestionSpanOpt.style.color = '#9B9027';
            suggestionSpanOpt.appendChild(document.createTextNode(this.options.newItemLabel));
        }
        else {
            suggestionSpanOpt.appendChild(document.createTextNode(suggestion.value));
        }

        var textMatchSpan = document.createElement("span");
        textMatchSpan.id            = this.id + "_match_" + n;
        textMatchSpan.className     = this.options.matchClassName;
        textMatchSpan.onmouseover   = this.mouseoverHandler.bindAsEventListener(this);
        textMatchSpan.onclick       = this.itemClickHandler.bindAsEventListener(this);

        textMatchSpan.appendChild(document.createTextNode(textValues.mid));

        suggestionSpan.appendChild(document.createTextNode(textValues.start));
        suggestionSpan.appendChild(textMatchSpan);
        suggestionSpan.appendChild(document.createTextNode(textValues.end));
        suggestionSpan.appendChild(suggestionSpanOpt);
        return suggestionSpan;
    },
   
    mouseoverHandler: function(e) {
        var src = e.srcElement ? e.srcElement : e.target;
        var index = parseInt(src.id.substring(src.id.lastIndexOf('_')+1));
        this.updateSelection(index);
    },

    itemClickHandler: function(e) {
        this.mouseoverHandler(e);
        this.hideSuggestions();
        this.textInput.focus();
    },

    splitTextValues: function(text, len, regExp) {
        var startPos  = text.search(regExp);
        var matchText = text.substring(startPos, startPos + len);
        var startText = startPos == 0 ? "" : text.substring(0, startPos);
        var endText   = text.substring(startPos + len);
        return { start: startText, mid: matchText, end: endText };
    },

    getElementContent: function(element) {
        return element.firstChild.data;
    }, 
   
    contains: function(val,arr) {
        for (var i=0;i<arr.length;i++) {
            if (arr[i].text.toLowerCase() == val.toLowerCase()) {
                return true;
            }
        }
        return false;
    }
});

TextSuggestKeyHandler = Class.create({

    initialize: function(textSuggest) {
        this.textSuggest = textSuggest;
        this.input       = this.textSuggest.textInput;
        this.addKeyHandling();
    },

    addKeyHandling: function() {
        this.input.onkeyup    = this.keyupHandler.bindAsEventListener(this);

        if (!this.textSuggest.isSafari) {
            this.input.onkeydown  = this.keydownHandler.bindAsEventListener(this);
        }
        this.input.onblur     = this.onblurHandler.bindAsEventListener(this);
        if (this.textSuggest.isOpera) {
            this.input.onkeypress = this.keyupHandler.bindAsEventListener(this);
        }
    },

    keydownHandler: function(e) {
        var upArrow   = 38;
        var downArrow = 40;

        if (e.keyCode == upArrow) {
            this.textSuggest.moveSelectionUp();
            setTimeout(this.moveCaretToEnd.bind(this), 1);
        }
        else if (e.keyCode == downArrow){
            this.textSuggest.moveSelectionDown();
        }
    },

    keyupHandler: function(e) {
        if (this.input.length == 0 && !this.textSuggest.isOpera) {
            this.textSuggest.hideSuggestions();
        }

        if (!this.handledSpecialKeys(e)) {
            this.textSuggest.handleTextInput();
        }
    },

    handledSpecialKeys: function(e) {
        var enterKey  = 13;
        var upArrow   = 38;
        var downArrow = 40;
        var escKey    = 27;

        if (e.keyCode == upArrow || e.keyCode == downArrow) {
            return true;
        }
        else if (e.keyCode == escKey) {
            this.textSuggest.hideSuggestions();
            return true;
        }
        else if (e.keyCode == enterKey) {
            this.textSuggest.setInputFromSelection();
            return true;
        }

        return false;
    },

    moveCaretToEnd: function() {
        var pos = this.input.value.length;
        if (this.input.setSelectionRange) {
            this.input.setSelectionRange(pos,pos);
        }
        else if(this.input.createTextRange){
            var m = this.input.createTextRange();
            m.moveStart('character',pos);
            m.collapse();
            m.select();
        }
    },

    onblurHandler: function(e) {
        if (this.textSuggest.suggestionsDiv.style.display == '') {
            this.textSuggest.setInputFromSelection();
        }
        this.textSuggest.hideSuggestions();
    }
});
