(function() {
    var textSuggest = {
        initialize: function(e, url, options) {
            this.url = url;
            this.textInput = jQuery(e);
            if (!this.textInput) {
                return false
            }
            jQuery.extend(this, {
                id: 'MICSearchSuggest',
                interval: 70,
                periodicalTimer: 0,
                selectedIndex: -1,
                lastRequestString: '',
                lastRequestType: 0,
                oBuffer: [],
                oBufferSize: 99,
                oBufferLiteral: '{str: [],arr: []}',
                suggestions: [],
                suggestionsDiv: null,
                handlingRequest: false
            });
            this.options = jQuery.extend({
                suggestDivClassName: 'TextDropdown',
                selectionHighClassName: 'HighElement',
                selectionNormalClassName: 'NormalElement',
                selectionWordClassName: 'spanWord',
                selectionCountClassName: 'spanCount',
                matchClassName: 'spanMatchText',
                matchTextWidth: true,
                matchAnywhere: true,
                ignoreCase: true,
                count: 10
            }, options);
            this.createSuggestionsDiv();
            this.injectSuggestBehavior(this.textInput);
            return this
        },
        createSuggestionsDiv: function() {
            if (!this.suggestionsDiv) {
                this.suggestionsDiv = jQuery('<div></div>').addClass(this.options.suggestDivClassName).css({
                    position: 'absolute',
                    display: 'none',
                    zIndex: 11
                })
            }
        },
        injectSuggestBehavior: function(formInput) {
            formInput.attr('autoComplete', 'off').keydown(this.keyDownHandler).click(this.setIntervalHandler).blur(this.clearIntervalHandler)
        },
        keyDownHandler: function(e) {
            var key = (window.event) ? window.event.keyCode : e.keyCode;
            var objSelf = window.TextSuggest;
            var bHidden = objSelf.isHiddenSuggestionsDiv();
            switch (key) {
                case 27 || '.KEY_ESC':
                    objSelf.clearIntervalHandler(e);
                    return null;
                case 9 || '.KEY_TAB':
                    objSelf.setInputFromSelection();
                    return null;
                case 13 || '.KEY_RETURN':
                    if (!bHidden && objSelf.selectedIndex >= 0) {
                        objSelf.setInputFromSelection();
                        return false
                    }
                    else {
                        objSelf.clearIntervalHandler(e);
                        return true
                    }
                case 38 || '.KEY_UP':
                    if (!bHidden) {
                        objSelf.moveSelectionUp()
                    }
                    clearInterval(objSelf.periodicalTimer);
                    return false;
                case 40 || '.KEY_DOWN':
                    if (!bHidden) {
                        objSelf.moveSelectionDown()
                    }
                    clearInterval(objSelf.periodicalTimer);
                    return false;
                default:
                    objSelf.setIntervalHandler(e);
                    return null
            }
        },
        setIntervalHandler: function(e) {
            var src = jQuery((window.event) ? window.event.srcElement : e.target);
            var objSelf = window.TextSuggest;
            if (objSelf.textInput.index(src) < 0) {
                objSelf.textInput = src
            }
            clearInterval(objSelf.periodicalTimer);
            objSelf.periodicalTimer = setInterval(function() {
                window.TextSuggest.handleTextInput()
            }, objSelf.interval)
        },
        clearIntervalHandler: function(e) {
            var objSelf = window.TextSuggest;
            clearInterval(objSelf.periodicalTimer);
            objSelf.hideSuggestionsDiv()
        },
        handleTextInput: function() {
            var curRequestType = this.getRequestType();
            if (curRequestType == 2 && 'no suggest 4 companies now') {
                return false
            }
            this.lastRequestType = curRequestType;
            var bufferObject = this.getBufferObject();
            var curRequestString = this.textInput.val();
            if (this.options.ignoreCase) {
                curRequestString = curRequestString.toLowerCase()
            }
            this.oldVal = this.lastRequestString;
            if (curRequestString != '') {
                var index = -1;
                var bufferStr = bufferObject.str;
                if (!!jQuery.each(bufferStr, function(i, n) {
                    if (n == curRequestString) {
                        index = i;
                        return false
                    }
                }) &&
                index >= 0) {
                    this.oldVal = bufferStr[index];
                    var indexSuggestions = bufferObject.arr[index];
                    if (this.suggestions == indexSuggestions) {
                        this.showSuggestionsDiv();
                        return true
                    }
                    this.suggestions = indexSuggestions;
                    this.updateSuggestions();
                    return null
                }
                var emptyResult = jQuery.grep(bufferObject.str, function(n, i) {
                    return ((bufferObject.arr[i]).length == 0 && curRequestString.indexOf(n) >= 0)
                });
                if (emptyResult && emptyResult.length > 0) {
                    this.suggestions = [];
                    return this.updateSuggestionsDiv()
                }
                this.lastRequestString = curRequestString;
                this.sendRequestForSuggestions();
                return true
            }
            this.suggestions = [];
            this.clearIntervalHandler();
            return this.updateSuggestionsDiv()
        },
        sendRequestForSuggestions: function() {
            if (!!this.handlingRequest) {
                this.pendingRequest = true;
                return
            }
            this.handlingRequest = true;
            this.callAjaxEngine()
        },
        callAjaxEngine: function() {
            var iThis = this;
            try {
                var myAjax = jQuery.getJSON(this.url, {
                    param: this.lastRequestString,
                    kind: this.lastRequestType,
                    id: this.id,
                    count: this.options.count,
                    ignoreCase: this.options.ignoreCase,
                    matchAnywhere: this.options.matchAnywhere,
                    time: new Date().getTime()
                }, function(suggestions) {
                    iThis.ajaxUpdate(suggestions)
                })
            } 
            catch (ajaxError) {
                return false
            }
        },
        ajaxUpdate: function(suggestions) {
            if (!this.createSuggestions(suggestions)) {
                return false
            }
            this.updateSuggestions();
            this.handlingRequest = false;
            if (!!this.pendingRequest) {
                this.handleTextInput()
            }
        },
        createSuggestions: function(suggestions) {
            if (!suggestions) {
                return false
            }
            this.suggestions = suggestions;
            var bufferObject = this.getBufferObject();
            bufferObject.str.push(this.lastRequestString);
            bufferObject.arr.push(suggestions);
            this.oldVal = this.lastRequestString;
            return true
        },
        updateSuggestions: function() {
            this.textInput.after(this.suggestionsDiv);
            if (this.updateSuggestionsDiv()) {
                this.updateSelection(this.selectedIndex);
                this.showSuggestionsDiv()
            }
        },
        updateSuggestionsDiv: function() {
            this.selectedIndex = -1;
            this.suggestionsDiv.empty();
            if (this.suggestions.length <= 0) {
                this.hideSuggestionsDiv();
                return false
            }
            var suggestLines = this.createSuggestionSpans();
            for (var i = 0; i < suggestLines.length; i++) {
                this.suggestionsDiv.append(suggestLines[i])
            }
            return true
        },
        createSuggestionSpans: function() {
            var regExpFlags = 'g';
            if (this.options.ignoreCase) {
                regExpFlags += 'i'
            }
            var startRegExp = '^';
            if (this.options.matchAnywhere) {
                startRegExp = ''
            }
            var regExp = new RegExp(startRegExp + '(' + this.textInput.val() + ')', regExpFlags);
            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 qCount = suggestion['count'];
            if (qCount > 100) {
                qCount -= qCount % 100;
                qCount = (qCount + '').split('').reverse().join('').replace(/(\d{3})(?=\d)/g, '$1,').split('').reverse().join('')
            }
            else {
                if (qCount > 10) {
                    qCount -= qCount % 10
                }
                else {
                    qCount = 10
                }
            }
            var qType = '';
            switch (this.lastRequestType) {
                case 0:
                    qType = 'products';
                    break;
                case 1:
                    qType = 'offers';
                    break;
                case 2:
                    qType = 'companies';
                    break;
                default:
                    qType = 'results'
            }
            var wordSpan = jQuery('<span>' + suggestion['word'].replace(regExp, '<span class="' + this.options.matchClassName + '">$1</span>') + '</span>').addClass(this.options.selectionWordClassName);
            var countSpan = jQuery('<span>' + 'about ' + qCount + ' ' + qType + '</span>').addClass(this.options.selectionCountClassName);
            var suggestionSpan = jQuery('<div></div').addClass(this.options.selectionNormalClassName).append(wordSpan).append(countSpan).mousedown(this.itemSelectHandler).mouseover(this.itemOverHandler);
            suggestionSpan.find('span').mouseover(this.itemOverHandler);
            return suggestionSpan
        },
        itemOverHandler: function(e) {
            var src = jQuery((window.event) ? window.event.srcElement : e.target);
            if (!src.is('div')) {
                src = src.parents('div')
            }
            var objSelf = window.TextSuggest;
            var idx = objSelf.suggestionsDiv.find('div').index(src);
            if (idx != objSelf.selectedIndex) {
                objSelf.updateSelection(idx)
            }
        },
        itemSelectHandler: function(e) {
            var objSelf = window.TextSuggest;
            objSelf.setInputFromSelection()
        },
        setInputFromSelection: function() {
            if (this.selectedIndex >= 0) {
                this.clearIntervalHandler();
                var originLen = this.textInput.val();
                var suggestion = this.suggestions[this.selectedIndex]['word'];
                this.textInput.val(suggestion).parents('form').submit();
                this.setTextSelectionRange(originLen, suggestion.length);
                this.selectedIndex = -1;
                return true
            }
            else {
                this.hideSuggestionsDiv()
            }
            return false
        },
        updateSelection: function(n) {
            this.suggestionsDiv.find('div').removeClass(this.options.selectionHighClassName).addClass(this.options.selectionNormalClassName);
            this.selectedIndex = n;
            if (n >= 0 && n < this.suggestions.length) {
                this.suggestionsDiv.find('div').eq(n).removeClass(this.options.selectionNormalClassName).addClass(this.options.selectionHighClassName)
            }
        },
        showSuggestionsDiv: function() {
            if (this.suggestions.length <= 0) {
                this.hideSuggestionsDiv();
                this.selectedIndex = -1;
                this.textInput.focus()
            }
            else {
                this.positionSuggestionsDiv()
            }
        },
        positionSuggestionsDiv: function() {
            var textPos = this.textInput.offset();
            this.suggestionsDiv.css({
                left: textPos.left + (window.event ? 0 : 1),
                top: (textPos.top + this.textInput.outerHeight())
            });
            var divWidth = this.textInput.width();
            this.suggestionsDiv.find('div').each(function(i) {
                var spansWidth = 0;
                jQuery(this).children('span').each(function() {
                    spansWidth += parseInt(this.offsetWidth)
                });
                if (spansWidth > divWidth) {
                    divWidth = spansWidth + 3
                }
            });
            if (this.options.matchTextWidth) {
                this.suggestionsDiv.css({
                    width: divWidth
                })
            }
            this.suggestionsDiv.show()
        },
        hideSuggestionsDiv: function() {
            this.suggestionsDiv.hide()
        },
        isHiddenSuggestionsDiv: function() {
            return ((this.suggestionsDiv.get(0).style.display == 'none') ? true : false)
        },
        moveSelectionUp: function() {
            if (this.selectedIndex >= 0) {
                this.updateSelection(this.selectedIndex - 1)
            }
            else {
                this.updateSelection(this.suggestions.length - 1)
            }
            var n = this.selectedIndex;
            if (n >= 0 && n < this.suggestions.length) {
                this.textInput.val(this.suggestions[n]['word'])
            }
            else {
                this.textInput.val(this.oldVal);
            }
        },
        moveSelectionDown: function() {
            if (this.selectedIndex <= (this.suggestions.length - 1)) {
                this.updateSelection(this.selectedIndex + 1)
            }
            else {
                this.updateSelection(0)
            }
            var n = this.selectedIndex;
            if (n >= 0 && n < this.suggestions.length) {
                this.textInput.val(this.suggestions[n]['word'])
            }
            else {
                this.textInput.val(this.oldVal);
            }
        },
        setTextSelectionRange: function(start, end) {
            var pos = this.textInput.val().length;
            if (!start) {
                var start = pos
            }
            if (!end) {
                var end = pos
            }
            if (this.textInput.setSelectionRange) {
                this.textInput.setSelectionRange(start, end)
            }
            else {
                if (this.textInput.createTextRange) {
                    var range = this.textInput.createTextRange();
                    range.collapse(true);
                    range.moveEnd('character', end);
                    range.moveStart('character', start);
                    range.select()
                }
            }
        },
        getRequestType: function() {
            var curRequestType = 0;
            var qSelect = this.textInput.parents('form').find('select');
            if (qSelect && qSelect.length > 0) {
                var selectedSrc = qSelect.eq(0).val();
                if (selectedSrc.indexOf('product') < 0) {
                    if (selectedSrc.indexOf('offer') >= 0) {
                        curRequestType = 1
                    }
                    else {
                        if (selectedSrc.indexOf('company') >= 0) {
                            curRequestType = 2
                        }
                        else {
                            curRequestType = 1
                        }
                    }
                }
            }
            return curRequestType
        },
        getBufferObject: function() {
            var bufferObject = this.oBuffer[this.lastRequestType];
            if (!bufferObject || jQuery.unique(bufferObject.str).length > this.oBufferSize) {
                bufferObject = this.oBuffer[this.lastRequestType] = eval('(' + this.oBufferLiteral + ')')
            }
            return bufferObject
        }
    };
    window['TextSuggest'] = textSuggest
})();

