jQuery(function($) {
    labels = {
        i18nMessages : {},
        editDialogs : {},

        initI18nMessages : function() {
            $("input.plugin_labels_param_i18n").each(function() {
                labels.i18nMessages[this.name] = this.value;
            });
        },

        getParams : function(fieldSet) {
            var params = {};
            fieldSet.find("input.plugin_labels_param").each(function() {
                params[this.name] = this.value;
            });

            return params;
        },

        getContextPath : function() {
            return contextPath;
        },

        getLabelInputTextField : function(editPanel) {
            return editPanel.find("input.plugin_label_input");
        },

        makeAutocomplete : function(options, issueId, customFieldKey) {
            var autoCompleteWidget = begetObject(jira.widget.autocomplete.REST);

            autoCompleteWidget.getAjaxParams = function() {
                return {
                    url: labels.getContextPath() + "/rest/labels/1.0/label/" + (issueId ? issueId : "0" ) + "/" + customFieldKey + ".json",
                    data: options.ajaxParams,
                    dataType: "json",
                    type: "GET"
                };
            };

            autoCompleteWidget.renderSuggestions = function(response) {
                var resultsContainer, suggestionNodes = [];

                this.clearResponseContainer();

                if (response && response.results && response.results.length > 0) {
                    resultsContainer = $("<ul/>").appendTo(this.responseContainer);
                    var count = 0;
                    $(response.results).each(function() {
                        //only show the first 6 suggestions
                        if(count++ < 6) {
                            var label = "" + this; // Make it a string
                            // add html element and corresponding complete value  to sugestionNodes Array
                            suggestionNodes.push([ $("<li/>").html(label).appendTo(resultsContainer), label ]);
                        }
                    });
                }
                if (suggestionNodes.length > 0)
                    autoCompleteWidget.addSuggestionControls(suggestionNodes);

                return suggestionNodes;
            };

            options.minQueryLength = 2;
            options.queryDelay = 0.25;
            options.autoSelectFirst = false;
            options.allowDuplicates = true;

            autoCompleteWidget.init(options);

            return autoCompleteWidget;
        },

        initEditPanelInputAutoComplete : function(issueId, customFieldKey, editPanel) {
            var labelInputId = this.getLabelInputTextField(editPanel).attr("id");

            // initialises autocomplete control
            this.makeAutocomplete({
                fieldID: labelInputId,
                delimChar : " ",
                ajaxParams: {}
            }, issueId, customFieldKey);
        },

        setErrorMessage : function(errorMessageContainerContainer, errorMessage) {
            if (errorMessage) {
                var errorMessageContainer = errorMessageContainerContainer.find("div.plugin_labels_error_container");
                errorMessageContainer.text(errorMessage);
                errorMessageContainer.show();
            } else {
                errorMessageContainerContainer.find("div.plugin_labels_error_container").hide();
            }
        },

        updateLabels : function(issueId, customFieldKey, html, editPanel) {
            $(document).find(".plugin_label_labels_" + issueId + "_" + customFieldKey).each(function() {
                var labelListContainer = $(this);

                labelListContainer.html(html);
                labelListContainer.find("a.delLabelImage").remove();
            });

            editPanel.find("#plugin_label_existing_labels").html(html);
            this.initDeleteLabelIcons(issueId, customFieldKey, editPanel);
        },

        removeLabel : function(issueId, customFieldKey, labelPositionInList, editPanel) {
            this.setErrorMessage(editPanel, null);

            $.ajax({
                url : labels.getContextPath() + "/rest/labels/1.0/label/" + issueId + "/" + customFieldKey  + "/"  + labelPositionInList + ".html",
                type : "DELETE",
                success : function(html) {
                    labels.updateLabels(issueId, customFieldKey, html, editPanel);
                },
                error: function(XMLHttpRequest) {
                    if(XMLHttpRequest.status === 400) {
                        labels.setErrorMessage(editPanel, XMLHttpRequest.responseText);
                    } else {
                        labels.setErrorMessage(editPanel, labels.i18nMessages["i18n-notpermittedtoeditlabels"]);
                    }
                }
            });
        },

        initDeleteLabelIcons : function(issueId, customFieldKey, editPanel) {
            editPanel.find("a.delLabelImage").each(function(index) {
                var deleteLink = $(this);
                deleteLink.click(function() {
                    labels.removeLabel(issueId, customFieldKey, index, editPanel);
                    return false;
                });
            });
        },

        addLabel : function(issueId, customFieldKey, labelsString, editPanel, callback) {
            $.ajax({
                url : labels.getContextPath() + "/rest/labels/1.0/label/" + issueId + "/" + customFieldKey  + ".html",
                type : "PUT",
                data : {
                    newlabels : labelsString
                },
                success : function(html) {
                    labels.updateLabels(issueId, customFieldKey, html, editPanel);
                    if (callback)
                        callback();
                },
                error: function(XMLHttpRequest) {
                    if(XMLHttpRequest.status === 400) {
                        labels.setErrorMessage(editPanel, XMLHttpRequest.responseText);
                    } else {
                        labels.setErrorMessage(editPanel, labels.i18nMessages["i18n-notpermittedtoeditlabels"]);
                    }
                }
            });
        },

        initAddSuggestedLabelLinks : function(issueId, customFieldKey, editPanel) {
            editPanel.find("ul.plugin_label_suggested_labels a").each(function() {
                var suggestedLabelLink = $(this);
                suggestedLabelLink.click(function() {
                    labels.addLabel(issueId, customFieldKey, suggestedLabelLink.html(), editPanel);
                    return false;
                });
            });
        },

        validateLabelsString : function(labelsString, editPanel, allowEmpty) {
            if (labelsString == "" && !allowEmpty) {
                this.setErrorMessage(editPanel, this.i18nMessages["i18n-nolabel"]);
                return false;
            } else if (labelsString.match(/[\:\;\,\.\?\&\[\]\(\)\#\^\*\@\!\<\>\\\']/)) {
                this.setErrorMessage(editPanel, this.i18nMessages["i18n-cannotcontaininvalidchars"]);
                return false;
            } else {
                this.setErrorMessage(editPanel, null);
                return true;
            }
        },

        isSuggestionsVisible: function(editPanel) {
            var suggestions = editPanel.find("div.ajax_autocomplete .suggestions .active");
            return suggestions.length > 0 && !suggestions.is(":hidden");
        },

        closeLabelsAutocompleteSuggestions : function(editPanel) {
            editPanel.find("div.ajax_autocomplete .suggestions ul").remove();
            editPanel.find("div.ajax_autocomplete .suggestions").hide();
        },

        initLabelInput : function(issueId, customFieldKey, editDialog) {
            var editPanel = this.getEditPanel(editDialog);

            var escapeHandler = function(e) {
                if (e.keyCode == 27) {
                    var suggestions = editPanel.find("div.ajax_autocomplete .suggestions");
                    if(suggestions.length === 0 || suggestions.is(":hidden")) {
                        editDialog.hide(); // If label suggestions are not visible, close the dialog
                    } else {
                        labels.closeLabelsAutocompleteSuggestions(editPanel);
                        e.stopPropagation();
                    }
                }
            };

            // AJS.Dialog listens for escape key presses. So we have to stop its propagation as appropriate.
            this.getLabelInputTextField(editPanel).keypress(function(e) { e.stopPropagation(); });

            this.getLabelInputTextField(editPanel).keydown(function(e) {
                var labelInput = $(this);
                var labelsSuggestionsVisible = labels.isSuggestionsVisible(editPanel);

                if (e.keyCode == 13 && !labelsSuggestionsVisible) {
                    labels.closeLabelsAutocompleteSuggestions(editPanel);
                    var labelsString = $.trim(labelInput.attr("value"));
                    if (labels.validateLabelsString(labelsString, editPanel)) {
                        labels.addLabel(issueId, customFieldKey, labelsString, editPanel, function() {
                            labelInput.attr("value", "").focus();
                        });
                    }
                    //stop IE from double submitting
                    e.preventDefault();
                } else if (e.keyCode == 27) {
                    escapeHandler(e);
                } else {
                    setTimeout(function() {
                        var labelsString = labelInput.attr("value");
                        if(labelsString != '') {
                            labels.validateLabelsString(labelsString, editPanel);
                        }
                    }, 300);
                }
            });

            editPanel.find("#add-label-button").click(function(e) {
                var labelInput = labels.getLabelInputTextField(editPanel);
                var labelsString = $.trim(labelInput.attr("value"));
                if (labels.validateLabelsString(labelsString, editPanel)) {
                    labels.addLabel(issueId, customFieldKey, labelsString, editPanel, function() {
                        labelInput.attr("value", "").focus();
                    });
                }
                e.preventDefault();
            });

        },

        initLabelForm : function(editPanel) {
            $("form", editPanel).submit(function() {
                return false;
            });
        },

        initEditPanel : function(issueId, customFieldKey, editDialog) {
            var editPanel = this.getEditPanel(editDialog);

            this.initEditPanelInputAutoComplete(issueId, customFieldKey, editPanel);
            this.initDeleteLabelIcons(issueId, customFieldKey, editPanel);
            this.initAddSuggestedLabelLinks(issueId, customFieldKey, editPanel);
            this.initLabelInput(issueId, customFieldKey, editDialog);
            this.initLabelForm(editPanel);
        },

        getEditPanel : function(dialog) {
            return dialog.getCurrentPanel().body;
        },

        showEditPanel : function(title, issueId, customFieldKey, panelHtml) {
            var dialogKey = issueId + "-" + customFieldKey;
            var dialogHeight = 200;
            if(labels.editDialogs[dialogKey]) {
                labels.editDialogs[dialogKey].show();
            } else {
                labels.editDialogs[dialogKey] = new AJS.Dialog(800, dialogHeight, "label-dialog");

                labels.editDialogs[dialogKey].addHeader(title + "<button class='close'>&nbsp;</button>");
                AJS.$("#label-dialog button.close").click(function(e) {
                    labels.editDialogs[dialogKey].hide();
                    e.preventDefault();
                });
                labels.editDialogs[dialogKey].addPanel("editLabelDialog", panelHtml);

                this.initEditPanel(issueId, customFieldKey, labels.editDialogs[dialogKey]);
                labels.editDialogs[dialogKey].show();
                
                //need to calculate pageHeight to handle overflow better.
                var pageHeight = dialogHeight - labels.editDialogs[dialogKey].popup.element.find("h2").height();
                labels.editDialogs[dialogKey].popup.element.find(".page-body").css("height", pageHeight + "px");
                labels.editDialogs[dialogKey].popup.element.find(".panel-body").css("height", "");

                //JRADEV-636: IE can't deal with position:relative; on the input div.  Need to remove it when scrolling.
                if(AJS.$.browser.msie && AJS.$.browser.version.substr(0,1) < 8) {
                    labels.editDialogs[dialogKey].popup.element.find(".page-body").scroll(function() {
                        var editPanel = labels.getEditPanel(labels.editDialogs[dialogKey]);
                        labels.closeLabelsAutocompleteSuggestions(editPanel);
                        AJS.$(".ajax_autocomplete").css("position", "");
                    });
                }
            }
            this.getEditPanel(labels.editDialogs[dialogKey]).find("input.plugin_label_input").val("").focus();
            this.setErrorMessage(this.getEditPanel(labels.editDialogs[dialogKey]), null);
        },

        initEditLink : function(editLink) {
            var fieldSet = editLink.next("fieldset");
            var params = this.getParams(fieldSet);
            var paramIssueId = params["issueId"];
            var paramCustomFieldKey = params["customFieldKey"];
            var dialogTitle = editLink.attr("rel") || labels.i18nMessages["i18n-addlabel"];
            //make sure the title is html encoded!
            dialogTitle = AJS.$("<div/>").text(dialogTitle).html();

            editLink.click(function() {

                AJS.$(AJS.$.ajax({
                    type : "GET",
                    url : labels.getContextPath() + "/rest/labels/1.0/label/editor/" + paramIssueId + "/" + paramCustomFieldKey + ".html",
                    data : {
                        issueId : paramIssueId,
                        customFieldKey : paramCustomFieldKey
                    },
                    success : function(response) {
                        labels.showEditPanel(dialogTitle, paramIssueId, paramCustomFieldKey, response);
                    },
                    error: function() {
                        alert(labels.i18nMessages["i18n-cannotshowlabelseditor"]);
                    }
                })).throbber({target:editLink});
                return false;
            });
        },

        initLabelCustomFieldInEditMode : function(labelCustomFieldInEditMode) {
            var fieldSet = labelCustomFieldInEditMode.next("fieldset");
            var params = this.getParams(fieldSet);
            var paramIssueId = params["issueId"];
            var paramCustomFieldKey = params["customFieldKey"];


            this.makeAutocomplete({
                fieldID: paramCustomFieldKey,
                delimChar : " ",
                ajaxParams: {}
            }, paramIssueId, paramCustomFieldKey);

            labelCustomFieldInEditMode.keydown(function()  {
                setTimeout(function() {
                    var labelsString = labelCustomFieldInEditMode.attr("value");
                    labels.validateLabelsString(labelsString,  labelCustomFieldInEditMode.parent(), true);
                }, 300);
            });

            labelCustomFieldInEditMode.parent().find("div.plugin_labels_suggested_labels a").each(function() {
                var suggestedLabelLink = $(this);

                suggestedLabelLink.click(function() {
                    var customFieldValue = labelCustomFieldInEditMode.attr("value");
                    var prependSpace = customFieldValue.length > 0 && customFieldValue.charAt(customFieldValue.length - 1) != ' ';

                    labelCustomFieldInEditMode.attr("value", customFieldValue + (prependSpace ? ' ' : '') + suggestedLabelLink.html());
                    labelCustomFieldInEditMode.focus();

                    suggestedLabelLink.hide();
                    return false;
                });
            });
        },

        initLabelCustomFieldSearch : function(labelSearchInput) {
            var fieldSet = labelSearchInput.next("fieldset");
            var params = this.getParams(fieldSet);
            var paramCustomFieldKey = params["customFieldKey"];


            this.makeAutocomplete({
                fieldID: paramCustomFieldKey,
                ajaxParams: {}
            }, null, paramCustomFieldKey);
        }
    };

    labels.initI18nMessages();

    $("a.label-link").each(function() {        
        labels.initEditLink($(this));
    });
    $("input.plugin_label_input_issue_edit").each(function() {
        labels.initLabelCustomFieldInEditMode($(this));
    });
    $("input.plugin_label_input_search").each(function() {
        labels.initLabelCustomFieldSearch($(this));
    });
});
