HTML_AJAX.Open = function(request) {};
HTML_AJAX.Load = function(request) {};

topicSuggest = Class.create({
    initialize: function(elementId, serverUrl, options) {
        this.useSuggest         = this.getUseSuggest();
        this.id                 = elementId;
        this.textInput          = $(this.id);
        this.url                = serverUrl;
        this.suggestions        = [];
        this.backSuggestions    = [];
        this.observer           = null;
        this.textValue          = '';
        this.oldTextInputValue  = this.textInput.value;
        this.active             = false;
        this.hasFocus           = false;
        this.click              = false;
        this.IE                 = Prototype.Browser.IE; 
        this.setOptions(options);
        this.injectSuggestBehavior();
    },

    getCookieVal: function(offset) {
        var endstr = document.cookie.indexOf (";", offset);
        if (endstr == -1)
            endstr = document.cookie.length;
        return unescape(document.cookie.substring(offset, endstr));
    },

    getCookie: function(name) {
        var arg = name + "=";  
        var alen = arg.length;  
        var clen = document.cookie.length;  
        var i = 0;  
        while (i < clen) {
            var j = i + alen;    
            if (document.cookie.substring(i, j) == arg)      
                return this.getCookieVal(j);    
            i = document.cookie.indexOf(" ", i) + 1;    
            if (i == 0) break;   
        }  
        return null;
    },

    setCookie: function(name, value) {
        var argv = this.setCookie.arguments;  
        var argc = this.setCookie.arguments.length;  
        var ExpDate = new Date();
        ExpDate.setTime(ExpDate.getTime() + 1000*60*60*24*365); 
        var expires = ExpDate;  
        var path = '/';  
        //var expires = (argc > 2) ? argv[2] : null;  
        //var path = (argc > 3) ? argv[3] : null;  
        var domain = (argc > 4) ? argv[4] : null;  
        var secure = (argc > 5) ? argv[5] : false;  
        document.cookie = name + "=" + escape (value) + ((expires == null) ? "" : ("; expires=" + expires.toGMTString())) + ((path == null) ? "" : ("; path=" + path)) +  ((domain == null) ? "" : ("; domain=" + domain)) +  ((secure == true) ? "; secure" : "");
    },

    delCookie: function(name) {
        var exp = new Date();  
        exp.setTime (exp.getTime() - 1);   
        var cval = GetCookie (name);  
        document.cookie = name + "=" + cval + "; expires=" + exp.toGMTString();
    },

    getUseSuggest: function() {
        var use = this.getCookie('useSuggest');
        if (use == 'Y') {
            return 'Y';
        } else if (use == null) {
            return 'Y';
        } else {
            return 'N';
        }
    },

    setOptions: function(options) {
        this.options = Object.extend({
            className           : 'autocomplete',
            methodName          : 'getAutoComplete',
            baseDivClassName    : 'baseDiv',
            suggestDivClassName : 'suggestDiv',
            onOffDivClassName   : 'onOffDiv',
            onOffSpanClassName  : 'onOffSpan',
            onOffSpanClassName2 : 'onOffSpan2',
            suggestionClassName : 'suggestion',
            textClassName       : 'text',
            lineClassName       : 's_line',
            descriptionClassName: 'description',
            matchClassName      : 'match',
            arrowClassName      : 'arrow',
            arrowAClassName     : 'arrowA',
            arrowImgClassName   : 'arrowImg',
            matchTextWidth      : true,
            selectionColor      : '#f5f5f5',
            arrowUp             : '/images/btn_atcmp_down_on2.gif',
            arrowDown           : '/images/btn_atcmp_up_on2.gif',
            disabledArrowUp     : '/images/btn_atcmp_down_on.gif',
            disabledArrowDown   : '/images/btn_atcmp_up_on.gif',
            frequency           : 0.05,
            maxHeight           : null,
            tokens              : [],
            minChars            : 2,
            matchAnywhere       : false,
            ignoreCase          : true,
            useBackword         : true,
            useValue            : false,
            useOnOff            : true,
            useQ                : true,
            QKwd                : ['\"'],
            count               : 10,
            countBackWord       : 5
        }, options || {});

        if (this.options.matchAnywhere) {
            this.options.useBackword = false;
        }

        if (typeof(this.options.tokens) == 'string') {
            this.options.tokens = new Array(this.options.tokens);
        }
        // Force carriage returns as token delimiters anyway
        if  (!this.options.tokens.include('\n')) {
            this.options.tokens.push('\n');
        }
    },

    injectSuggestBehavior: function() {
        this.textInput.setAttribute('autocomplete','off');

        if (this.options.useOnOff) {
            this.createArrow();
        }
        this.createSuggestionsDiv();

        Event.observe(this.textInput, 'focus', this.onFocus.bindAsEventListener(this));
        Event.observe(this.textInput, 'keydown', this.handledSpecialKeys.bind(this));
        Event.observe(this.textInput, 'click', this.onClick.bind(this));
        Event.observe(this.textInput, 'blur', this.onBlur.bindAsEventListener(this));
    },

    createArrow: function() {
        this.ArrowSpan = document.createElement("span");
        this.ArrowSpan.className = this.options.arrowClassName;
        //this.arrowA = document.createElement("a");
        //this.arrowA.href = "#";
        //this.arrowA.className = this.options.arrowAClassName;
        this.arrow = document.createElement("img");
        this.changeArrow();
        this.arrow.className = this.options.arrowImgClassName;
        //this.ArrowSpan.appendChild(this.arrowA);
        //this.arrowA.appendChild(this.arrow);
        this.ArrowSpan.appendChild(this.arrow);
        this.textInput.parentNode.appendChild(this.ArrowSpan);

        //var Obj = this;
        //Event.observe(this.arrowA,'focus',function(){ Obj.arrowA.blur(); });
        //Event.observe(this.ArrowSpan,'click',this.arrowOnClick.bind(this));
        Event.observe(this.arrow,'click',this.arrowOnClick.bind(this));

        /*
        if (this.textInput.style.width) {
            this.textInput.style.width = parseInt(this.textInput.style.width) + "px";
        } else {
            this.textInput.size = this.textInput.size - 5;
        }
        */
    },

    changeArrow: function() {
        if (this.useSuggest == 'Y') {
            this.arrow.src = this.options.arrowUp;
        } else {
            this.arrow.src = this.options.disabledArrowUp;
        }
    },

    createSuggestionsDiv: function() {
        if (this.IE) {
            var br = document.createElement("br");
            this.textInput.parentNode.appendChild(br);
        }
        
        this.baseDiv = document.createElement("div");
        this.baseDiv.className = this.options.baseDivClassName;

        var divStyle = this.baseDiv.style;
        divStyle.position = 'absolute';
        divStyle.zIndex   = 101;
        divStyle.display  = "none";

        //this.textInput.parentNode.parentNode.appendChild(this.baseDiv);
        //this.textInput.parentNode.appendChild(this.baseDiv);
        $('suggest').appendChild(this.baseDiv);

        this.suggestionsDiv = document.createElement("div");
        this.suggestionsDiv.className = this.options.suggestDivClassName;
        this.baseDiv.appendChild(this.suggestionsDiv);

        if (this.options.useOnOff) {
            this.onOffDiv = document.createElement("div");
            this.onOffDiv.className = this.options.onOffDivClassName;
            this.baseDiv.appendChild(this.onOffDiv);

            this.onOffSpan = document.createElement("span");
            if (Prototype.Browser.IE) {
                this.onOffSpan.className = this.options.onOffSpanClassName;
            } else {
                this.onOffSpan.className = this.options.onOffSpanClassName2;
            }
            this.onOffSpan.innerHTML = this.createOnOffText();

            /*
            var clearAllHisComment = document.createElement("span");
            clearAllHisComment.className = 'clearAllHisComment';
            clearAllHisComment.innerHTML = "ÃÖ±ÙÅ°¿öµå";
            this.onOffDiv.appendChild(clearAllHisComment);

            var clearAllHis = document.createElement("span");
            clearAllHis.className = 'clearAllHis';
            clearAllHis.innerHTML = "ÀüÃ¼Áö¿ì±â";
            this.onOffDiv.appendChild(clearAllHis);
            */

            this.onOffDiv.appendChild(this.onOffSpan);
            Event.observe(this.onOffSpan, 'click', this.onOffClickHandler.bindAsEventListener(this));
            /* Event.observe(clearAllHis, 'click', this.clearAllHisClickHandler.bindAsEventListener(this)); */
        }
        /*
        if (this.options.requestParameters.arg != 'mp' && this.options.requestParameters.arg != 'sch') {
            this.historyDiv = document.createElement("div");
            this.historyDiv.className = 'historyDiv';
            this.baseDiv.appendChild(this.historyDiv);
        }
        */
    },

    clearAllHisClickHandler: function() {
        delAllHistory();
        this.historyDiv.style.display = "none";
    },

    createOnOffText: function() {
        /* cjo */
        if (this.useSuggest == 'Y') {
            //this.onOffDiv.innerHTML = '<span id="onoff" class="'+this.options.onOffSpanClassName+'">±â´É²ô±â</span>';
            return 'ÀÚµ¿¿Ï¼º±â´É²ô±â';
        } else {
            //this.onOffDiv.innerHTML = '<span id="onoff" class="'+this.options.onOffSpanClassName+'">±â´ÉÄÑ±â</span>';
            return 'ÀÚµ¿¿Ï¼º±â´ÉÄÑ±â';
        }
    },

    onBlur: function(event) {
        if (!this.hasFocus && this.baseDiv.style.display == '') {
            //setTimeout(this.hide.bind(this), 150);
            this.hide();
            clearTimeout(this.keyTimer);
            this.blur = true;
        }
    },

    hide: function() {
        var divStyle = this.baseDiv.style;
        if (divStyle.display != 'none') {
            if (this.options.useOnOff) {
                this.changeArrow();
            }
            divStyle.display = 'none';
            this.active = false;
        }
    },

    moveSelectionUp: function() {
        if (this.selectedIndex > 0) {
            var divStyle = this.suggestionsDiv.style;
            if (divStyle.overflowY == 'scroll' && this.selectedIndex > 0) {
                this.updateSelectionsDivScrollUp(this.selectedIndex - 1);
            }
            this.updateSelection(this.selectedIndex - 1);
        } else {
            this.hide();
        }
    },

    moveSelectionDown: function() {
        if (this.selectedIndex < (this.suggestions.length - 1)) {
            var divStyle = this.suggestionsDiv.style;
            if (divStyle.overflowY == 'scroll') {
                this.updateSelectionsDivScrollDown(this.selectedIndex + 1);
            }
            this.updateSelection(this.selectedIndex + 1);
        }
    },

    updateSelectionsDivScrollUp: function(n) {
        var span = $(this.id + "_" + n);
        var div = this.suggestionsDiv;
        if ((span.offsetTop - span.clientHeight) < div.scrollTop) {
            div.scrollTop -= span.clientHeight;
        }
    },

    updateSelectionsDivScrollDown: function(n) {
        var span = $(this.id + "_" + n);
        var div = this.suggestionsDiv;
        if ((span.offsetTop + span.clientHeight) > (div.scrollTop + div.clientHeight - span.clientHeight)) {
            div.scrollTop += span.clientHeight;
        }
    },

    onFocus: function() {
        if (this.textInput.value && this.suggestionsDiv.innerHTML == "") {
            //this.onObserverEvent();
            this.nohide = true;
        }
        this.onKeyPress(this);
    },

    onKeyPress: function(event) {
        /*cjo Å°Á¦¾î*/
        if (!this.textInput.value && !this.blur) { this.hide(); }
        if (this.textValue != this.textInput.value) {
            this.textValue = this.textInput.value;
            if (this.observer) { clearTimeout(this.observer); }
            this.observer = setTimeout(this.onObserverEvent.bind(this), this.options.frequency*1000);
        } else {
        }
        if (this.keyTimer) { clearTimeout(this.keyTimer); }
        this.keyTimer = setTimeout(this.onKeyPress.bind(this), 10);
    },

    onClick: function(event) {
        if (this.useSuggest == 'Y') {
            if (this.baseDiv.style.display == "" && !this.nohide) {
                if (this.suggestionsDiv.style.display != '' && this.textInput.value != '') {
                    this.updateSelection(-1);
                    this.suggestionsDiv.style.display = "";
                    this.show();
                } else {
                    this.hide();
                }
            } else if (this.baseDiv.style.display != "" && this.textInput.value && this.suggestionsDiv.innerHTML != "" && this.getToken().length>=this.minChars) {
                this.updateSelection(-1);
                this.suggestionsDiv.style.display = "";
                this.show();
            }
            this.nohide = false;
        }
    },

    arrowOnClick: function(event) {
        /* cjo */
        if (this.active || this.blur) {
            this.hide();
            this.blur = false;
        } else {
            this.arrowShow();
            this.blur = true;
        }
    },

    arrowShow: function() {
        //this.suggestionsDiv.innerHTML = "";
        this.suggestionsDiv.style.display = "none";
        this.show();
    },

    handledSpecialKeys: function(event) {
        /*cjo Æ¯¼öÅ° Á¦¾î*/
        if (this.active) {
            switch (event.keyCode) {
                case Event.KEY_ESC:
                    this.hide();
                    break;
                case Event.KEY_LEFT:
                case Event.KEY_RIGHT:
                    break;
                case Event.KEY_UP:
                    this.moveSelectionUp();
                    break;
                case Event.KEY_DOWN:
                    this.moveSelectionDown();
                    break;
            }
            if (this.selectedIndex > -1) {
                switch (event.keyCode) {
                    case Event.KEY_SPACEBAR:
                        return;
                        break;
                    //case Event.KEY_TAB:
                    case Event.KEY_RETURN:
                        this.setInputFromSelection();
                        this.textInput.value += ' ';
                        Event.stop(event);
                        break;
                }
            }
        } else if(event.keyCode == Event.KEY_DOWN && this.textInput.value && this.suggestionsDiv.innerHTML != "" && this.useSuggest == 'Y' && this.getToken().length>=this.minChars) {
            this.suggestionsDiv.style.display = "";
            this.updateSelection(-1);
            this.show();
        } else {
            if (event.keyCode == Event.KEY_TAB || event.keyCode == Event.KEY_RETURN || (Prototype.Browser.WebKit > 0 && event.keyCode == 0)) return;
        }
    },

    onObserverEvent: function() {
        this.tokenBounds = null;
        if(this.getToken().length >= this.minChars) {
            this.getUpdatedChoices();
        } else {
          this.active = false;
          this.hide();
        }
        this.oldTextInputValue = this.textInput.value;
    },

    getUpdatedChoices: function() {
        var text = this.getToken();
        /*cjo ¼­¹öÃø¿¡ ³Ñ±æ ¿É¼Ç*/
        var callParms = {
            //id                  : this.id,
            //query               : encodeURIComponent(text),
            count               : this.options.count,
            countBackWord       : this.options.countBackWord,
            match_anywhere      : this.options.matchAnywhere,
            ignore_case         : this.options.ignoreCase,
            useBackword         : this.options.useBackword,
            requestParameters   : this.options.requestParameters
        }
        if (text && this.useSuggest == 'Y') {
            this.lastRequestString = text;
            HTML_AJAX.defaultServerUrl = this.url;
            HTML_AJAX.call(this.options.className, this.options.methodName, this.ajaxUpdate.bind(this), encodeURIComponent(text), callParms);
        } else {
            this.hide();
        }
    },

    ajaxUpdate: function(result) {
        //console.debug(result);
        this.updateChoices(result);
    },

    updateChoices: function(choices) {
        this.createSuggestions(choices);

        if (this.suggestions.length == 0 && (!this.options.useBackword || this.backSuggestions.length == 0)) {
            this.suggestionsDiv.innerHTML = "";
            this.hide();
        } else {
            this.updateSuggestionsDiv();
            if (this.click == false) {
                this.suggestionsDiv.style.display = "";
                this.show();
            }
            this.click = false;
        }
    },

    showHistory: function(result) {
        //result = decodeURI(result);
        if (!result) { return false; }
        var historys = result.split("|");
        var regexp = /\\/g
        this.historyHtml = '<div class="history_title">Å°¿öµå È÷½ºÅä¸®</div><ul id="history_list" class="history_list"></ul>';
        this.historyDiv.innerHTML = this.historyHtml;

        for (var i=0; i<historys.length; i++) {
            var str = historys[i].replace(regexp,"");
            this.createHistoryList(str, i);
        }
        if (document.getElementById('history_list').clientHeight > 84) {
            document.getElementById('history_list').style.height = "84px";
        }
        Event.observe(this.historyDiv, 'mouseout', this.historyMouseoutHandler.bindAsEventListener(this));
    },

    historyMouseoutHandler: function(e) {
        this.updateHistorySelection(-1);
    },

    createHistoryList: function(text, id) {
        var historyListLi = document.createElement("li");
        historyListLi.id = "his_"+id;
        historyListLi.className = "history_sub";

        var historyLink = document.createElement("a");
        historyLink.id = "his_a_"+id;
        historyLink.href = '/search/photoList.php?keywordStr='+text;
        historyLink.className = 'history_contents';
        var ex_text = text.toArray();
        var ins_text = '';
        for(var i=0; i<ex_text.length; i++) {
            ins_text += ex_text[i];
            if (i == 30) { ins_text += "..."; historyLink.title = text; break; }
        }
        historyLink.innerHTML = ins_text;

        var historyImg = document.createElement("img");
        historyImg.id = "his_img_"+id;
        historyImg.src = '/images/button/history_del.gif';
        historyImg.className = 'history_del';

        historyListLi.appendChild(historyLink);
        historyListLi.appendChild(historyImg);
        document.getElementById('history_list').appendChild(historyListLi);

        //historyListLi.innerHTML = '<a href=\'/search/photoList.php?keywordStr='+text+'\' class="history_contents">'+text+'</a><img src="/images/button/history_del.gif" class="history_del" onclick="delHistory(\''+id+'\');" />';

        Event.observe(historyListLi, 'mouseover', this.historyMouseoverHandler.bindAsEventListener(this));
        Event.observe(historyImg, 'click', this.historyDelClick.bindAsEventListener(this,id,text));
    },

    historyDelClick: function(e,id,text) {
        delHistory(id,text);
    },

    historyMouseoverHandler: function(e) {
        var src = e.srcElement ? e.srcElement : e.target;
        var index = parseInt(src.id.substring(src.id.lastIndexOf('_')+1));
        this.updateHistorySelection(index);
    },

    updateHistorySelection: function(n) {
        var li = $("his_" + this.selectedHistoryIndex);
        var del = $("his_img_" + this.selectedHistoryIndex);
        var his_a = $("his_a_" + this.selectedHistoryIndex);
        if (li){
            li.style.backgroundColor = "";
            li.style.cursor = "";
            del.style.display = "none";
            his_a.style.color = "#666";
        }
        this.selectedHistoryIndex = n;
        var li = $("his_" + this.selectedHistoryIndex);
        var del = $("his_img_" + this.selectedHistoryIndex);
        var his_a = $("his_a_" + this.selectedHistoryIndex);
        if (li){
            li.style.backgroundColor = '#f4f4f4';
            //li.style.cursor = "pointer";
            del.style.display = "inline";
            his_a.style.color = "#4989f4";
        }
    },

    show: function() {
        /*
        if (!document.getElementById('history_list') && this.options.requestParameters.arg != 'mp' && this.options.requestParameters.arg != 'sch') {
            HTML_AJAX.defaultServerUrl = this.url;
            HTML_AJAX.call(this.options.className, 'gethistorylist', this.showHistory.bind(this));
        }
        */

        var baseDivStyle = this.baseDiv.style;
        var divStyle = this.suggestionsDiv.style;

        if (this.options.useOnOff) {
            if (this.useSuggest == 'Y') {
                this.arrow.src = this.options.arrowDown;
            } else {
                this.arrow.src = this.options.disabledArrowDown;
            }
        }
        this.active = true;
        this.selectedIndex = -1;

        divStyle.height = '';
        divStyle.overflowY = '';

        if (baseDivStyle.display == '') {
            if (this.options.maxHeight && this.baseDiv.clientHeight > (this.options.maxHeight + this.onOffDiv.clientHeight)) {
                divStyle.height = this.options.maxHeight + "px";
                divStyle.overflowY = 'scroll';
                divStyle.overflowX = 'hidden';
            }
            return;
        }
        this.positionSuggestionsDiv();

        divStyle.width = baseDivStyle.width;
        this.onOffDiv.style.width = baseDivStyle.width;

        baseDivStyle.display = '';

        /*cjo Div¹Ú½º³ôÀÌÁ¦¾î*/
        if (this.options.maxHeight && this.baseDiv.clientHeight > (this.options.maxHeight + this.onOffDiv.clientHeight)) {
            divStyle.height = this.options.maxHeight + "px";
            divStyle.overflowY = 'scroll';
            divStyle.overflowX = 'hidden';
        }

        Event.observe(this.baseDiv, 'mouseover', this.divMouseOver.bindAsEventListener(this));
        Event.observe(this.baseDiv, 'mouseout', this.divMouseOut.bindAsEventListener(this));
    },

    divMouseOver: function() {
        this.hasFocus = true;
        //this.textInput.focus();
    },

    divMouseOut: function() {
        this.hasFocus = false;
        this.updateSelection(-1);
        //this.textInput.focus();
    },

    positionSuggestionsDiv: function() {
        //var textPos = RicoUtil.toDocumentPosition(this.textInput);
        //var textPos = RicoUtil.toDocumentPosition($('suggest'));
        var divStyle = this.baseDiv.style;
        if (Prototype.Browser.IE) {
            var bar = -1;
            var line = 2;
        } else {
            var bar = -1;
            var line = 2;
        }
        //divStyle.top  = (textPos.y + this.textInput.offsetHeight + bar) + "px";
        //divStyle.top  = ($('suggest').offsetHeight + bar) + "px";
        //divStyle.left = textPos.x + "px";

        if (this.options.matchTextWidth) {
            /*
            if (this.IE) {
                if (this.options.useOnOff) {
                    divStyle.width = (this.textInput.offsetWidth + this.ArrowSpan.offsetWidth + 2) + "px";
                } else {
                    divStyle.width = (this.textInput.offsetWidth + 2) + "px";
                }
            } else {
                var dv = document.defaultView.getComputedStyle(this.baseDiv, null);
                var divBorderWidth = parseInt(dv.getPropertyValue("border-left-width")) + parseInt(dv.getPropertyValue("border-right-width"));
                if (this.options.useOnOff) {
                    divStyle.width = (this.textInput.offsetWidth + this.ArrowSpan.offsetWidth - divBorderWidth + 2) + "px";
                } else {
                    divStyle.width = (this.textInput.offsetWidth - divBorderWidth + 2) + "px";
                }
            }
            */
            //divStyle.width = ($('suggest').offsetWidth - line) + 'px';
            if (this.options.requestParameters.arg == 'mp') {
                divStyle.width = '536px';
            } else if (this.options.requestParameters.arg == 'sch') {
                divStyle.width = ($('suggest').offsetWidth - line) + 'px';
                this.baseDiv.className = 'schbaseDiv';
            } else {
                divStyle.width = '258px';
            }
        }
    },

    updateSuggestionsDiv: function() {
        this.suggestionsDiv.innerHTML = "";
        var suggestLines = this.createSuggestionSpans();
        this.suggestLines = suggestLines.length;
        for (var i = 0 ; i < suggestLines.length ; i++)
            this.suggestionsDiv.appendChild(suggestLines[i]);
    },

    createSuggestionSpans: function() {
        var regExpFlags = "";
        if (this.options.ignoreCase)
            regExpFlags = 'i';
        var startRegExp = "^";
        if (this.options.matchAnywhere)
            startRegExp = '';

        var lastText = RegExp.escape(this.lastRequestString);
        var regExp = new RegExp(startRegExp + lastText, regExpFlags);

        var suggestionSpans = [];
        var suggestionsLength = this.suggestions.length;
        for (var i = 0; i < suggestionsLength; i++) {
            suggestionSpans.push(this.createSuggestionSpan(i, regExp));
        }
        if (this.options.useBackword && this.backSuggestions.length > 0) {
            regExp = new RegExp(lastText + "$", regExpFlags);
            for (var i = 0; i< this.backSuggestions.length; i++) {
                this.suggestions.push(this.backSuggestions[i]);
            }
            suggestionSpans.push(this.createLine());
            for (var i = suggestionsLength; i < this.suggestions.length; i++) {
                suggestionSpans.push(this.createSuggestionSpan(i, regExp));
            }
        }

        return suggestionSpans;
    },

    createControl: function() {
        var suggestionSpan = document.createElement("span");
        suggestionSpan.style.width   = '100%';
        suggestionSpan.style.display = 'block';
        suggestionSpan.style.clear   = 'both';
        suggestionSpan.className     = this.options.controlClassName;
        return suggestionSpan;
    },

    createLine: function() {
        var suggestionSpan = document.createElement("img");
        suggestionSpan.style.width   = '100%';
        suggestionSpan.style.display = 'block';
        suggestionSpan.style.clear   = 'both';
        suggestionSpan.className     = this.options.lineClassName;
        return suggestionSpan;
    },

    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 };
    },

    createSuggestionSpan: function(n, regExp) {
        var suggestion = this.suggestions[n];

        /*cjo*/
        var suggestionSpan = document.createElement("span");
        suggestionSpan.className = this.options.suggestionClassName;
        suggestionSpan.id            = this.id + "_" + n;
        suggestionSpan.style.width   = '100%';
        suggestionSpan.style.display = 'block';
        suggestionSpan.style.clear   = 'both';

        var textValues = this.splitTextValues(suggestion.text, this.lastRequestString.length, regExp);

        var textSpan = document.createElement("span");
        textSpan.id = this.id + "_text_" + n;
        textSpan.className = this.options.textClassName;

        /*cjo ÀÏÄ¡ºÎºÐ*/
        var textMatchSpan = document.createElement("span");
        textMatchSpan.id            = this.id + "_match_" + n;
        textMatchSpan.className     = this.options.matchClassName;

        /*cjo Ãß°¡¼³¸í*/
        var descriptionSpan = document.createElement("span");
        descriptionSpan.id            = this.id + "_description_" + n;
        descriptionSpan.className     = this.options.descriptionClassName;
        if (this.IE) {
            descriptionSpan.style.styleFloat   = 'right';
        } else {
            descriptionSpan.style.cssFloat   = 'right';
        }

        textMatchSpan.appendChild(document.createTextNode(textValues.mid));
        if (this.options.useValue) {
            descriptionSpan.appendChild(document.createTextNode(suggestion.value));
        }

        textSpan.appendChild(document.createTextNode(textValues.start));
        textSpan.appendChild(textMatchSpan);
        textSpan.appendChild(document.createTextNode(textValues.end));
        suggestionSpan.appendChild(descriptionSpan);
        suggestionSpan.appendChild(textSpan);

        //Event.observe(textSpan, 'mouseover', this.mouseoverHandler.bindAsEventListener(this));
        //Event.observe(textSpan, 'click', this.itemClickHandler.bindAsEventListener(this));
        //Event.observe(textMatchSpan, 'mouseover', this.mouseoverHandler.bindAsEventListener(this));
        //Event.observe(textMatchSpan, 'click', this.itemClickHandler.bindAsEventListener(this));
        //Event.observe(descriptionSpan, 'mouseover', this.mouseoverHandler.bindAsEventListener(this));
        //Event.observe(descriptionSpan, 'click', this.itemClickHandler.bindAsEventListener(this));
        //Event.observe(suggestionSpan, 'mousemove', this.mousemoveHandler.bindAsEventListener(this,suggestionSpan));
        Event.observe(suggestionSpan, 'mouseover', this.mouseoverHandler.bindAsEventListener(this));
        Event.observe(suggestionSpan, 'click', this.itemClickHandler.bindAsEventListener(this));

        return suggestionSpan;
    },

    mousemoveHandler: function(suggestionSpan) {
        var eventArg = $A(arguments);

        Event.observe(eventArg[1], 'mouseover', this.mouseoverHandler.bindAsEventListener(this));
        Event.observe(eventArg[1], 'click', this.itemClickHandler.bindAsEventListener(this));
    },

    mouseoverHandler: function(e) {
        var src = e.srcElement ? e.srcElement : e.target;
        var index = parseInt(src.id.substring(src.id.lastIndexOf('_')+1));
        this.updateSelection(index);
    },

    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;
        }
    },

    itemClickHandler: function(e) {
        this.mouseoverHandler(e);
        this.setInputFromSelection();
        this.textInput.value += ' ';
        this.click = true;
        if (this.textValue != this.textInput.value) {
            this.textValue = this.textInput.value;
            this.onObserverEvent();
        }
    },

    onOffClickHandler: function(e) {
        this.useSuggest = this.useSuggest == 'Y' ? 'N' : 'Y';
        this.delCookie('useSuggest');
        this.setCookie('useSuggest', this.useSuggest);
        this.onOffSpan.innerHTML = this.createOnOffText();
        this.changeArrow();
        if (this.useSuggest == 'Y') {
            this.onObserverEvent();
            this.textInput.focus();
        }
        this.hide();
        this.active = false;
        this.blur = false;
    },

    setInputFromSelection: function() {
        this.textInput.focus();
        var suggestion  = this.suggestions[this.selectedIndex];
        this.updateElement(suggestion);
        this.hide();
    },

    updateElement: function(suggestion) {
        var value = suggestion.text;

        var bounds = this.getTokenBounds();
        if (bounds[0] != -1) {
            var newValue = this.textInput.value.substr(0, bounds[0]);
            var whitespace = this.textInput.value.substr(bounds[0]).match(/^\s+/);
            if (whitespace)
                newValue += whitespace[0];
            if (this.tokenBoundsQ != null) {
                this.textInput.value = newValue + value + this.Q + this.textInput.value.substr(bounds[1]);
                this.tokenBoundsQ = null
            } else {
                this.textInput.value = newValue + value + this.textInput.value.substr(bounds[1]);
            }
        } else {
            if (this.tokenBoundsQ != null) {
                this.textInput.value = value + this.Q;
                this.tokenBoundsQ = null
            } else {
                this.textInput.value = value;
            }
        }
        this.oldTextInputValue = this.textInput.value;
        //this.textValue = this.textInput.value;
    },

    createSuggestions: function(ajaxResponse) {
        this.suggestions = [];
        var entries = eval("("+ajaxResponse+")");
        for (i in entries['foreword']) {
            //var strText = decodeURIComponent(entries['foreword'][i]['text']);
            var strText = entries['foreword'][i]['text'];
            var strValue = entries['foreword'][i]['value'];
            this.suggestions.push({ text: strText, value: strValue });
        }
        if (this.options.useBackword && entries['backword']) {
            this.backSuggestions = [];
            for (i in entries['backword']) {
                //var strText = decodeURIComponent(entries['backword'][i]['text']);
                var strText = entries['backword'][i]['text'];
                var strValue = entries['backword'][i]['value'];
                this.backSuggestions.push({ text: strText, value: strValue });
            }
        }
    },

    getToken: function() {
        var bounds = this.getTokenBounds();
        if (this.textInput.value.substring(bounds[0], bounds[1]).strip().charCodeAt(0) >= 127) {
            this.minChars = this.options.minChars / 2;
        } else {
            this.minChars = this.options.minChars;
        }
        /*
        var keyword = this.textInput.value.substring(bounds[0], bounds[1]).strip();
        var retkeyword = keyword;

        if (this.options.useQ == true) {
            for(var Qindex = 0, Ql = this.options.QKwd.length; Qindex < Ql; ++Qindex) {
                var startPattern = eval('/^'+this.options.QKwd[Qindex]+'.+/g');
                var endPattern = eval('/.+'+this.options.QKwd[Qindex]+'$/g');

                var cnt = this.options.QKwd[Qindex].length;
                if (keyword.match(startPattern)) {
                    retkeyword = keyword.substring(cnt);
                    this.tokenBoundsQ = this.tokenBounds[0];
                }
                if (keyword.match(endPattern)) {
                    this.tokenBoundsQ = null;
                }
            }
        }

        return retkeyword;
        */
        return this.textInput.value.substring(bounds[0], bounds[1]).strip();
    },

    getTokenBounds: function() {
        if (null != this.tokenBounds) return this.tokenBounds;
        var value = this.textInput.value;
        if (value.strip().empty()) return [-1, 0];
        var diff = arguments.callee.getFirstDifferencePos(value, this.oldTextInputValue);
        var offset = (diff == this.oldTextInputValue.length ? 1 : 0);
        var prevTokenPos = -1, nextTokenPos = value.length;
        var tp;
        var addlength;
        for (var index = 0, l = this.options.tokens.length; index < l; ++index) {
            tp = value.lastIndexOf(this.options.tokens[index], diff + offset - 1);
            if (tp > prevTokenPos) {
                prevTokenPos = tp;
                addlength = this.options.tokens[index].length;
            }
            tp = value.indexOf(this.options.tokens[index], diff + offset);
            if (-1 != tp && tp < nextTokenPos) nextTokenPos = tp;
        }

        if (this.options.useQ == true) {
            this.tokenBoundsQ = null;
            for(var Qindex = 0, Ql = this.options.QKwd.length; Qindex < Ql; ++Qindex) {
                var pattern = eval('/'+this.options.QKwd[Qindex]+'/g');
                var match = value.match(pattern);
                if (match != null) {
                    if (match.length % 2 == 1) {
                        var cnt = match.length - 1;
                        this.tokenBoundsQ = value.lastIndexOf(match[cnt]) + this.options.QKwd[Qindex].length;
                        this.Q = this.options.QKwd[Qindex];
                    }
                }
            }
        }

        if (null != this.tokenBoundsQ) {
            return (this.tokenBounds = [this.tokenBoundsQ, nextTokenPos]);
        } else {
            return (this.tokenBounds = [prevTokenPos + addlength, nextTokenPos]);
        }
    }
});

topicSuggest.prototype.getTokenBounds.getFirstDifferencePos = function(newS, oldS) {
    var boundary = Math.min(newS.length, oldS.length);
    for (var index = 0; index < boundary; ++index)
        if (newS[index] != oldS[index])
            return index;
    return boundary;
};

var RicoUtil = {

   getElementsComputedStyle: function ( htmlElement, cssProperty, mozillaEquivalentCSS) {
      if ( arguments.length == 2 )
         mozillaEquivalentCSS = cssProperty;

      var el = $(htmlElement);
      if ( el.currentStyle )
         return el.currentStyle[cssProperty];
      else
         return document.defaultView.getComputedStyle(el, null).getPropertyValue(mozillaEquivalentCSS);
   },

   createXmlDocument : function() {
      if (document.implementation && document.implementation.createDocument) {
         var doc = document.implementation.createDocument("", "", null);

         if (doc.readyState == null) {
            doc.readyState = 1;
            doc.addEventListener("load", function () {
               doc.readyState = 4;
               if (typeof doc.onreadystatechange == "function")
                  doc.onreadystatechange();
            }, false);
         }

         return doc;
      }

      if (window.ActiveXObject)
          return Try.these(
            function() { return new ActiveXObject('MSXML2.DomDocument')   },
            function() { return new ActiveXObject('Microsoft.DomDocument')},
            function() { return new ActiveXObject('MSXML.DomDocument')    },
            function() { return new ActiveXObject('MSXML3.DomDocument')   }
          ) || false;

      return null;
   },

   getContentAsString: function( parentNode ) {
      return parentNode.xml != undefined ? 
         this._getContentAsStringIE(parentNode) :
         this._getContentAsStringMozilla(parentNode);
   },

   _getContentAsStringIE: function(parentNode) {
      var contentStr = "";
      for ( var i = 0 ; i < parentNode.childNodes.length ; i++ )
         contentStr += parentNode.childNodes[i].xml;
      return contentStr;
   },

   _getContentAsStringMozilla: function(parentNode) {
      var xmlSerializer = new XMLSerializer();
      var contentStr = "";
      for ( var i = 0 ; i < parentNode.childNodes.length ; i++ )
         contentStr += xmlSerializer.serializeToString(parentNode.childNodes[i]);
      return contentStr;
   },

   toViewportPosition: function(element) {
      return this._toAbsolute(element,true);
   },

   toDocumentPosition: function(element) {
      return this._toAbsolute(element,false);
   },

   /**
    *  Compute the elements position in terms of the window viewport
    *  so that it can be compared to the position of the mouse (dnd)
    *  This is additions of all the offsetTop,offsetLeft values up the
    *  offsetParent hierarchy, ...taking into account any scrollTop,
    *  scrollLeft values along the way...
    *
    * IE has a bug reporting a correct offsetLeft of elements within a
    * a relatively positioned parent!!!
    **/
   _toAbsolute: function(element,accountForDocScroll) {

      if ( navigator.userAgent.toLowerCase().indexOf("msie") == -1 )
         return this._toAbsoluteMozilla(element,accountForDocScroll);

      var x = 0;
      var y = 0;
      var parent = element;
      while ( parent ) {

         var borderXOffset = 0;
         var borderYOffset = 0;
         if ( parent != element ) {
            var borderXOffset = parseInt(this.getElementsComputedStyle(parent, "borderLeftWidth" ));
            var borderYOffset = parseInt(this.getElementsComputedStyle(parent, "borderTopWidth" ));
            borderXOffset = isNaN(borderXOffset) ? 0 : borderXOffset;
            borderYOffset = isNaN(borderYOffset) ? 0 : borderYOffset;
         }

         x += parent.offsetLeft - parent.scrollLeft + borderXOffset;
         y += parent.offsetTop - parent.scrollTop + borderYOffset;
         parent = parent.offsetParent;
      }

      if ( accountForDocScroll ) {
         x -= this.docScrollLeft();
         y -= this.docScrollTop();
      }

      return { x:x, y:y };
   },

   /**
    *  Mozilla did not report all of the parents up the hierarchy via the
    *  offsetParent property that IE did.  So for the calculation of the
    *  offsets we use the offsetParent property, but for the calculation of
    *  the scrollTop/scrollLeft adjustments we navigate up via the parentNode
    *  property instead so as to get the scroll offsets...
    *
    **/
   _toAbsoluteMozilla: function(element,accountForDocScroll) {
      var x = 0;
      var y = 0;
      var parent = element;
      while ( parent ) {
         x += parent.offsetLeft;
         y += parent.offsetTop;
         parent = parent.offsetParent;
      }

      parent = element;
      while ( parent &&
              parent != document.body &&
              parent != document.documentElement ) {
         if ( parent.scrollLeft  )
            x -= parent.scrollLeft;
         if ( parent.scrollTop )
            y -= parent.scrollTop;
         parent = parent.parentNode;
      }

      if ( accountForDocScroll ) {
         x -= this.docScrollLeft();
         y -= this.docScrollTop();
      }

      return { x:x, y:y };
   },

   docScrollLeft: function() {
      if ( window.pageXOffset )
         return window.pageXOffset;
      else if ( document.documentElement && document.documentElement.scrollLeft )
         return document.documentElement.scrollLeft;
      else if ( document.body )
         return document.body.scrollLeft;
      else
         return 0;
   },

   docScrollTop: function() {
      if ( window.pageYOffset )
         return window.pageYOffset;
      else if ( document.documentElement && document.documentElement.scrollTop )
         return document.documentElement.scrollTop;
      else if ( document.body )
         return document.body.scrollTop;
      else
         return 0;
   }

};

