
Autocompleter.LocalAdvanced = Class.create(Autocompleter.Base, {
    initialize: function(element, update, array, options) {
        var hidden_input = new HiddenInput(options["elHidden"], this);
        this.composer = $(options["elComposer"]);
        options["updateElement"] = options["updateElement"].curry(array, this.composer, hidden_input);

        this.baseInitialize(element, update, options);
        this.options.array = array;
        this.wrapper = $(this.element.parentNode);
        
        if (!this.element.hacks) {
            this.element.should_use_borderless_hack = Prototype.Browser.WebKit;
            this.element.should_use_shadow_hack = Prototype.Browser.IE || Prototype.Browser.Opera;
            this.element.hacks = true;
        }
        if (this.element.should_use_borderless_hack || this.element.should_use_shadow_hack) {
            this.wrapper.addClassName('tokenizer_input_borderless');
        }

        this.message = this.composer.select(".facebookComposerAutoPopulate").first();
        if (Object.isElement(this.message)) {
            this.messageText = this.message.innerHTML;
        }

        var elInputContainer = $(element).up("div.tokenizer");
        if (elInputContainer != null) {
            elInputContainer.setStyle({
                backgroundColor: element.getStyle("backgroundColor")
            });
            elInputContainer.observe('click', function(event){
                var el = event.element();
                if (el.identify() != this.element.identify()) {
                    //console.log("set focus by click");
//                    setTimeout(function(evt){
                        el.select('input.facebookComposerAutoInput').first().focus();
//                    }, 150);
                }
            }.bind(this));
        }

    
        this.options.onShow = function(element,update) {
//            var elClono = element.parentNode.parentNode;
            Position.clone(element.parentNode.parentNode, update, {
                setHeight: false,
                setWidth: false,
                offsetTop: element.parentNode.parentNode.offsetHeight
            });
            update.show();
        }
        this.options.onHide = function(element, update) {
            update.update(this.messageText).hide()
        }.bind(this);

        this.element.observe('focus', this.checkShowMessage.bind(this));
    },
    getUpdatedChoices: function() {
        this.updateChoices(this.options.selector(this));
    },

    checkShowMessage: function(evt){
        this.element.writeAttribute('isFocused', '1');
//        console.log("checkShowMessage");

        // Move the cursor to the end of the user inputted text
//        evt.element().value = evt.element().value;
        if (evt.element().setSelectionRange) {
            evt.element().setSelectionRange(evt.element().value.length, evt.element().value.length);
        } else if (evt.element().createTextRange) {
            var FieldRange = evt.element().createTextRange();
            FieldRange.moveStart('character', evt.element().value.length);
            FieldRange.collapse();
            FieldRange.select();
        }

         // Ignore this focus event the first time onBlur fires
        // (IE fires when you scroll the list of choices)
        if (!Object.isUndefined(this.noUpdate) && this.noUpdate) {
            this.noUpdate = false;
        } else {
            if (Object.isUndefined(this.ignoreScrollBar) || !this.ignoreScrollBar) {
                // Do something on entering autocomplete field if not scrolling the choices list
                if (this.element.value == "" && !Object.isUndefined(this.message)) {
                    this.message.show();
                } else {
                    this.message.hide();
                }
            }
        }
    },
    onBlur: function($super, event) {
        this.noUpdate = true;
        if (!Object.isUndefined(this.ignoreScrollBar) && this.ignoreScrollBar) {
//            console.log("ingore blur input");
            //var el = event.element();
            event.stop();
            event.element().focus();
        } else {
//            console.log("blur input start");
            if (this.element.readAttribute('isFocused') == "1") {
                if (!Object.isUndefined(this.ignoreBlurTimer) && this.ignoreBlurTimer != null) {
                    clearTimeout(this.ignoreBlurTimer);
//                    console.log("Clear blur timeout" + this.ignoreBlurTimer);
                    this.ignoreBlurTimer = null;
                }
                this.element.writeAttribute('isFocused', '0');
                this.ignoreBlurTimer = setTimeout(function(){
                    this.noUpdate = false;
                    //var test = this;
                    var t = this.element.readAttribute('isFocused');
                    if (t != "1") {
//                        console.log("blur input");
                        if (Object.isUndefined(this.ignoreScrollBar) || !this.ignoreScrollBar) {
                            if (this.index > 0) {
                                this.selectEntry();
                            }
                            $super();
                            //move itself back to the end on blur
                            if (this.wrapper.nextSiblings().length > 0) {
                                this.wrapper.nextSiblings().last().insert({
                                    after: this.wrapper
                                });
                            }
                        }
                    }
                }.bind(this), 250);
            }
        }

    },
    set_input_size: function(size) {
        size = size || 20;
        this.element.setStyle({width: size + "px"});
    },
    onKeyPress: function(event) {
        //dynamically resize the input field
        var new_size = 20 + (this.element.value.length * 7);
        this.set_input_size(Math.min(new_size, 340));
        // active is when there's suggesitons found
        if (this.active) {
            switch (event.keyCode) {
                case Event.KEY_TAB:
                case Event.KEY_RETURN:
                    if (!event.stopped) {
                        this.selectEntry();
                    }
                    Event.stop(event);
                case Event.KEY_ESC:
                    this.hide();
                    this.active = false;
                    Event.stop(event);
                    return;
                case Event.KEY_LEFT:
                case Event.KEY_RIGHT:
                    return;
                case Event.KEY_UP:
                    this.markPrevious();
                    this.render();
                    Event.stop(event);
                    return;
                case Event.KEY_DOWN:
                    this.markNext();
                    this.render();
                    Event.stop(event);
                    return;
            }
    
        } else {
            if (event.keyCode == Event.KEY_TAB || event.keyCode == Event.KEY_RETURN ||
            (Prototype.Browser.WebKit > 0 && event.keyCode == 0) || event.keyCode == 44 /* , comma */ || event.keyCode == 188 ) {
            var email_addr = this.element.value.strip().sub(',', '');
            // recognise email format
            if (validate_email(email_addr)) {
                addEmailToList(email_addr);
                Event.stop(event);
            }
            this.element.value = "";
            this.set_input_size();
            return false;
        }
        switch (event.keyCode) {
            //jump left to token
            case Event.KEY_LEFT:
            case Event.KEY_BACKSPACE:
                if (this.element.value == "" && typeof this.wrapper.previous().token != "undefined") {
                    this.wrapper.previous().token.select();
    
                }
                return;
            //jump right to token
            case Event.KEY_RIGHT:
                if (this.element.value == "" && this.wrapper.next() && typeof this.wrapper.next().token != "undefined") {
                    this.wrapper.next().token.select();
                }
            }
        }
    
        this.changed = true;
        this.hasFocus = true;
    
        if (this.observer) {
            clearTimeout(this.observer);
        }
        this.observer = setTimeout(this.onObserverEvent.bind(this), this.options.frequency * 1000);
    },

    boldMatches: function(str) {
        
    },
    ignoreIeScroll: function() {
            if (!Object.isUndefined(this.ignoreScrollTimer) && this.ignoreScrollTimer != null) {
                clearTimeout(this.ignoreScrollTimer);
//                console.log("Clear scroller timeout" + this.ignoreScrollTimer);
                this.ignoreScrollTimer = null;
            }
            this.ignoreScrollBar = true;
            this.ignoreScrollTimer = setTimeout(function(){
//                console.log("Honor Scroll Close");
                this.ignoreScrollBar = false;
                this.noUpdate = true;
                this.element.focus();
            }.bind(this), 900);
//            console.log("Start scroller timeout" + this.ignoreScrollTimer);
    },
    setOptions: function(options) {
        this.options = Object.extend({
            choices: 10,
            partialSearch: true,
            partialChars: 2,
            ignoreCase: true,
            fullSearch: false,
            idField: 'uid',
            selector: function(instance) {
                var ret = [];
                // Beginning matches
                var partial = [];
                // Inside matches
                var entry = instance.getToken();
                var count = 0;

                for (var i = 0; i < instance.options.array.length && ret.length < instance.options.choices; i++) {
                    var elem = instance.options.array[i];
                    var elem_name = elem[instance.options.search_field];
                    var foundPos = instance.options.ignoreCase ?
                    elem_name.toLowerCase().indexOf(entry.toLowerCase()) :
                    elem_name.indexOf(entry);

                    while (foundPos != -1) {
                        if (foundPos == 0 && elem_name.length != entry.length) {
                            var value = "<strong>" + elem_name.substr(0, entry.length) + "</strong>" + elem_name.substr(entry.length);
//                            "<li value='" + i + "'>" + "<div>" + value + "</div>"
                            
                            var retVal = "<li value='" + i + "'>" + "<div>" + elem.displayVal + "</div>";
                            if (!Object.isUndefined(elem.displayDetail)) {
                                retVal += "<div>" + elem.displayDetail + "</div>";
                            }
                            retVal += "<div style=\"display:none\">" + elem[instance.options.idField] + "</div>";
                            retVal += "</li>";
                            ret.push(retVal);
                            break;

                        } else if (entry.length >= instance.options.partialChars && instance.options.partialSearch && foundPos != -1) {
                            if (instance.options.fullSearch || /\s/.test(elem_name.substr(foundPos - 1, 1))) {
                                var value = elem_name.substr(0, foundPos) + "<strong>" +
                                elem_name.substr(foundPos, entry.length) + "</strong>" + elem_name.substr(foundPos + entry.length)

//                            "<li value='" + i + "'>" + "<div>" + value + "</div>"
                            
                                var retVal = "<li value='" + i + "'>" + "<div>" + elem.displayVal + "</div>";
                                if (!Object.isUndefined(elem.displayDetail)) {
                                    retVal += "<div>" + elem.displayDetail + "</div>";
                                }
                                retVal += "<div style=\"display:none\">" + elem[instance.options.idField] + "</div>";
                                retVal += "</li>";
                                partial.push(retVal);
                                break;

                            }

                        }
                        foundPos = instance.options.ignoreCase ?
                        elem_name.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1) :
                        elem_name.indexOf(entry, foundPos + 1);
                    }
                }
                if (partial.length) {
                    ret = ret.concat(partial.slice(0, instance.options.choices - ret.length));
                }
                var myUl = new Element('ul').update(ret.join(''));
                myUl.observe('scroll', instance.ignoreIeScroll.bind(instance));
                //return "<ul onscroll=\"alert('scroll')\">" + ret.join('') + "</ul>";
                return myUl;
            }
        },
        options || {});
    }
});


HiddenInput = Class.create({
    initialize: function(element, auto_complete) {
        this.element = $(element);
        this.auto_complete = auto_complete;
        this.token;
        Event.observe(this.element, 'keydown', this.onKeyPress.bindAsEventListener(this));
    },
    onKeyPress: function(event) {
        var ttt = this;
        if (!Object.isUndefined(this.token) && this.token.selected) {
            switch (event.keyCode) {
                case Event.KEY_LEFT:
                    this.token.element.insert({before: this.auto_complete.wrapper});
                    this.token.deselect();
                    this.auto_complete.element.focus();
                    return false;
                case Event.KEY_RIGHT:
                    this.token.element.insert({after: this.auto_complete.wrapper});
                    this.token.deselect();
                    this.auto_complete.element.focus();
                    return false;
                case Event.KEY_BACKSPACE:
                case Event.KEY_DELETE:
                    this.token.element.remove();
                    this.auto_complete.element.focus();
                    return false;
            }
        }
    }
});

Token = Class.create({
    initialize: function(element, hidden_input) {
        this.element = $(element);
        this.hidden_input = hidden_input;
        this.element.token = this;
        this.selected = false;
        Event.observe(document, 'click', this.onclick.bindAsEventListener(this));
    },
    select: function() {
        this.hidden_input.token = this;
        this.hidden_input.element.activate();
        this.selected = true;
        this.element.addClassName('token_selected');
    },
    deselect: function() {
        this.hidden_input.token = undefined;
        this.selected = false;
        this.element.removeClassName('token_selected')
    },
    onclick: function(event) {
        if (this.detect(event) && !this.selected) {
            this.select();
        } else {
            this.deselect();
        }
    },
    detect: function(e) {
        //find the event object
        var eventTarget = e.target ? e.target: e.srcElement;
        var token = eventTarget.token;
        var candidate = eventTarget;
        while (token == null && candidate.parentNode) {
            candidate = candidate.parentNode;
            token = candidate.token;
        }
        return token != null && token.element == this.element;
    }
});











GrowableTextarea = Class.create({
    charCount: 0,

    initialize: function(textarea, options)
    {
        var gt = this;

        this.textarea = $(textarea);
        this.options = $H({
            'min_height' : 30,
            'max_height' : 125,
            'max_length' : -1
        }).update(options);

        this.textarea.observe('keydown', this.refresh.bind(this));
//        this.textarea.observe('keyup', this.refreshUp.bind(this));
//        this.textarea.observe('focus', this.refreshStart.bind(this));
//        this.textarea.observe('blur', this.refreshStop.bind(this));

        this.textarea.setStyle({
            overflowY: 'auto',
            overflowX: 'hidden'
        });


        this._shadow = new Element('div').setStyle({
            lineHeight : this.textarea.getStyle('lineHeight'),
            fontSize   : this.textarea.getStyle('fontSize'),
            fontFamily : this.textarea.getStyle('fontFamily'),
            position   : 'absolute',
            top        : '-10000px',
            left       : '-10000px',
//            width: this.textarea.getWidth()-5 + 'px',
            wordWrap: 'break-word',
            overflowY  : 'scroll',

            textAlign:    this.textarea.getStyle('textAlign'),
            paddingTop:    '2px',
            paddingRight:  '2px',
            paddingBottom: '2px',
            paddingLeft:   '2px'
/*
            paddingTop:    this.textarea.getStyle('paddingTop'),
            paddingRight:  this.textarea.getStyle('paddingRight'),
            paddingBottom: this.textarea.getStyle('paddingBottom'),
            paddingLeft:   this.textarea.getStyle('paddingLeft'),

            borderTopWidth:    this.textarea.getStyle('borderTopWidth'),
            borderRightWidth:  this.textarea.getStyle('borderRightWidth'),
            borderBottomWidth: this.textarea.getStyle('borderBottomWidth'),
            borderLeftWidth:   this.textarea.getStyle('borderLeftWidth')
*/
        });
        this.textarea.insert({ after: this._shadow });

        var taSetWidth = function() {
            gt._shadow.setStyle({
                width: gt.textarea.getWidth()-5 + 'px'
            });
        }
        taSetWidth.defer();

        this._remainingCharacters = new Element('p').addClassName('remainingCharacters');
        this.textarea.insert({after: this._remainingCharacters});
        this.refresh();
    },
/*
    refreshStart: function(evt) {
        var fb = this;
        this.growInterval = window.setInterval(function(){fb.refresh(1,2)}, 400);
    },
    refreshStop: function(evt) {
        clearInterval(this.growInterval);
    },
    refreshDown: function(evt) {
        this.refresh(evt, true);
    },
    refreshUp: function(evt) {
        this.refresh(evt, false);
    },
    refresh: function(evt, isDown)
*/
    refresh: function(evt)
    {
        var myText = $F(this.textarea);

        if (evt != null && evt.keyCode != null) {// && evt.keyCode == Event.KEY_RETURN) {
            //myText += "\n";
            if (evt.keyCode == Event.KEY_RETURN) {
                myText += "\n";
            } else if (evt.keyCode == Event.KEY_BACKSPACE) {
                //myText = myText.substring(0, myText.length-1);
            } else {
                myText += "A";
            }
        }

        this._shadow.update(myText.replace(/\n/g, '<br/>'));

        var lineHeight = parseInt(this.textarea.getStyle('lineHeight').replace('px', ''));
        // IE is stupid and reports "" for the lineheight since it's not set explicitly... just use 16 as a buffer
        if (isNaN(lineHeight)) {
            lineHeight = 16;
        }
        var textHeight = $(this._shadow).getHeight();
        var newHeight  = 0;

        if (this.options.get('min_height') > -1 && textHeight + 2*lineHeight < this.options.get('min_height')) {
            newHeight = this.options.get('min_height');
        } else if (this.options.get('max_height') > -1 && textHeight + lineHeight > this.options.get('max_height')) {
            newHeight = this.options.get('max_height');
        } else {
            newHeight = textHeight;
            if (this.charCount < myText.length && myText.substr(myText.length-1) == "\n") {
                newHeight += lineHeight;
            }
        }
        if (this.options.get('min_height') > -1 && newHeight < this.options.get('min_height')) {
            newHeight = this.options.get('min_height');
        }
        this.textarea.setStyle({
//            height: Math.max(parseInt(this._shadow.getHeight()) + parseInt(this.textarea.getStyle('lineHeight').replace('px', '')), this.options.get('min_height')) + 'px'
            height: newHeight + 'px'
//            ,overflowY: 'scroll'
        });

        if (this.options.get('max_length') >= 0) {
            var remaining = this.options.get('max_length') - $F(this.textarea).length;
            this._remainingCharacters.update(Math.abs(remaining)  + ' characters ' + (remaining > 0 ? 'remaining' : 'over the limit'));
        }
        this.charCount = myText.length;
    }
});

