var search_form     = document.getElementById   ("search");
var search_box      = search_form.querySelector ("input[name=q]");
var search_results  = search_form.querySelector (".suggestions");
var search_query    = "";

// Send Ajax request to find suggestions
function search_topics (event)
{
    /**
     * Remember user query.
     * Used to restore original value because it could have been changed
     * when highlighting a result item. This value is used to restore the
     * original query (not a suggestion's text) when no suggestion is selected.
     */
    search_query = search_box.value;
    
    // Empty search?
    if (search_box.value.length == 0)
    {
        hide_results ();
        search_results.innerHTML = "";
        return;
    }
    
    // Send XMLHttpRequest request
    var xhr = new XMLHttpRequest ();
    
    // xhr.addEventListener ("loadstart", ...);
    // xhr.addEventListener ("loadend", ...);
    // xhr.addEventListener ("progress", ...);
    // xhr.addEventListener ("error", ...);
    // xhr.addEventListener ("abort", ...);
    
    xhr.addEventListener ("load", function (event) {
        
        switch (xhr.status)
        {
            case 200: // OK
                
                // Retrieve response (should contain items as HTML)
                search_results.innerHTML = xhr.response;
                
                // No results found?
                if (xhr.response.length == 0)
                {
                    hide_results ();
                    break;
                }
                
                // Reset scroll position to top, and show results
                search_results.scrollTop = 0;
                show_results ();
                
                /**
                * Bind a "mouseover" event to all result items.
                * Highlight result when mouse moving over it (as
                * opposed to using Up/Down keys).
                */
                search_results
                    .querySelectorAll ("*")
                    .forEach (function (item, index) {
                        item.addEventListener ("mousemove", function (event) {
                            highlight_result (event.target);
                        });
                    });
                
                break;
            
            default:
                break;
        }
    });
    
    xhr.open ("GET", "suggest?q=" + search_box.value, true);
    xhr.send ();
}

/**
 * Handler for "click" events on the entire page.
 * This is created when the list of results is visible, and it's
 * meant to hide the list when users click anywhere else on the page.
 * This is removed once the list is no longer visible.
 */
function document_click_handler (event)
{
    hide_results ();
}

/**
 * Handler for "click" events on the search form.
 * The only reason for this event, is to stop bubbling up of the "click"
 * event when users click inside the search form, when the list of
 * results is visible. This is required because if the list of results is
 * visible and the user clicks on the search box, the list gets hidden.
 * In other words, this event is used to prevent the execution of document_click_handler().
 */
function searchform_click_handler (event)
{
    event.stopPropagation();
}

// Show the list of results.
function show_results ()
{
    search_results.style.display = "flex";
    
    // Attach "click" events to hide list when user clicks
    // outside of the list.
    document.addEventListener ("click", document_click_handler);
    search_form.addEventListener ("click", searchform_click_handler);
}

// Show the list of results.
function hide_results ()
{
    search_results.style.display = "none";
    
    // Remove all "click" events attached by show_results().
    document.removeEventListener ("click", document_click_handler);
    search_form.removeEventListener ("click", searchform_click_handler);
}

// Highlight a single item in the list of results
function highlight_result (the_result)
{
    // Remove selection class from all items in the list
    search_results
        .querySelectorAll ("*")
        .forEach (function (item, index) {
            item.classList.remove ("highlight");
        });
    
    // Add selection class to new item
    the_result && the_result.classList.add ("highlight");
    
    // Replace searchbox text with item text
    search_box.value = the_result ? the_result.text : search_query;
    
    // Move cursor to the end of the text box
    search_box.setSelectionRange (search_box.value.length, search_box.value.length);
    
    /**
     * Scroll search_results. This is required if there are too many elements, because
     * simply changing the CSS class above won't scroll the list.
     */
    the_result && the_result.scrollIntoView ({
        behavior:   "instant",
        block:      "nearest",
        inline:     "nearest"
    });
}

// When pressing "Arrow down", select the next item in the search-results list
function select_next_result ()
{
    // Is the list of results hidden?
    if (search_results.style.display == "none")
    {
        show_results ();
        return;
    }
    
    // Current selected item in the list
    var selected_item = search_results.querySelector ("a.highlight");
    
    // Find next item to select
    selected_item = selected_item
                  ? selected_item.nextElementSibling
                  : search_results.firstElementChild;
    
    highlight_result (selected_item);
}

// When pressing "Arrow up", select the previous item in the search-results list
function select_previous_result ()
{
    // Is the list of results hidden?
    if (search_results.style.display == "none")
    {
        show_results ();
        return;
    }
    
    // Current selected item in the list
    var selected_item = search_results.querySelector ("a.highlight");
    
    // Find next item to select
    selected_item = selected_item
                  ? selected_item.previousElementSibling
                  : search_results.lastElementChild;
    
    highlight_result (selected_item);
}

// Wait when DOM ready
window.onload = function () {
    
    // Add event listener to searchbox to find suggestions
    search_box.addEventListener ("input", search_topics);
    
    // Keyboard events
    document.addEventListener ("keydown", function (event) {
        switch (event.keyCode)
        {
            case 27:    // Esc key
                hide_results ();
                break;
        }
    });
    
    search_box.addEventListener ("keydown", function (event) {
        switch (event.keyCode)
        {
            case 37:    // Left arrow
                break;
            case 38:    // Up arrow
                select_previous_result ();
                break;
            case 39:    // Right arrow
                break;
            case 40:    // Down arrow
                select_next_result ();
                break;
        }
    });

}
