jQuery(function() {
    var livesearch = {
        getLivesearchForm : function(livesearchId) {
            var _livesearchId = livesearchId;
            var livesearchForm = null;

            jQuery("form.plugin_livesearch").each(function(index) {
                if (_livesearchId == index)
                    livesearchForm = jQuery(this);
            });

            return livesearchForm;
        },

        getLivesearchFieldset : function(livesearchId) {
            var livesearchForm = this.getLivesearchForm(livesearchId);

            return livesearchForm.children("fieldset");
        },

        getLivesearchParams : function(livesearchId) {
            var params = {};
            var fieldset = this.getLivesearchFieldset(livesearchId);

            fieldset.find("input").each(function() {
                params[this.name] = this.value;
            });

            return params;
        },

        getContextPath : function() {
            return contextPath;
            /* From the global JS var */
        },

        // If errorMessage is null, the error span will be hidden. Otherwise, it will show with the message in it.
        setErrorMessage : function(livesearchForm, errorMessage) {
            var errorBlock = livesearchForm.find(".plugin_livesearch_error_block");
            var livesearchResultsShadow = livesearchForm.find(".plugin_livesearch_searchresultshadow");
            var livesearchResultsShadowElem = livesearchResultsShadow.get(0);
            var livesearchResultsShadowOffset = livesearchResultsShadow.offset();
            
            if (errorMessage) {
                errorBlock.children("span").html(errorMessage);
                errorBlock.show();
                if (!livesearchResultsShadowElem.originalTopOffset)
                    livesearchResultsShadowElem.originalTopOffset = livesearchResultsShadowOffset.top;
                livesearchResultsShadow.css({
                    top: (livesearchResultsShadowElem.originalTopOffset + errorBlock.height()) + "px" 
                });
            } else {
                errorBlock.hide();

                if (livesearchResultsShadowElem.originalTopOffset) {
                    livesearchResultsShadow.css({
                        top: livesearchResultsShadowElem.originalTopOffset + "px"
                    });
                }
            }
        },

        doSearch : function(livesearchId) {
            var _livesearchId = livesearchId;
            var livesearchForm = this.getLivesearchForm(_livesearchId);
            var livesearchString = livesearchForm.find("input.plugin_livesearch_searchbox").attr("value");
            var livesearchSpacekey = livesearchForm.find("input[name='where']").attr("value");

            if (livesearchString && livesearchString.length > 0 && livesearchString != livesearchForm.get(0).livesearchString) {
                var firstChar = livesearchString.charAt(0);

                // don't send a request if the search term contains spaces or the first character is null, empty string, or a *
                if (livesearchString.search(" ") == -1 && firstChar != "" && firstChar != " " && firstChar != "*") {
                    jQuery.ajax({
                        type: "GET",
                        url : this.getContextPath() + "/plugins/livesearch/livesearch.action",
                        data : {
                            decorator : "none",
                            queryString : livesearchString + "*",
                            where : (!livesearchSpacekey ? "" : livesearchSpacekey)
                        },
                        success : function(data) {
                            livesearchForm.find("div.plugin_livesearch_searchresultshadow").each(function() {
                                var jQueryThis = jQuery(this);

                                jQueryThis.html(data);
                                jQueryThis.find(".plugin_livesearch_close").click(function() {
                                    livesearch.closeLivesearchResult(_livesearchId);
                                    return false;
                                });
                                jQueryThis.parent().show();

                                livesearchForm.get(0).livesearchString = livesearchString;
                            });

                            livesearch.setErrorMessage(livesearchForm, null);
                        },
                        error : function(xmlHttpRequest) {
                            var i18nMessages = {};

                            livesearchForm.prev("fieldset").find("input").each(function() {
                                i18nMessages[this.name] = this.value;
                            });

                            var errorMessage = i18nMessages["i18n-unexpectederror"];

                            if (xmlHttpRequest.status == 400) {
                                /* SC_BAD_REQUEST */
                                errorMessage = i18nMessages["i18n-invalidsearchquery"];
                            }

                            livesearch.setErrorMessage(livesearchForm, errorMessage);
                        }
                    });
                }
            }

            return false;
        },

        closeLivesearchResult : function(livesearchId) {
            var livesearchForm = this.getLivesearchForm(livesearchId);
            livesearchForm.find("div.plugin_livesearch_searchresult").hide();
        },

        isSearchResultVisible : function(livesearchId) {
            var livesearchResultControls = jQuery(".plugin_livesearch_searchresult");

            if (livesearchResultControls.length > 0 && livesearchId < livesearchResultControls.length)
                return jQuery(livesearchResultControls.get(livesearchId)).is(":visible");

            return false;
        },

        initLivesearches : function() {
            jQuery("input.plugin_livesearch_searchbox").each(function(livesearchId) {
                var _livesearchId = livesearchId;

                jQuery(this).keydown(function(event) {
                    var searchResults = null;
                    var highlightedRow = null;
                    var searchResultVisible = livesearch.isSearchResultVisible(_livesearchId);
                    var livesearchForm = livesearch.getLivesearchForm(_livesearchId);

                    if (event.keyCode == 40 && searchResultVisible) {
                        /* Down arrow */
                        searchResults = livesearchForm.find(".plugin_livesearch_row");

                        if (searchResults.length > 0) {
                            highlightedRow = livesearchForm.find(".plugin_livesearch_searchhighlight");

                            if (highlightedRow.length > 0) {
                                searchResults.each(function() {
                                    var jQueryThis = jQuery(this);

                                    if (jQueryThis.hasClass("plugin_livesearch_searchhighlight")) {
                                        var nextSibling = jQueryThis.next();

                                        if (nextSibling.length > 0) {
                                            jQueryThis.removeClass("plugin_livesearch_searchhighlight");
                                            nextSibling.addClass("plugin_livesearch_searchhighlight");
                                        }

                                        return false;
                                        /* Stop iterating */
                                    }
                                });
                            } else {
                                jQuery(searchResults.get(0)).addClass("plugin_livesearch_searchhighlight");
                            }

                            if (!jQuery.browser.msie)
                                event.preventDefault();
                        }

                    } else if (event.keyCode == 38 && searchResultVisible) {
                        /* Up arrow */
                        searchResults = livesearchForm.find(".plugin_livesearch_row");

                        if (searchResults.length > 0) {
                            highlightedRow = livesearchForm.find(".plugin_livesearch_searchhighlight");

                            if (highlightedRow.length > 0) {
                                searchResults.each(function() {
                                    var jQueryThis = jQuery(this);

                                    if (jQueryThis.hasClass("plugin_livesearch_searchhighlight")) {
                                        var prevSibling = jQueryThis.prev();

                                        if (prevSibling.length > 0) {
                                            jQueryThis.removeClass("plugin_livesearch_searchhighlight");
                                            prevSibling.addClass("plugin_livesearch_searchhighlight");
                                        }

                                        return false;
                                        /* Stop iterating */
                                    }
                                });
                            }

                            if (!jQuery.browser.msie)
                                event.preventDefault();
                        }

                    } else if (event.keyCode == 27 && searchResultVisible) {
                        /* Escape */
                        if (jQuery.browser.msie)
                            event.preventDefault(); /* We don't want IE to clear the search text field */
                        livesearch.closeLivesearchResult(_livesearchId);

                    } else if (event.keyCode == 13 && searchResultVisible) {
                        /* Enter */
                        livesearchForm.find(".plugin_livesearch_searchhighlight").each(function() {
                            var jQueryThis = jQuery(this);
                            var searchResultLink = jQueryThis.find("a");

                            window.location = searchResultLink.attr("href");
                            event.stopPropagation();
                            return false; /* Stop iterating */
                        });
                    }
                });
            });

            jQuery("input.plugin_livesearch_searchbox").each(function(livesearchId) {
                var _livesearchId = livesearchId;

                jQuery(this).keypress(function() {
                    /* Need to delay because if we don't do that, we won't get the last character input by the user.
                     * Detecting charCode would be equally bad as well due to accented input and other non-ASCII chars.
                     */
                    setTimeout(function() { livesearch.doSearch(_livesearchId); }, 200);
                });
            });

            jQuery("form.plugin_livesearch").each(function() {
                jQuery(this).submit(function() {
                    var livesearchForm = jQuery(this);
                    var searchResultContainer = livesearchForm.children("div.plugin_livesearch_searchresult");
                    var doesNotHaveHighlightedSearchResult = searchResultContainer.find(".plugin_livesearch_searchhighlight").length == 0;

                    /* Only submit if the search result is _not_ visible or there is no highlighted result */
                    if (!searchResultContainer.is(":visible") || doesNotHaveHighlightedSearchResult) {
                        var queryStringInput = livesearchForm.find("input[name='queryString']");
                        var livesearchString = livesearchForm.find("input.plugin_livesearch_searchbox").val();

                        queryStringInput.val(jQuery.trim(livesearchString).length > 0 ? livesearchString + "*" : livesearchString);
                        return true;

                    } else {
                        return false;
                    }
                });
            });
        }
    };

    livesearch.initLivesearches();
});
