(function( $ ){
    $.fn.suggest = function( options ) {

        var settings = {
            suggest: "activity-suggest",
            maxMatches: 10,
            data: { }
        };
        
        // If options exist, lets merge them
        // with our default settings
        if ( options ) { 
            $.extend( settings, options );
        }

        var nodes = {};
        var state = {};
        var data = settings.data;
        var currentLevel = 0;
        var activeItem = null;
        
        state.searchMode = false;
        state.open = false;
        
        nodes.input = this;
        nodes.container = this.parent();

        nodes.keywordOverlay = $('<div class="keywordOverlay"></div>');

        nodes.suggestBox = $('<div class="suggest"></div>');
        nodes.suggestBoxInner = $('<div class="suggest-inner"></div>');
        nodes.levels = [];
        
        settings.width = nodes.input.outerWidth();
        
        nodes.input.attr("autocomplete", "off");       
        nodes.suggestBox.append(nodes.suggestBoxInner);                


        createLevel(settings.data.level1);


        function createLevel(items) {
            var level = $('<ul class="nav"></ul>');
            if (currentLevel > 0) {
               level.append('<li><a href="#" class="back">&lt; Back</a></li>');
            }

            for (i = 0; i < items.length; i++) {
                var newLi = $('<li></li>');
            
                var itemIndex = items[i];
                if (settings.data.items[itemIndex].children && settings.data.items[itemIndex].children.length > 0) {
                    newLi.addClass("parent");
                }
                if (settings.data.items[itemIndex].type === "all") {
                    newLi.addClass("all");
                }                
                newLi.html('<a href="#">' + settings.data.items[itemIndex].name + '</a>');
                newLi.data('item', settings.data.items[itemIndex]);
                
                level.append(newLi);         
            }
            
            pushLevel(level);
        }

        function pushLevel(level) {
            var newLeft = currentLevel * -settings.width;
            nodes.levels[currentLevel] = level;
            nodes.suggestBoxInner.append(level);
            nodes.suggestBoxInner.css("left", newLeft + "px");
            if (level.outerHeight() > 0) {
                nodes.suggestBox.css("height", level.outerHeight() + "px");
            }
            currentLevel++;
        }
        function popLevel() {
            currentLevel--;
            var newLeft = (currentLevel-1) * -settings.width;            
            nodes.suggestBoxInner.css("left", newLeft + "px");
            if (nodes.levels[currentLevel-1].outerHeight() > 0) {
                nodes.suggestBox.css("height", nodes.levels[currentLevel-1].outerHeight() + "px");
            }            
            setTimeout(function(){
                nodes.levels[currentLevel].remove();                       
            }, 500);
        }
        
        function open() {
            nodes.suggestBox.addClass("show");
            state.open = true;
        }
        
        function close() {
            nodes.suggestBox.removeClass("show");
            state.open = false;            
        }
        
        function showNav() {
            toggleSearchMode(false);
            if (nodes.levels[currentLevel].outerHeight() > 0) {
                nodes.suggestBox.css("height", nodes.levels[currentLevel].outerHeight() + "px");
            }                    
        }
        
        function searchTerms(term){
   
            toggleSearchMode(true);
            
            nodes.suggestBox.find(".results").remove();
            
            var results = $('<ul class="results"></ul>');
            var count = 0;
            
            for(i = 0; i < data.items.length; i++) {
                //var haystack = data.items[i].value.toLowerCase();
                var haystack = data.items[i].name.toLowerCase();
                var needle = term.toLowerCase();
                
                if (haystack.indexOf(needle) != -1) {
                    count++;                

                    var newLi = $('<li></li>');     
                    if (count == 1) {
                        newLi.addClass("active");
                        activeItem = 0;
                    }
                    //newLi.html('<a href="#">' + data.items[i].value + '</a>');
                    newLi.html('<a href="#">' + data.items[i].name + '</a>');
                    newLi.data('item', settings.data.items[i]);

                    results.append(newLi);                    
                    if (count >= settings.maxMatches) {
                        break;
                    }

                }                                
            }
            nodes.suggestBox.append(results);
            if (results.outerHeight() > 0) {
                nodes.suggestBox.css("height", results.outerHeight() + "px");
            }
            // TODO: If no results found then must be a free text keyword, so clear the hidden keyword.
            //if (count == data.items.length) {
            //   nodes.container.find(".realkeywordfield").val("");
            //}
            
        }
        
        function toggleSearchMode(newvalue) {
            if (state.searchMode != newvalue) {
                state.searchMode = newvalue;        
                if (newvalue == true) {
                    nodes.suggestBox.addClass("searchmode");
                } else {
                    nodes.suggestBox.removeClass("searchmode");
                }
                return true;
            } else {
                return false;
            }
        }

        function setActive(item) {
            deselectActive();
            item.addClass("active");
            activeItem = item;
        }
        function deselectActive() {
            if (activeItem) {            
                activeItem.removeClass("active");
            }
            activeItem = null;            
        }
        
        nodes.input.after(nodes.suggestBox);        

        nodes.input.bind("keydown", function(event){
            switch (event.keyCode) {
                case 9: // Tab
/*                     $(this).val(activeItem.value); */
                    close();
                    break;
                case 13: // Enter
                    event.preventDefault()
/*                     $(this).val(activeItem.value);                            */
                    break;                            
            }
        });
        
        nodes.input.bind("focus blur keyup click", function(event) {
            event.stopPropagation();

            switch (event.type) {
                case "focus":
                    open();
                    break;
                case "blur":
/*                     nodes.suggestBox.removeClass("show");  */
                    break;
                case "keyup":
                    switch (event.keyCode) {
                        case 27: // Esc
                            close();
                            break;
                        case 38: // Up arrow
                            if (activeItem) {
                                setActive(activeItem.prev());
                            }
                            break;
                        case 40: // Down arrow
                            if (activeItem) {
                                setActive(activeItem.next());
                            } else {
                                var list = state.searchMode ? $(".results") : nodes.levels[currentLevel-1];         
                                setActive($(list.find("li")[0]));
                            }
                            break;

                        // TODO: Return key selects the highlighted entry

                        default:
                            open();
                            // Clear the hidden keyword if freetexting
                            nodes.container.find(".realkeywordfield").val('');
                            var term = $(this).val();
                            if (term != "") {
                                searchTerms(term);
                            } else {
                                currentLevel = 0;
                                showNav();
                            }
                            break;                            
                    }
                    break;
            }
        });
        
        
        $(document).click(function(){
            close();
        });


        nodes.suggestBox.delegate("li", "hover", function(event){
            switch (event.type) {
                case "mouseenter":
                    setActive($(this));
                    break;
                case "mouseleave":
                    deselectActive();     
                    break;
            }
        }); 

        nodes.suggestBox.delegate(".nav a", "click", function(event){
            event.preventDefault();
            event.stopPropagation();
            
            if ($(this).hasClass("back")) {
                popLevel();
                nodes.input.val("");
                nodes.container.find(".realkeywordfield").val("");
            } else {
                    
                var item = $(this).parent().data("item");

                //nodes.input.val(item.value);
                nodes.input.val(item.name.replace(/&amp;/g,'&'));
                nodes.container.find(".realkeywordfield").val(item.value);

                if (item.children && item.children.length > 0) {
                    createLevel(item.children);
                } else {
/*                     nodes.input.val(item.value); */
                    close();
                }

            }
        });

        nodes.suggestBox.delegate(".results a", "click", function(event){
            event.preventDefault();
            event.stopPropagation();
            
            var item = $(this).parent().data("item");
            //nodes.input.val(item.value);
            nodes.input.val(item.name.replace(/&amp;/g,'&'));
            nodes.container.find(".realkeywordfield").val(item.value);
            close();
        });        

        return {
            node: this,
            close: close,
            open: open
        }
    
    };
})( jQuery );

