/* -*- Mode: java; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

//  NOTE: The popup menu with id "contactsMenu" must exist before
//  using this interface.
// 
//  This interface fires two events:
//   - autocompletion:changed : fired when a new contact is selected
//   - autocompletion:changedlist : fired when a new list is selected
//
var SOGoAutoCompletionInterface = {

    // Attributes that could be changed from the object
    // inheriting the inteface
    uidField: "c_name",
    addressBook: null,
    excludeGroups: false,
    excludeLists: false,

    // Internal attributes
    animationParent: null,
    selectedIndex: -1,
    delay: 0.750,
    delayedSearch: false,
    menu: null,

    bind: function () {
        this.menu = $('contactsMenu');
        this.writeAttribute("autocomplete", "off");
        this.writeAttribute("container", null);
        this.confirmedValue = null;
        this.observe("keydown", this.onKeydown.bindAsEventListener(this));
        this.observe("blur", this.onBlur.bindAsEventListener(this));
    },
    
    onKeydown: function (event) {
        if (event.ctrlKey || event.metaKey) {
            this.focussed = true;
            return;
        }
        if (event.keyCode == Event.KEY_TAB) {
            if (this.confirmedValue)
                this.value = this.confirmedValue;
            else
                this.writeAttribute("uid", null);
             if (document.currentPopupMenu)
                hideMenu(document.currentPopupMenu);
        }
        else if (event.keyCode == 0
                 || event.keyCode == Event.KEY_BACKSPACE
                 || event.keyCode == Event.KEY_DELETE
                 || event.keyCode == 32  // Space
                 || event.keyCode > 47) {
            this.confirmedValue = null;
            this.selectedIndex = -1;
            if (this.delayedSearch)
                window.clearTimeout(this.delayedSearch);
            this.delayedSearch = this.performSearch.delay(this.delay, this);
        }
        else if (event.keyCode == Event.KEY_RETURN) {
            preventDefault(event);
            if (this.confirmedValue)
                this.value = this.confirmedValue;
            else
                this.writeAttribute("uid", null);
            if (document.currentPopupMenu)
                hideMenu(document.currentPopupMenu);
            this.selectedIndex = -1;
            if (this.readAttribute("container")) {
                this.confirmedValue = null;
                this.fire("autocompletion:changedlist", this.readAttribute("container"));
            }
            else
                this.fire("autocompletion:changed", event.keyCode);
        }
        else if (this.menu.getStyle('visibility') == 'visible') {
            if (event.keyCode == Event.KEY_UP) { // Up arrow
                if (this.selectedIndex > 0) {
                    var contacts = this.menu.select("li");
                    contacts[this.selectedIndex--].removeClassName("selected");
                    this.value = contacts[this.selectedIndex].readAttribute("address");
                    this.confirmedValue = this.value;
                    this.writeAttribute("uid", contacts[this.selectedIndex].readAttribute("uid"));
                    contacts[this.selectedIndex].addClassName("selected");
                    var container = contacts[this.selectedIndex].readAttribute("container");
                    if (container)
                        this.writeAttribute("container", container);
                }
            }
            else if (event.keyCode == Event.KEY_DOWN) { // Down arrow
                var contacts = this.menu.select("li");
                if (contacts.size() - 1 > this.selectedIndex) {
                    if (this.selectedIndex >= 0)
                        contacts[this.selectedIndex].removeClassName("selected");
                    this.selectedIndex++;
                    this.value = contacts[this.selectedIndex].readAttribute("address");
                    this.confirmedValue = this.value;
                    this.writeAttribute("uid", contacts[this.selectedIndex].readAttribute("uid"));
                    contacts[this.selectedIndex].addClassName("selected");
                    var container = contacts[this.selectedIndex].readAttribute("container");
                    if (container)
                        this.writeAttribute("container", container);
                }
            }
        }
    },

    onBlur: function (event) {
        if (this.delayedSearch)
            window.clearTimeout(this.delayedSearch);
        if (this.confirmedValue) {
            this.value = this.confirmedValue;
            if (this.readAttribute("container"))
                this.fire("autocompletion:changedlist", this.readAttribute("container"));
            else
                this.fire("autocompletion:changed", event.keyCode);
        }
        else
            this.writeAttribute("uid", null);
    },

    performSearch: function (input) {
        // Perform address completion
        if (document.contactLookupAjaxRequest) {
            // Abort any pending request
            document.contactLookupAjaxRequest.aborted = true;
            document.contactLookupAjaxRequest.abort();
        }
        if (input.value.trim().length > 2) {
            var urlstr = UserFolderURL + "Contacts/";
            if (input.addressBook)
                urlstr += input.addressBook + "/contact";
            else
                urlstr += "allContact";
            urlstr += "Search?search=" + encodeURIComponent(input.value);
            if (input.excludeGroups)
                urlstr += "&excludeGroups=1";
            if (input.excludeLists)
                urlstr += "&excludeLists=1";
            if (input.animationParent)
                startAnimation(input.animationParent);
            document.contactLookupAjaxRequest =
                triggerAjaxRequest(urlstr, input.performSearchCallback.bind(input), input);
        }
        else {
            if (document.currentPopupMenu)
                hideMenu(document.currentPopupMenu);
        }
    },

    performSearchCallback: function (http) {
        if (http.readyState == 4) {
            var list = this.menu.down("ul");

            var input = http.callbackData;

            if (http.status == 200) {
                var start = input.value.length;
                var data = http.responseText.evalJSON(true);

                if (data.contacts.length > 1) {
                    list.select("li").each(function(item) {
                            item.stopObserving("mousedown");
                            item.remove();
                        });

                    // Populate popup menu
                    for (var i = 0; i < data.contacts.length; i++) {
                        var contact = data.contacts[i];
                        var completeEmail = contact["c_cn"];
                        if (contact["c_mail"])
                            completeEmail += " <" + contact["c_mail"] + ">";
                        var node = new Element('li', { 'address': completeEmail,
                                                       'uid': contact[this.uidField] });
                        var matchPosition = completeEmail.toLowerCase().indexOf(data.searchText.toLowerCase());
                        if (matchPosition > -1) {
                            var matchBefore = completeEmail.substring(0, matchPosition);
                            var matchText = completeEmail.substring(matchPosition, matchPosition + data.searchText.length);
                            var matchAfter = completeEmail.substring(matchPosition + data.searchText.length);
                            node.appendChild(document.createTextNode(matchBefore));
                            node.appendChild(new Element('strong').update(matchText));
                            node.appendChild(document.createTextNode(matchAfter));
                        }
                        else {
                            node.appendChild(document.createTextNode(completeEmail));
                        }
                        list.appendChild(node);
                        if (contact['c_name'].endsWith (".vlf")) {
                            // Keep track of list containers
                            node.writeAttribute("container", contact['container']);
                        }
                        if (contact["contactInfo"])
                            node.appendChild(document.createTextNode(" (" + contact["contactInfo"] + ")"));
                        $(node).observe("mousedown", this.onAddressResultClick.bindAsEventListener(this));
                    }

                    // Show popup menu
                    var offsetScroll = Element.cumulativeScrollOffset(input);
                    var offset = Element.positionedOffset(input);
                    if ($(document.body).hasClassName("popup") && typeof initPopupMailer == 'undefined')
                    // Hack for some situations where the offset must be computed differently
                         offset = Element.cumulativeOffset(input);
                    var top = offset.top - offsetScroll.top + node.offsetHeight + 3;
                    var height = 'auto';
                    var heightDiff = window.height() - offset[1];
                    var nodeHeight = node.getHeight();

                    if ((data.contacts.length * nodeHeight) > heightDiff)
                        // Limit the size of the popup to the window height, minus 12 pixels
                        height = parseInt(heightDiff/nodeHeight) * nodeHeight - 12 + 'px';

                    this.menu.setStyle({ top: top + "px",
                                left: offset[0] + "px",
                                height: height,
                                visibility: "visible" });
                    this.menu.scrollTop = 0;

                    document.currentPopupMenu = this.menu;
                    $(document.body).stopObserving("click");
                    $(document.body).observe("click", onBodyClickMenuHandler);
                }
                else {
                    if (document.currentPopupMenu)
                        hideMenu(document.currentPopupMenu);

                    if (data.contacts.length == 1) {
                        // Single result
                        var contact = data.contacts[0];
                        input.writeAttribute("uid", contact[this.uidField]);
                        if (contact['c_name'].endsWith(".vlf")) {
                            this.writeAttribute("container", contact['container']);
                        }
                        var completeEmail = contact["c_cn"];
                        if (contact["c_mail"])
                            completeEmail += " <" + contact["c_mail"] + ">";
                        if (contact["c_cn"].substring(0, input.value.length).toUpperCase()
                            == input.value.toUpperCase())
                            input.value = completeEmail;
                        else
                            // The result matches email address, not user name
                            input.value += ' >> ' + completeEmail;
                        input.confirmedValue = completeEmail;
                        
                        var end = input.value.length;
                        $(input).selectText(start, end);
                        
                        this.selectedIndex = -1;
                    }
                }
            }
            else
                if (document.currentPopupMenu)
                    hideMenu(document.currentPopupMenu);
            document.contactLookupAjaxRequest = null;
        }
    },

    onAddressResultClick: function(event) {
        var e = Event.element(event);
        if (e.tagName != 'LI')
            e = e.up('LI');
        if (e) {
            preventDefault(event);
            this.value = e.readAttribute("address");
            this.writeAttribute("uid", e.readAttribute("uid"));
            if (e.readAttribute("container"))
                this.fire("autocompletion:changedlist", e.readAttribute("container"));
            else {
                this.confirmedValue = this.value;
                this.fire("autocompletion:changed", Event.KEY_RETURN);
            }
        }
    }
};
