jQuery(function($) {
    labels = {
        i18nMessages : {},

        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);
                    $(response.results).each(function()
                    {
                        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;

            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");
                var errorMessageSpan = errorMessageContainer.children("span");

                errorMessageSpan.html("<img src='" + this.getContextPath() + "/images/icons/serious_warning_16.gif' /> ");
                errorMessageSpan.append(errorMessage);
                errorMessageSpan.show();
                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("span.delLabelImage").remove();
            });

            editPanel.find("span.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() {
                    labels.setErrorMessage(editPanel, labels.i18nMessages["i18n-notpermittedtoeditlabels"]);
                }
            });
        },

        initDeleteLabelIcons : function(issueId, customFieldKey, editPanel) {
            editPanel.find("span.delLabelImage a").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() {
                    labels.setErrorMessage(editPanel, labels.i18nMessages["i18n-notpermittedtoeditlabels"]);
                }
            });
        },

        initAddSuggestedLabelLinks : function(issueId, customFieldKey, editPanel) {
            editPanel.find("span.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) {
            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");
            return suggestions.length > 0 && !suggestions.is(":hidden");
        },

        closeLabelsAutocompleteSuggestions : function(editPanel) {
            editPanel.find("div.ajax_autocomplete .suggestions ul").remove();
        },

        initLabelInput : function(issueId, customFieldKey, editPanel) {
            this.getLabelInputTextField(editPanel).keydown(function(e) {
                var labelInput = $(this);
                var labelsSuggestionsVisible = labels.isSuggestionsVisible(editPanel);

                if (e.keyCode == 13 && !labelsSuggestionsVisible) {
                    var labelsString = $.trim(labelInput.attr("value"));
                    if (labelsString != "" && labels.validateLabelsString(labelsString, editPanel)) {
                        labels.addLabel(issueId, customFieldKey, labelsString, editPanel, function() {
                            labelInput.attr("value", "");
                        });
                    }
                } else if (e.keyCode == 27) {
                    if (!labelsSuggestionsVisible) {
                        editPanel.dialog("destroy");
                        editPanel.remove();
                    } else {
                        labels.closeLabelsAutocompleteSuggestions(editPanel);
                    }
                } else {
                    setTimeout(function() {
                        var labelsString = labelInput.attr("value");
                        labels.validateLabelsString(labelsString, editPanel);
                    }, 300);
                }
            });
        },

        initAddLabelButton : function(issueId, customFieldKey, editPanel) {
            editPanel.find("input.plugin_label_add_button").click(function() {
                var labelsString = $.trim(labels.getLabelInputTextField(editPanel).attr("value"));
                if (labelsString != "" && labels.validateLabelsString(labelsString, editPanel)) {
                    labels.addLabel(issueId, customFieldKey, labelsString, editPanel);
                }
            });
        },

        initDoneLabelButton : function(issueId, customFieldKey, editPanel) {
            editPanel.find("input.plugin_label_done_button").click(function() {
                var labelsString = labels.getLabelInputTextField(editPanel).attr("value");

                if ($.trim(labelsString) != '') {
                    if (labels.validateLabelsString(labelsString, editPanel)) {
                        labels.addLabel(issueId, customFieldKey, labelsString, editPanel, function() {
                            editPanel.dialog("destroy");
                            editPanel.remove();
                        });
                    }
                } else {
                    editPanel.dialog("destroy");
                    editPanel.remove();
                }
            });
        },

        isDialogDisplaying : function() {
            return $("body div.plugin_labels_panel").length > 0;
        },

        initEditPanel : function(issueId, customFieldKey, panelHtml) {
            var editPanel = $("body > div.plugin_labels_panel");
            
            if (editPanel.length == 0) {
                editPanel = $("body").append("<div class='plugin_labels_panel' style='display: none;'></div>");
                editPanel = $("body > div.plugin_labels_panel");
            }

            editPanel.html(panelHtml);

            this.initEditPanelInputAutoComplete(issueId, customFieldKey, editPanel);
            this.initDeleteLabelIcons(issueId, customFieldKey, editPanel);
            this.initAddSuggestedLabelLinks(issueId, customFieldKey, editPanel);
            this.initLabelInput(issueId, customFieldKey, editPanel);
            this.initAddLabelButton(issueId, customFieldKey, editPanel);
            this.initDoneLabelButton(issueId, customFieldKey, editPanel);

            return editPanel;
        },

        showEditPanel : function(issueId, customFieldKey, panelHtml) {
            var editPanel = this.initEditPanel(issueId, customFieldKey, panelHtml);
            editPanel.dialog({
                closeOnEscape: false,
                dialogClass: "labels-dialog",
                draggable: false,
                modal: true,
                resizable: false,
                width: 700
            });
            editPanel.find("input.plugin_label_input").focus();
        },

        initEditLink : function(editLink) {
            var fieldSet = editLink.next("fieldset");
            var params = this.getParams(fieldSet);
            var paramIssueId = params["issueId"];
            var paramCustomFieldKey = params["customFieldKey"];

            editLink.click(function() {
                if (!labels.isDialogDisplaying()) {
                    var editLinkSpan = editLink.parent();
                    var waitIcon = $("<img src='" + labels.getContextPath() + "/images/icons/wait.gif'/>").prependTo(editLinkSpan);

                    editLinkSpan.removeClass("inline-control-link");
                    editLink.hide();
                    
                    $.ajax({
                        type : "GET",
                        url : labels.getContextPath() + "/rest/labels/1.0/label/editor/" + paramIssueId + "/" + paramCustomFieldKey + ".html",
                        data : {
                            issueId : paramIssueId,
                            customFieldKey : paramCustomFieldKey
                        },
                        success : function(response) {
                            waitIcon.remove();
                            editLink.show();
                            editLinkSpan.addClass("inline-control-link");
                            labels.showEditPanel(paramIssueId, paramCustomFieldKey, response);
                        },
                        error: function() {
                            waitIcon.remove();
                            labels.setErrorMessage(editLink.parent().parent(), labels.i18nMessages["i18n-cannotshowlabelseditor"]);
                        }
                    });
                }
                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());
                }, 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();

    $("span.inline-control-link a").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));
    });
});
