var _complete = new Object();
//if (!onupfunctions)
//    var onupfunctions = new Array();

function console_log(message)
{
    try{
        console.log(message);
    } catch (e) {}
}

function arrayIndexOf(array, object) 
{
    for (var i = 0; i < array.length; i++) {
        if (array[i] == object)
            return i;
    }
    return -1;
}

check_complete = function(e)
{
    e = (e) ? e : ((window.event) ? window.event : null);
    if (e !== null)
    {
        for (id in _complete)
        {
            _complete[id].check_click_source(e, id);
        }
    }
};

// BACKPORTED from dojo1.1 <ag.widget.autocomplete>
// Remove an autocomplete widget from the _complete "registry".  Added to
// support replacing recipient email textarea with single-recipient text
// input for gift cards.  -- mpirnat, 10/06/2008
autocomplete_unregister = function(id) {                              
    if(_complete[id]) { 
        delete _complete[id];
    }                   
};  

if (document.addEventListener)
    document.addEventListener("mouseup", check_complete, false);
else
    document.attachEvent("onmouseup", check_complete);

function AutoComplete(element, suggest_url)
{
    var auto = this;
    _complete[element.id] = this;
    
    this.request = new Requester(suggest_url, "POST", true, false);
    this.debug = document.getElementById("debug");
    this.element = element;
    this.suggestions = new Array();
    this.inputText = null;
    this.search_text = null;
    
    // position variables
    this.top = 0;
    this.left = 0;
    this.cursor = -1;
        
    this.open = false;
    this.max_suggestions = 15;
    this.selectedIdx = -1;
    this.suggest_url = suggest_url;

    // default styles
    this.class_name = "agi-auto-complete";
    this.class_selected = "agi-auto-complete-selected";
    
    // must type more than this many characters to get a suggestion
    this.min_len = 0;
    
    // look for the auto-complete-div or create it if missing
    this.popup = document.getElementById(element.id + "-auto-complete-div");
    if (!this.popup)
        this.popup = createDiv(this.element.id);

    // look for the auto-complete-iframe or create it if missing
    this.iframe = document.getElementById(element.id + "-auto-complete-iframe");
    if (!this.iframe)
        this.iframe = createIFrame(this.element.id);
    
    // Keycode constants
    var TAB = 9;
    var ENTER = 13;
    var ESC = 27;
    var KEYUP = 38;
    var KEYDN = 40;
    var KEYLFT = 37;
    var KEYRGT = 39;
    var KEYSHFT = 16;
    
    // turn off the browser's autocomplete on the element
    this.element.setAttribute("autocomplete", "off");

    this.is_open = function()
    {
        return _complete[element.id].open;
    };
    
    this.check_click_source = function(e, id)
    {
        if (!_complete[element.id].is_open())
        {
            // cancel pending queries
            if (_complete[element.id].request.in_process)
                _complete[element.id].request.onsuccess = null;
            return;
        } else {
            var my_ids = new Array(id, id + "-auto-complete-div", id + "-auto-complete-ifram");
            var clicked = get_event_source(e);
            
            //if (my_ids.indexOf(clicked.id) == -1)
            if (arrayIndexOf(my_ids, clicked.id) == -1) {
                if ((clicked.id.indexOf(id + "-href-") !== 0) 
                    && (clicked.id.indexOf(id + "-li-") !== 0) 
                    && (clicked.id.indexOf(id + "-div-") !== 0))
                {
                    // cancel pending queries
                    if (_complete[element.id].request.in_process)
                        _complete[element.id].request.onsuccess = null;
                    _complete[element.id].hidePopup();
                }
            }
        }
        
    };
    
    this.makeVisible = function()
    {
        var popup_bottom = this.popup.clientHeight + this.top - getScrollOffset().pageYOffset;
        var new_top = this.top - this.element.offsetHeight - this.popup.clientHeight;
        var window_height = getSize().height;
        
        // position the popup above the element if it will fit there but not below
        if (popup_bottom > window_height && new_top > 0)
        {
            this.popup.style.top = new_top + "px";
            this.iframe.style.top = new_top + "px";
        }
    };
    
    this.positionPopup = function()
    {       
        var elem = this.element;
        this.left = 0;
        this.top = elem.offsetHeight;

        //Walk up the DOM and add up all of the offset positions.
        while (elem.offsetParent && elem.tagName.toUpperCase() != 'BODY')
        {
            //if (elem.id != "lightbox")
            //{
                this.left += elem.offsetLeft;
                this.top += elem.offsetTop;
            //}
            elem = elem.offsetParent;
        }

        this.left += elem.offsetLeft;
        this.top += elem.offsetTop;
        
        this.popup.style.left = this.left + 'px';
        this.popup.style.top = this.top + 'px';
    };
    
    this.showPopup = function()
    {
        this.selectedIdx = -1;
    
        this.iframe.style.display = "block";
        this.popup.style.display = "block";
        this.popup.scrollTop = 0;
        
        var width = this.popup.clientWidth + "px";
        var ul = document.getElementById(element.id + "-ul");
        var lis = ul.getElementsByTagName('DIV');
        for (i = 0; i < lis.length; i++)
        {
            lis[i].style.width = width;
        }
        
        if (lis.length > 15)
        {
            lineHeight = lis[0].scrollHeight;
            divHeight = lineHeight * 15;
            this.popup.style.height = divHeight + "px";
            this.iframe.style.height = divHeight + "px";
            this.popup.style.overflow = "auto";
            this.popup.style.overflowX = "hidden";
        } else {
            this.popup.style.height = "";
            this.iframe.style.height = "";
            this.popup.style.overflow = "";
        }
        
        this.popup.style.zIndex = "500";
        this.iframe.style.zIndex = "499";
        this.iframe.style.background = "#FFFFFF";
        this.iframe.style.width = this.popup.clientWidth + "px";
        this.iframe.style.height = this.popup.clientHeight + "px";
        this.iframe.style.left = this.popup.style.left;
        this.iframe.style.top = this.popup.style.top;
        this.open = true;
        this.makeVisible();
    };
    
    this.hidePopup = function()
    {
        this.selectedIdx = -1;
        this.iframe.style.display = "none";
        this.popup.style.display = "none";
        this.open = false;
    };

    
    this.bind_element = function(element)
    {
        this.element = element;
        
        // if the popup is visible, don't allow arrow keys to move the cursor
        element.onkeypress = function(e)
        {
            var thisKey = auto.getKeyCode(e);
            switch(thisKey)
            {
                case TAB:
                case KEYUP:
                case KEYDN:
                case KEYLFT:
                case KEYRGT:
                case ENTER:
                case ESC:
                    return (auto.popup.style.display == "none");
                default:
                    return true;
            }
        };

        element.onkeyup = function(e)
        {
            var thisKey = auto.getKeyCode(e);
        
            switch(thisKey)
            {
                case TAB:
                case ESC:
                case KEYUP:
                case KEYDN:
                case KEYLFT:
                case KEYRGT:
                    return (auto.popup.style.display == "none");
                case KEYSHFT:
                    return true;
                default:
                    var cur_text = auto.getSearchValue(auto.element);
                    if (cur_text != auto.inputText)
                    {   
                        auto.inputText = cur_text;
                        if  (cur_text.length > auto.min_len)
                            auto.searchSuggestions();
                        else
                            auto.hidePopup();   
                    }// else {
                    //  auto.hidePopup();
                    //}
                    return true;
            }
        };

        element.onkeydown = function(e)
        {
            var thisKey = auto.getKeyCode(e);
    
            switch(thisKey)
            {
                case ENTER:
                    auto.useSuggestion();
                break;
    
                case TAB:
                    if (auto.selectedIdx > -1)
                    {
                        auto.useSuggestion();
                    } else {
                        auto.hidePopup();
                        if (auto.request.in_process)
                            auto.request.onsuccess = null;
                        focus_next_element(auto.element);
                    }
                break;
    
                case ESC:
                    var status = (auto.popup.style.display == "none");
                    auto.hidePopup();
                    return status;
                break;
    
                case KEYUP:
                    if (auto.selectedIdx > 0)
                        auto.selectedIdx--;
                    //else
                    //  auto.selectedIdx = auto.suggestions.length - 1;
                    auto.changeSelected(thisKey);
                    return (auto.popup.style.display == "none");
                break;

                case KEYDN:
                    if (auto.selectedIdx < (auto.suggestions.length - 1))
                        auto.selectedIdx++;
                    //else
                    //  auto.selectedIdx = 0;
                    auto.changeSelected(thisKey);
                    return (auto.popup.style.display == "none");
                break;
            }
        };
        
    };
    
    this.bind_element(this.element);
    
    this.getKeyCode = function(e)
    {
        if(e)           //Firefox
            return e.keyCode;
        if(window.event)    //IE
            return window.event.keyCode;
    };
    
    this.createSuggestions = function(search_text)
    {
        var ul = document.createElement('ul');
        ul.setAttribute("id", element.id + "-ul");
        ul.style.listStyleType = "none";
        ul.style.margin = "0px";
        ul.style.padding = "0px";
        ul.style.cursor = "pointer";
                
        //Create an array of LI's for the words.
        //for (i = 0; i < this.suggestions.length && i < this.max_suggestions; i++)
        for (i = 0; i < this.suggestions.length; i++)
        {
            var linkText = this.getDisplaySuggestion(this.suggestions[i]);
            if (search_text)
            {
                fidx = linkText.toLowerCase().indexOf(search_text);
                linkText = linkText.substring(0,fidx) +
                            "<b>" + linkText.substring(fidx, fidx + search_text.length) +
                            "</b>" + linkText.substring(fidx + search_text.length);
            }
            linkText = linkText.replace(/ /g, "&nbsp;");
            
            var li = document.createElement('li');
            li.setAttribute("id", element.id + "-li-" + i);
            var d = document.createElement('div');
            d.setAttribute("id", element.id + "-div-" + i);
            d.setAttribute("style", "cursor: pointer;");    
            
            var a = document.createElement('a');
            a.href="javascript:void(null)";
            a.innerHTML = linkText;
            a.setAttribute("class", this.class_name);
            a.setAttribute("className", this.class_name);
            a.setAttribute("id", element.id + "-href-" + i);
            d.appendChild(a);
            li.appendChild(d);
            //li.appendChild(a);
    
            if (auto.selectedIdx == i)
            {
                li.setAttribute("class", this.class_selected);
                li.setAttribute("className", this.class_selected);
                a.className = this.class_selected;
            } else {
                li.setAttribute("class", this.class_name);
                li.setAttribute("className", this.class_name);
            }

            ul.appendChild(li);
        }
    
        this.popup.replaceChild(ul,this.popup.childNodes[0]);
    

        /********************************************************
        mouseover handler for the dropdown ul
        move the highlighted suggestion with the mouse
        ********************************************************/
        ul.onmouseover = function(ev)
        {
            //Walk up from target until you find the LI.
            var target = auto.getEventSource(ev);
            while (target.parentNode && target.tagName.toUpperCase() != 'LI')
            {
                target = target.parentNode;
            }
        
            var lis = auto.popup.getElementsByTagName('LI');
            
    
            for (i = 0; i < lis.length; i++)
            {
                var li = lis[i];
                if(li == target)
                {
                    auto.selectedIdx = i;
                    break;
                }
            }
            auto.changeSelected();
        };

        /********************************************************
        click handler for the dropdown ul
        insert the clicked suggestion into the input
        ********************************************************/
        ul.onclick = function(ev)
        {
            auto.useSuggestion();
            auto.hidePopup();
            auto.cancelEvent(ev);
            return false;
        };
    
        this.popup.className = this.class_name;
        this.popup.style.position = 'absolute';
    };
    
    this.useSuggestion = function()
    {
        if (this.selectedIdx > -1)
        {
            var suggested_email = this.suggestions[this.selectedIdx];
            this.applySuggestion(suggested_email);
            this.hidePopup();
            this.selectedIdx = -1;
            this.inputText = "";
            this.search_text = "";


            //intentionally lose focus on the element to discard the enter event;
            this.element.blur();

            //It's impossible to cancel the Tab key's default behavior. 
            //So this undoes it by moving the focus back to our field right after
            //the event completes.
            setTimeout("focus_element('" + this.element.id + "')",10);

            // IE needs to be told where to position the cursor again...
            if (this.cursor != -1)
                setTimeout("set_cursor_position('" + this.element.id + "'," + this.cursor + "," + this.cursor + ")", 15);
            this.setSuggestionUsage(suggested_email,'k');
        }
    };
    
    this.setSuggestionUsage = function(address,type)
    {
        // Store autocomplete indicator in hidden webvar.
        try {
            var autokomp = document.getElementsByName("autokomp")[0];
            var usage_value = autokomp.value;
            var entry = trim(address) + "|" + type;
            entry = encodeURIComponent(entry);
            
            if (usage_value.length > 0)
                usage_value += "," + entry;
            else
                usage_value = entry;
            autokomp.value = usage_value;
        } catch(e) {
            console_log('error = ' + e);
        }
       
    };

    this.changeSelected = function(keyPressed)
    {
        if (!keyPressed)
            keyPressed = '';
        var lis = this.popup.getElementsByTagName('LI');

        var height = lis[0].scrollHeight;
        if (!isIE)
            height = height + 1;
        var divScroll = this.popup.scrollTop + (this.popup.clientHeight * 1);

        for (i = 0; i < lis.length; i++)
        {
            var li = lis[i];
            if (this.selectedIdx == i)
            {
                li.className = this.class_selected;
                li.getElementsByTagName("A")[0].className = this.class_selected;
                if (lis.length > 15 && (keyPressed == KEYDN || keyPressed == KEYUP))
                {
                    var scroll = height * i;
                    if (scroll > divScroll)
                        this.popup.scrollTop = this.popup.scrollTop + height;
                    else if (scroll < this.popup.scrollTop)
                        this.popup.scrollTop = scroll;
                }
            }
            else
            {
                li.className = this.class_name;
                li.getElementsByTagName("A")[0].className = this.class_name;
            }
        }
    };
    
    this.getEventSource = function(ev)
    {
        if(ev)          //Moz
            return ev.target;
    
        if(window.event)    //IE
            return window.event.srcElement;
    };
    
    this.cancelEvent = function(ev)
    {
        if(ev)          //Moz
        {
            ev.preventDefault();
            ev.stopPropagation();
        }

        if(window.event)    //IE
            window.event.returnValue = false;
    };
    
    this.searchSuggestions = function()
    {
        auto.request.onsuccess = auto.onsuccess;
        if (!auto.request.in_process)
        {
            auto.search_text = auto.getSearchValue(auto.element);
            auto.request.sendRequest("q=" + encodeURIComponent(auto.getSearchValue(auto.element)));
        }
    };
    
    this.onsuccess = function(req)
    {
        var cur_text = auto.getSearchValue(auto.element);
        if (cur_text != auto.search_text && cur_text.length > auto.min_len )
        {
            auto.searchSuggestions();
            return;
        }
        try {
            eval("auto.suggestions = " + req.responseText);
        } catch (e) {
            auto.hidePopup();
            return;
        }
        auto.suggestions.sort(compare_contacts);    
        auto.createSuggestions(auto.search_text);
        auto.positionPopup();
        if (auto.suggestions.length > 0)
            auto.showPopup();
        else
            auto.hidePopup();
    };
        
    // override the getDisplaySuggestion, applySuggestion, and getSearchValue
    // functions if suggestions are not simple arrays of strings.
    this.getDisplaySuggestion = function(suggestion)
    {
        return suggestion;
    };
    
    this.applySuggestion = function(suggestion)
    {
        this.element.value = suggestion;
    };

    this.getSearchValue = function(el)
    {
        return this.element.value;
    };
}

// functions used to create the popup div and the iframe
// used to hide controls in IE.
function createIFrame(parent_id)
{
    var iframe = document.createElement("IFRAME");
    iframe.setAttribute("src", "javascript:void(null)");
    iframe.setAttribute("scrolling", "no");
    iframe.setAttribute("frameBorder", "0");
    iframe.setAttribute("id", parent_id + "-auto-complete-iframe");
    iframe.style.width = "0px";
    iframe.style.height = "0px";
    iframe.style.position = "absolute";
    iframe.style.display = "none";
//  objParent.appendChild(iframe);
    document.body.appendChild(iframe);
    return iframe;
}

function createDiv(parent_id)
{
    var div = document.createElement("DIV");
    div.setAttribute("id", parent_id + "-auto-complete-div");
    div.style.display = "none";
//  div.style.overflow = "auto";
    
    var list = document.createElement("UL");

    div.appendChild(list);
//  objParent.appendChild(div);
    document.body.appendChild(div);
    return div;
}

// bma custom page contact autocomplete
function CustomEventComplete(elId, to_name, to_email)
{
    // methods to work on storage
    var wcomplete = this;
    var complete;
    var toname    = to_name;
    var toemail   = to_email;

    // set up AutoComplete object
    if (_complete[elId])
    {
        complete = _complete[elId];
        complete.bind_element(document.getElementById(elId));
    } else {
        complete = new AutoComplete(document.getElementById(elId), ahost + '/reminders/contactsearch.pd');
    }
    
    //Actually finds matches
    var oldcomplete = complete.searchSuggestions;
    complete.searchSuggestions = function()
    {
        if (!preloaded)
        {
            oldcomplete();
            return;
        }
            
        complete.suggestions = new Array();

        // text to be searched for
        var search = (complete.getSearchValue(complete.element) + "").toLowerCase();

        //pl_contacts is wombat storage object, match text to storage
        for (i in pl_contacts)
        {
            var first_name = (pl_contacts[i].first_name + "").toLowerCase();
            var last_name = (pl_contacts[i].last_name + "").toLowerCase();
            var email = (pl_contacts[i].email + "").toLowerCase();
            if (email.indexOf(search) === 0 ||
                    first_name.indexOf(search) === 0 ||
                    last_name.indexOf(search) === 0)
                complete.suggestions.push(pl_contacts[i]);
        }

        // handles results of search
        complete.suggestions.sort(compare_contacts);    
        complete.createSuggestions(search);
        complete.positionPopup();

        // popup display
        if (complete.suggestions.length > 0)
            complete.showPopup();
        else
            complete.hidePopup();
    };

    complete.getDisplaySuggestion = function(suggestion)
    {
            return wcomplete.assembleContact(suggestion).replace("<","&#60;").replace(">", "&#62;");
    };
    
    this.assembleContact = function(suggestion)
    {
        var fname = (suggestion.first_name === null) ? "" : suggestion.first_name;
        var lname = (suggestion.last_name === null) ? "" : suggestion.last_name;
        var space = (lname.length > 0 && fname.length > 0) ? " " : "";
        var name = (lname.length > 0 || fname.length > 0) ? '"' + fname + space + lname +'"' : "";
        var email = (suggestion.email === null || suggestion.email.length === 0) ? "" : " <" + suggestion.email + ">";
        return name + email;
    };
    
    complete.applySuggestion = function(suggestion)
    {
        var re = /\&\#(\d*)\;/g ;
        // fill in name and email fields
        if (toname) {
            if (suggestion.first_name !== null && suggestion.last_name !== "")
                toname.value = suggestion.first_name.replace(re, get_unicode);
        }
        if (toemail) {
            if (suggestion.email !== null && suggestion.email !== "")
                toemail.value = suggestion.email;
        }
    };
}


// reminders add/edit page contact autocomplete
function WombatEventComplete(elId, contact_arg)
{
    var wcomplete = this;
    var contact = contact_arg;
    if (_complete[elId])
    {
        var complete = _complete[elId];
        complete.bind_element(document.getElementById(elId));
    } else {
        var complete = new AutoComplete(document.getElementById(elId), ahost + '/reminders/contactsearch.pd');
    }
    
    var oldcomplete = complete.searchSuggestions;
    complete.searchSuggestions = function()
    {
        if (!preloaded)
        {
            oldcomplete();
            return;
        }
            
        complete.suggestions = new Array();
//      for (i = 0; i < pl_contacts.length; i++)
        var search = (complete.getSearchValue(complete.element) + "").toLowerCase();
        for (i in pl_contacts)
        {
            var first_name = (pl_contacts[i].first_name + "").toLowerCase();
            var last_name = (pl_contacts[i].last_name + "").toLowerCase();
            var email = (pl_contacts[i].email + "").toLowerCase();
            if (email.indexOf(search) === 0 ||
                    first_name.indexOf(search) === 0 ||
                    last_name.indexOf(search) === 0)
                complete.suggestions.push(pl_contacts[i]);
        }
        complete.suggestions.sort(compare_contacts);    
        complete.createSuggestions(search);
        complete.positionPopup();
        if (complete.suggestions.length > 0)
            complete.showPopup();
        else
            complete.hidePopup();
    };

    complete.getDisplaySuggestion = function(suggestion)
    {
            return wcomplete.assembleContact(suggestion).replace("<","&#60;").replace(">", "&#62;");
    };
    
    this.assembleContact = function(suggestion)
    {
        var fname = (suggestion.first_name === null) ? "" : suggestion.first_name;
        var lname = (suggestion.last_name === null) ? "" : suggestion.last_name;
        var space = (lname.length > 0 && fname.length > 0) ? " " : "";
        var name = (lname.length > 0 || fname.length > 0) ? '"' + fname + space + lname +'"' : "";
        var email = (suggestion.email === null || suggestion.email.length === 0) ? "" : " <" + suggestion.email + ">";
        return name + email;
    };
    
    complete.applySuggestion = function(suggestion)
    {
        var re = /\&\#(\d*)\;/g ;
        // fill in name and email fields
        if (contact.lname) {
            if (suggestion.last_name !== null && suggestion.last_name !== "")
                contact.lname.value = suggestion.last_name.replace(re, get_unicode);
        }
        if (contact.fname) {
            if (suggestion.first_name !== null && suggestion.last_name !== "")
                contact.fname.value = suggestion.first_name.replace(re, get_unicode);
        }
        if (contact.email) {
            if (suggestion.email !== null && suggestion.email !== "")
                contact.email.value = suggestion.email;
        }
        // check the correct gender
        if (contact.male && suggestion.gender !== null && suggestion.gender.toLowerCase() == "m")
            contact.male.checked = true;
        else if (contact.female)
            contact.female.checked = true;
        
        // select the correct relationship and type if set for the contact
        if (contact.relationship_type && suggestion.relate_type !== null)
        {
            contact.relationship_type.value = suggestion.relate_type;
            var options = relate_options[suggestion.relate_type];
        
            for (var j = contact.relationship.options.length - 1; j > -1; j--)
                contact.relationship.remove(j);
            
            contact.relationship.appendChild(get_option("", "Relationship"));       
            
            for (var i=0; i < options.length; i++)
            {
                var this_option = get_option(options[i].id, options[i].description);
                if (contact.relationship && suggestion.relationship !== null && options[i].id == suggestion.relationship)
                    this_option.setAttribute("selected", true);
                    
                contact.relationship.appendChild(this_option);
            }
        }
        
        // try to set the display values if this is the event detail page
        try {
            if (suggestion.first_name !== null && suggestion.first_name !== "")
                contact.fname_display.innerHTML = contact.fname.value + "&nbsp;";           
            if (suggestion.last_name !== null && suggestion.last_name !== "")
                contact.lname_display.innerHTML = contact.lname.value + "&nbsp;";
            if (suggestion.email !== null && suggestion.email !== "")
                contact.email_display.innerHTML = contact.email.value + "&nbsp;";
            contact.gender_display.innerHTML = (contact.male.checked) ? "Male" : "Female";
            contact.relationship_display.innerHTML = contact.relationship.options[contact.relationship.selectedIndex].text  + "&nbsp;";
        } catch(e) {
        }
    };
}

// reminders textarea email autocomplete
function TextAreaComplete(elId)
{
    var complete;
    var textcomplete = this;
    if (_complete[elId])
    {
        complete = _complete[elId];
        complete.bind_element(document.getElementById(elId));
    } else {
        complete = new AutoComplete(document.getElementById(elId), ahost + '/reminders/contactsearch.pd');
    }
    
    // Expose this as property of "class" so that its functions can be decorated later
    this.baseCompleter = complete;
    
    var oldcomplete = complete.searchSuggestions;
    complete.searchSuggestions = function()
    {
        if (!preloaded)
        {
            oldcomplete();
            return;
        }
            
        complete.suggestions = new Array();
        var search = (complete.getSearchValue(complete.element) + "").toLowerCase();
        for (g in pl_groups)
        {
            var label = (pl_groups[g].label + "").toLowerCase();
            
            //if (label == search)
            //{
            //  complete.suggestions = new Array();
            //  complete.applySuggestion(pl_groups[g]);
            //  break;
            //}
            
            if (label.indexOf(search) === 0)
                complete.suggestions.push(pl_groups[g]);
        }
        for (i in pl_contacts)
        {
            var first_name = (pl_contacts[i].first_name + "").toLowerCase();
            var last_name = (pl_contacts[i].last_name + "").toLowerCase();
            var email = (pl_contacts[i].email + "").toLowerCase();
            var f = (first_name.length > 0) ? first_name + " " : "";
            var l = (last_name.length > 0) ? last_name + " " : "";
            var full = f + l;
            
            if (email.toLowerCase() == search)
            {
                complete.suggestions = new Array();
                break; 
            }
            
            if (((email.indexOf(search) === 0 ||
                    first_name.indexOf(search) === 0 ||
                    last_name.indexOf(search) === 0) ||
                    full.indexOf(search) === 0) &&
                    (email.length > 0))
                complete.suggestions.push(pl_contacts[i]);
        }
        complete.suggestions.sort(compare_contacts);
        complete.createSuggestions(search);
        complete.positionPopup();
        if (complete.suggestions.length > 0)
            complete.showPopup();
        else
            complete.hidePopup();
    };

    complete.getDisplaySuggestion = function(suggestion)
    {
        return textcomplete.assembleContact(suggestion).replace("<","&#60;").replace(">", "&#62;");
    };
    
    complete.applySuggestion = function(suggestion)
    {
        var suggestion_text = "";
        if (!suggestion.label)
            suggestion_text = suggestion.email;
        else
            suggestion_text = get_group_emails(suggestion);
        if(this.element.type == 'textarea') {
            var elStr = this.element.value;
            var position = get_cursor_position(this.element);
            var start = position - complete.getSearchValue(complete.element).length;
            var before_text = elStr.substring(0, start);
            var after_text = elStr.substring(position);
            
            var white_before = (before_text.search(/\s+$/g) != -1 || before_text.length === 0);     
            var white_after = (after_text.search(/^\s+/g) != -1);
            
            var prefix = (white_before) ? "" : " ";
            var postfix = (white_after) ? "," : ", ";
            

            var newValue = prefix + suggestion_text + postfix;
            this.element.value =  before_text + newValue + after_text;
            this.cursor = start + newValue.length;
            //textcomplete.setPosition(this.element, this.cursor, this.cursor);
        } else {
            this.element.value = suggestion_text;
        }
    };
        
    complete.getSearchValue = function(el)
    {
        var elStr = el.value;
        var position = get_cursor_position(el);
        var idx = elStr.lastIndexOf(",", position);
        var start = (idx == -1) ? 0 : idx + 1;
        idx = elStr.indexOf(",", position);
        var end = (idx == -1) ? elStr.length - 1 : idx - 1;
        return elStr.substring(start, position).replace(/^\s*|\s*$/g,"");
    };
    
    this.assembleContact = function(suggestion)
    {
        if (!suggestion.label)
        {
            var fname = (suggestion.first_name === null) ? "" : suggestion.first_name;
            var lname = (suggestion.last_name === null) ? "" : suggestion.last_name;
            var space = (lname.length > 0 && fname.length > 0) ? " " : "";
            var name = (lname.length > 0 || fname.length > 0) ? '"' + fname + space + lname +'"' : "";
            var email = (suggestion.email === null || suggestion.email.length === 0) ? "" : " <" + suggestion.email + ">";
            return name + email;
        } else {
            return suggestion.label + " (group)";
        }
    };
    
}

function get_cursor_position(area)
{
    // IE loses focus on the text area when clicking a suggestion -- force it back.
    try {
        area.focus();
    } catch(e){}
    
    if( document.selection && area.type == 'textarea')
    {
        // The current selection
        var range = document.selection.createRange();
        // We'll use this as a 'dummy'
        var stored_range = range.duplicate();
        // Select all text
        stored_range.moveToElementText( area );
        // Now move 'dummy' end point to end point of original range
        stored_range.setEndPoint( 'EndToEnd', range );
        // Now we can calculate start and end points
        area.selectionStart = stored_range.text.length - range.text.length;
        area.selectionEnd = area.selectionStart + range.text.length;
    }

    return area.selectionEnd;
}

function set_cursor_position(area_id, start, end) {
    var area = document.getElementById(area_id);
    if (navigator.appName.indexOf("Microsoft") == -1) {
        area.setSelectionRange(start, end);
    } else {
        // assumed IE
        var range = area.createTextRange();
        range.collapse(true);
        range.moveStart("character", start);
        range.moveEnd("character", end - start);
        range.select();
    }
}

function focus_next_element(element) 
{
    var idx = -1;
    for (var i = 0; i < element.form.elements.length; i++)
    {
        if (element.form.elements[i] == element && i < (element.form.elements.length - 1))
            idx = i;
    }
    
    if (idx != -1)
        element.form.elements[idx].focus();
}

function focus_element(elem_id)
{
    try {
        document.getElementById(elem_id).focus();
    } catch (e) {}
}

function get_unicode(str, digits, offset, s)
{
    // create a unicode string from the digits in an xmlcharref
    digits = parseInt(digits);
    return String.fromCharCode(digits);
}

function get_event_source(ev)
{
    if(ev) {        //Moz
        if (ev.target)
            return ev.target;
        else if (ev.srcElement) //IE
            return ev.srcElement;
    }

    if(window.event)    //IE
        return window.event.srcElement;
}

