jscape.domain = jscape.domain || {};

/** @class */
jscape.As2Message = Class.extend(
    /** @lends {jscape.As2Message.prototype} */
{
    /** @constructor */
    initialize: function(a, b, c, d, e, f, g, h, i, j, k, l) {
        this.id = a || "";
        this.messageId = b || "";
        this.date = parseInt(c) || 0;
        this.type = d || jscape.As2Message.Type.REQUEST;
        this.direction = e || jscape.As2Message.Direction.UNKNOWN;
        this.sender = f || "";
        this.recipient = g || "";
        this.username = h || "";
        this.tradingPartner = i || "";
        this.filename = j || "";
        this.receiptType = k || jscape.As2Message.ReceipType.NONE;
        this.status = l || jscape.As2Message.Status.PENDING;
    }
});
jscape.As2Message.fromJSON = function(data) {
    return $.extend(new jscape.As2Message(), data);
};
jscape.As2Message.Type = {REQUEST: "REQUEST", RECEIPT: "RECEIPT"};
jscape.As2Message.Direction = {INCOMING: "INCOMING", OUTGOING: "OUTGOING", UNKNOWN: "UNKNOWN"};
jscape.As2Message.ReceipType = {SYNC: "SYNC", ASYNC: "ASYNC", NONE: "NONE"};
jscape.As2Message.Status = {
    PENDING: "PENDING", SUCCESS: "SUCCESS", TRANSFER_FAILURE: "TRANSFER_FAILURE", FAILURE: "FAILURE",
    values: function () {
        return [jscape.As2Message.Status.PENDING, jscape.As2Message.Status.SUCCESS, jscape.As2Message.Status.TRANSFER_FAILURE, jscape.As2Message.Status.FAILURE];
    }
};

/** @class */
jscape.domain.AS2Module = jscape.domain.DomainModule.extend(
    /** @lends {jscape.domain.AS2Module.prototype} */
{
    onCreate: function () {
        this._super.apply(this, arguments);

        this.controller = new jscape.domain.As2MessagesController();
        this.controller.onCreate(this.managementService, this.domainName);
    },

    onStart: function () {
        this.controller.onStart();
    },

    onResume: function () {
        this.controller.onResume();
    }
});

/** @class */
jscape.domain.As2MessagesController = Class.extend(
    /** @lends {jscape.domain.As2MessagesController.prototype} */
{
    view: null,

    onCreate: function (managementService, domainName) {
        this.managementService = managementService;
        this.domainName = domainName;

        this.sendFileController = new jscape.domain.As2SendFileController();
        this.viewController = new jscape.domain.As2ViewMessageController();
        this.deleteController = new jscape.domain.As2DeleteMessageController()
    },

    onStart: function () {
        if (this.view == null) {
            this.view = new jscape.domain.As2MessagesView();
        }
        this.view.show(this);
    },

    onResume: function() {
        this.view.refresh();
    },

    onRefresh: function(params) {
        params = jscape.Page.requestParameters(params);
        return this.managementService.listAs2Messages(this.domainName, params.startIndex, params.count, params.query)
                .then(jscape.Page.datagridFormatter());
    },

    onSendFile: function() {
        this.sendFileController.start(this.managementService, this.domainName)
                .done($.proxy(function() { window.setTimeout($.proxy(function() { this.view.refresh(); }, this), 1000); }, this));
    },

    onViewMessage: function(message) {
        this.viewController.start(this.managementService, this.domainName, message);
    },

    onResendMessage: function (message) {
        this._confirmResend(message)
                .then($.proxy(function () { return this.managementService.resendAs2Message(this.domainName, message.id); }, this))
                .done($.proxy(function () { window.setTimeout($.proxy(function() { this.view.refresh(); }, this), 1000); }, this));
    },

    onDeleteMessage: function(messages) {
        return this.deleteController.start(this.managementService, this.domainName, messages)
                .done($.proxy(function() { this.view.refresh(); }, this));
    },

    _confirmResend: function(message) {
        var deferred = $.Deferred();
        var win = $.messager.confirm(window.R.string.AS2_MESSAGES_CONFIRM_RESEND_TITLE,
                                     window.R.string.AS2_MESSAGES_CONFIRM_RESEND_MESSAGE.supplant({0: message.messageId}),
                                     function(confirmed) { if (confirmed) { deferred.resolve(); } else { deferred.reject(); }});
        win.window("resize", {width: 620}).window("center");
        return deferred.promise();
    }
});

/** @class */
jscape.domain.As2MessagesView = Class.extend(
    /** @lends {jscape.domain.As2MessagesView.prototype} */
{
    selection: null,

    /** @constructor */
    initialize: function() {
        var initializing = true;

        this.fieldset = $("fieldset[name=as2messagesfields]");

        this.data = $("table[role=grid][aria-label=as2messages]", this.fieldset);
        this.data.datagrid({
            fit: true,
            fitColumns: true,
            ctrlSelect: true,
            pagination: true,
            search: true,
            remoteSearch: true,
            remoteSort: true,
            sortName: "date",
            sortOrder: "desc",
            columns: [[
                {field: "messageId", title: $("thead th:nth-child(4)", this.data).text(), sortable: true, width: 150},
                {field: "date", title: $("thead th:nth-child(1)", this.data).text(), sortable: true, width: 120, align: "right", finder: "datebox", formatter: function(value) { return new Date(value).toLocaleString(); }},
                {field: "type", title: $("thead th:nth-child(2)", this.data).text(), sortable: true, width: 130, formatter: $.proxy(this._formatType, this), finder: this._finderFor([jscape.As2Message.Type.RECEIPT, jscape.As2Message.Type.REQUEST], $.proxy(this._formatType, this))},
                {field: "direction", title: $("thead th:nth-child(3)", this.data).text(), sortable: true, width: 130, formatter: $.proxy(this._formatDirection, this), finder: this._finderFor([jscape.As2Message.Direction.INCOMING, jscape.As2Message.Direction.OUTGOING], $.proxy(this._formatDirection, this))},
                {field: "sender", title: $("thead th:nth-child(5)", this.data).text(), sortable: true, width: 120},
                {field: "recipient", title: $("thead th:nth-child(6)", this.data).text(), sortable: true, width: 150},
                {field: "filename", title: $("thead th:nth-child(7)", this.data).text(), sortable: true, width: 180},
                {field: "receiptType", title: $("thead th:nth-child(11)", this.data).text(), sortable: true, width: 90, formatter: $.proxy(this._formatReceiptType, this), finder: this._finderFor([jscape.As2Message.ReceipType.SYNC, jscape.As2Message.ReceipType.ASYNC], $.proxy(this._formatReceiptType, this))},
                {field: "username", title: $("thead th:nth-child(9)", this.data).text(), sortable: true, width: 90},
                {field: "tradingPartner", title: $("thead th:nth-child(10)", this.data).text(), sortable: true, width: 120},
                {field: "status", title: $("thead th:nth-child(8)", this.data).text(), sortable: true, width: 100, formatter: $.proxy(this._formatStatus, this), styler: $.proxy(this._formatStatusStyle, this), finder: this._finderFor(jscape.As2Message.Status.values(), $.proxy(this._formatStatus, this))}
            ]],
            onSelect: $.proxy(this._adjustRowSelection, this),
            onUnselect: $.proxy(this._adjustRowSelection, this),
            onDblClickRow: $.proxy(this._onClick$ViewButton, this),
            loader: $.proxy(this._onLoad$Data, this),
            onBeforeLoad: function() { return !initializing; },
            onLoadSuccess: $.proxy(this._adjustRowSelection, this)
        });

        this.sendFileButton = $("a[role=button][name=sendfile]", this.fieldset).linkbutton({onClick: $.proxy(this._onClick$SendFileButton, this)});
        this.viewButton = $("a[role=button][name=view]", this.fieldset).linkbutton({disabled: true, onClick: $.proxy(this._onClick$ViewButton, this)});
        this.resendButton = $("a[role=button][name=resend]", this.fieldset).linkbutton({disabled: true, onClick: $.proxy(this._onClick$ResendButton, this)});
        this.deleteButton = $("a[role=button][name=delete]", this.fieldset).linkbutton({disabled: true, onClick: $.proxy(this._onClick$DeleteButton, this)});

        initializing = false;
    },

    show: function(listener) {
        this.listener = listener || jscape.domain.As2MessagesView.LISTENER;
        this.data.datagrid("resize");
        this._adjustRowSelection();
    },

    refresh: function() {
        this.data.datagrid("reload");
    },

    _finderFor: function(values, formatter) {
        return {type: "combobox", options: {panelHeight: "auto", data: $.map(values, function(value) { return {text: formatter(value), value: value}; })}};
    },

    _formatType: function(value) {
        return window.R.string[("AS2_MESSAGES_TYPE_" + value).toUpperCase()] || "";
    },

    _formatDirection: function(value) {
        return window.R.string[("AS2_MESSAGES_DIRECTION_" + value).toUpperCase()] || "";
    },

    _formatStatus: function(value) {
        return window.R.string[("AS2_MESSAGES_STATUS_" + value).toUpperCase()] || "";
    },

    _formatStatusStyle: function(value) {
        switch (value) {
            case jscape.As2Message.Status.PENDING:
                return "color:grey";
            case jscape.As2Message.Status.SUCCESS:
                return "color:green";
            case jscape.As2Message.Status.TRANSFER_FAILURE:
            case jscape.As2Message.Status.FAILURE:
                return "color:red";
            default:
                return "";
        }
    },

    _formatReceiptType: function(value) {
        return window.R.string[("AS2_MESSAGES_RECEIPT_TYPE_" + value).toUpperCase()] || "";
    },

    _onClick$SendFileButton: function() {
        this.listener.onSendFile();
    },

    _onClick$ViewButton: function() {
        this.listener.onViewMessage(this.selection[0]);
    },

    _onClick$ResendButton: function() {
        this.listener.onResendMessage(this.selection[0]);
    },

    _onClick$DeleteButton: function() {
        this.listener.onDeleteMessage(this.selection)
                .done($.proxy(this._messageDeleted, this));
    },

    _messageDeleted: function (items) {
        var index = -1;
        while (items.length) {
            index = this.data.datagrid("getRowIndex", items.pop());
            if (index != -1) {
                this.data.datagrid("deleteRow", index);
            }
        }
        var opts = this.data.datagrid("options");
        var remains = this.data.datagrid("getData").total - (opts.pageNumber - 1) * opts.pageSize;
        if (opts.pageNumber > 1 && remains == 0) {
            this.data.datagrid("getPager").pagination("refresh", {pageNumber: --opts.pageNumber});
            this.data.datagrid("reload");
        } else {
            this.data.datagrid("selectRow", Math.max(0, Math.min(index, remains - 1)));
        }
    },

    _onLoad$Data: function(params, successCallback, errorCallback) {
        this.listener.onRefresh(params)
                .done(successCallback)
                .fail(errorCallback);
    },

    _adjustRowSelection: function () {
        this.selection = this.data.datagrid("getSelections");
        this._adjustButtonsState();
    },

    _adjustButtonsState: function() {
        var message = this.selection.length == 1 ? this.selection[0] : null;
        var resendAllowed = message != null && jscape.As2Message.Type.REQUEST == message.type && jscape.As2Message.Direction.OUTGOING == message.direction;
        this.viewButton.linkbutton(this.selection.length == 1 ? "enable" : "disable");
        this.resendButton.linkbutton(resendAllowed ? "enable" : "disable");
        this.deleteButton.linkbutton(this.selection.length != 0 ? "enable" : "disable");
    }});
jscape.domain.As2MessagesView.LISTENER = {
    onSendFile: $.noop,
    onViewMessage: $.noop,
    onResendMessage: $.noop,
    onDeleteMessage: $.noop,
    onRefresh: $.noop
};

/** @class */
jscape.domain.As2SendFileController = Class.extend(
    /** @lends {jscape.domain.As2SendFileController.prototype} */
{
    PROTOCOLS: ["AS2"],

    deferred: null,

    start: function(managementService, domainName) {
        this.managementService = managementService;
        this.domainName = domainName;
        this.deferred = $.Deferred();
        this.managementService.getTradingPartnerNames(this.domainName, this.PROTOCOLS)
                .done($.proxy(function (partners) {
                          if (partners.length) {
                              this._setupDialog(partners).show(this);
                          } else {
                              this._showNoPartnersError();
                              this.deferred.reject();
                              this.deferred = null;
                          }
                      }, this))
                .fail($.proxy(function () {
                          this._showNoPartnersError();
                          this.deferred.reject();
                          this.deferred = null;
                      }, this));
        return this.deferred.promise();
    },

    onSelectFile: function(dialog) {
        new SelectPathController($.proxy(this.managementService.listFileSystem, this.managementService),
                                 $.proxy(this.managementService.createFileSystemDir, this.managementService))
                .selectFile()
                .done(function(entry) { dialog.setFile(entry.path); });
    },

    onSelectDebugFile: function (dialog) {
        new SelectPathController($.proxy(this.managementService.listDebugDir, this.managementService),
                                 $.proxy(this.managementService.createDebugDir, this.managementService))
                .selectFile()
                .done($.proxy(function (entry) { dialog.setDebugFile(entry.path); }, this));
    },

    onSubmit: function (dialog) {
        var partnerName = dialog.getPartner();
        var data = this._createData(dialog);
        dialog.destroy();

        this.managementService.sendTradingPartnerFile(this.domainName, partnerName, data)
                .done($.proxy(function() { this.deferred.resolve(); this.deferred = null; }, this))
                .fail($.proxy(function() { this.deferred.reject(); this.deferred = null; }, this));
    },

    onCancel: function(dialog) {
        dialog.destroy();
        this.deferred.reject();
        this.deferred = null;
    },

    _createData: function(dialog) {
        return {path: dialog.getFile(), debugfile: dialog.getDebugFile()};
    },

    _setupDialog: function (partnerNames) {
        var dialog = new jscape.domain.As2SendFileDialog();
        dialog.setPartners(partnerNames);
        return dialog;
    },

    _showNoPartnersError: function() {
        $.messager.alert(window.R.string.APPLICATION_ERROR_TITLE,
                         window.R.string.AS2_MESSAGES_ERROR_NO_PARTNERS,
                         "warning");
    }
});

/** @class */
jscape.domain.As2SendFileDialog = Class.extend(
    /** @lends {jscape.domain.As2SendFileDialog.prototype} */
{
    /** @constructor */
    initialize: function() {
        this.dialog = $("#d-as2-sendfile").clone().attr("id", new Date().getTime().toString(36));
        this.dialog.dialog({
            width: 600, height: "auto",
            modal: true, resizable: false, closable: true, closed: true,
            buttons: [
                {text: window.R.string.DIALOG_BUTTON_OK || "Ok", handler: $.proxy(this._onSubmit, this)},
                {text: window.R.string.DIALOG_BUTTON_CANCEL || "Cancel", handler: $.proxy(this._onCancel, this)}
            ],
            onClose: $.proxy(function () {if (!this.closing) { this._onCancel(); }}, this)
        }).show();

        this.fieldset = $("fieldset[name=as2sendfilefields]", this.dialog);

        this.partner = $("select[name=partner]", this.fieldset).combobox({required: true, editable: false, width: 170, panelHeight: "auto", panelMaxHeight: "40%"});

        this.file = $("input[name=file]", this.fieldset).textbox({required: true, tipPosition: "bottom", missingMessage: window.R.string.AS2_MESSAGES_ERROR_BAD_FILE, width: "50%"});
        this.browseFileButton = $("a[role=button][name=browsefile]", this.fieldset).linkbutton({onClick: $.proxy(this._onClick$BrowseFileButton, this)});

        this.debugFile = $("input[name=debugfile]", this.fieldset).textbox({width: "50%"});
        this.browseDebugFileButton = $("a[role=button][name=browsedebugfile]", this.fieldset).linkbutton({onClick: $.proxy(this._onClick$BrowseDebugFileButton, this)});
    },

    getPartner: function() {
        return this.partner.combobox("getValue");
    },

    setPartners: function(values) {
        this.partner.combobox("loadData", values.sort(function(a, b) { return a.toUpperCase() > b.toUpperCase(); }));
    },

    getFile: function() {
        return this.file.textbox("getValue");
    },

    setFile: function(value) {
        this.file.textbox("setValue", value);
    },

    getDebugFile: function() {
        return this.debugFile.textbox("getValue");
    },

    setDebugFile: function(value) {
        this.debugFile.textbox("setValue", value);
    },

    show: function (listener) {
        this.listener = listener || jscape.domain.As2SendFileDialog.LISTENER;
        this.dialog.dialog("center").dialog("open");
        this.fieldset.form("validate");
        this.fieldset.find("input:first").focus();
    },

    hide: function () {
        if (!this._closed()) {
            this.closing = true;
            this.dialog.dialog("close");
            this.fieldset.form("disableValidation");
            this.closing = false;
        }
    },

    destroy: function() {
        this.dialog.dialog("destroy");
    },

    _onClick$BrowseFileButton: function() {
        this.listener.onSelectFile(this);
    },

    _onClick$BrowseDebugFileButton: function() {
        this.listener.onSelectDebugFile(this);
    },

    _onSubmit: function () {
        if (this.fieldset.form("validate")) {
            this.hide();
            this.listener.onSubmit(this);
        }
    },

    _onCancel: function () {
        this.hide();
        this.listener.onCancel(this);
    },

    _closed: function () {
        return !!this.dialog.dialog("options").closed;
    }
});
jscape.domain.As2SendFileDialog.LISTENER = {
    onSelectFile: $.noop,
    onSelectDebugFile: $.noop
};

/** @class */
jscape.domain.As2ViewMessageController = Class.extend(
    /** @lends {jscape.domain.As2ViewMessageController.prototype} */
{
    recordData: null,
    recordRawData: null,
    deferred: null,

    start: function(managementService, domainName, message) {
        this.managementService = managementService;
        this.domainName = domainName;
        this.id = message.id;
        this.deferred = $.Deferred();
        this.recordData = null;
        this.recordRawData = null;

        var dialog = new jscape.domain.ViewAs2MessageDialog();
        dialog.setTitle(message.type == jscape.As2Message.Type.RECEIPT
                        ? window.R.string.AS2_MESSAGES_VIEW_DIALOG_TITLE_RECEIPT
                        : window.R.string.AS2_MESSAGES_VIEW_DIALOG_TITLE_REQUEST);
        dialog.show(this);

        this.managementService.getAs2MessageRecordView(this.domainName, message.id)
                .done($.proxy(function(data) {
                    this.recordData = data || null;
                    dialog.setRecordView(data);
                }, this))
                .fail(this.deferred.reject);

        return this.deferred.promise();
    },

    onRecordView: function(dialog) {
        dialog.setRecordView(this.recordData);
    },

    onRawView: function(dialog) {
        if (this.recordRawData == null) {
            this.managementService.getAs2MessageRecordRawView(this.domainName, this.id)
                    .done($.proxy(function(data) {
                        this.recordRawData = data || null;
                        dialog.setRecordRawView(data);
                    }, this));
        } else {
            dialog.setRecordRawView(this.recordRawData);
        }
    },

    onSubmit: function(dialog) {
        dialog.destroy();
        this.deferred.resolve();
    },

    onCancel: function(dialog) {
        dialog.destroy();
        this.deferred.resolve();
    }
});

/** @class */
jscape.domain.ViewAs2MessageDialog = Class.extend(
    /** @lends {jscape.domain.ViewAs2MessageDialog.prototype} */
{
    /** @constructor */
    initialize: function() {
        this.dialog = $("#as2-viewrecord").clone().attr("id", "");
        this.dialog.dialog({
            width: 800, height: 600,
            modal: true, resizable: true, closable: true, closed: true,
            buttons: [
                {text: window.R.string.DIALOG_BUTTON_CLOSE || "Close", handler: $.proxy(this._onCancel, this)}
            ],
            toolbar: [
                {text: window.R.string.AS2_MESSAGES_BUTTON_RAW_VIEW, toggle: true, selected: false, handler: $.proxy(this._onClick$RawViewButton, this)}
            ],
            onResize: $.proxy(function() { this.data && this.data.propertygrid("resize"); }, this),
            onClose: $.proxy(function () {if (!this.closing) { this._onCancel(); }}, this)
        }).show();

        this.fieldset = $("fieldset[name=as2viewrecordfields]", this.dialog).panel({fit: true, border: false});

        this.rawView = $("div[aria-label=messagerawview]", this.fieldset).hide();
        this.data = $("table[role=grid][aria-label=as2messagerecord]", this.fieldset).propertygrid({fit: true, height: "auto"});
    },

    setTitle: function(value) {
        this.dialog.dialog("setTitle", value || "");
    },

    setRecordView: function(record) {
        this.rawView.hide();
        this.data.propertygrid("getPanel").parent().show();
        this.data.propertygrid("loadData", $.map(record || {}, function(value, key) { return {name: key, value: value}; }));
    },

    setRecordRawView: function(value) {
        this.data.propertygrid("getPanel").parent().hide();
        this.rawView.html("<pre>" + value + "</pre>").show().css("overflow", "auto");
    },

    show: function (listener) {
        this.listener = listener || jscape.domain.ViewAs2MessageDialog.LISTENER;
        this.dialog.dialog("center").dialog("open");
    },

    hide: function () {
        if (!this._closed()) {
            this.closing = true;
            this.dialog.dialog("close");
            this.closing = false;
        }
    },

    destroy: function() {
        this.dialog.dialog("destroy");
    },

    _onClick$RawViewButton: function(e) {
        if (!$(e.currentTarget).linkbutton("options").selected) {
            this.listener.onRawView(this);
        } else {
            this.listener.onRecordView(this);
        }
    },

    _onSubmit: function () {
        this.hide();
        this.listener.onSubmit(this);
    },

    _onCancel: function () {
        this.hide();
        this.listener.onCancel(this);
    },

    _closed: function () {
        return !!this.dialog.dialog("options").closed;
    }
});
jscape.domain.ViewAs2MessageDialog.LISTENER = {
    onRecordView: $.noop,
    onRawView: $.noop
};


/** @class */
jscape.domain.As2DeleteMessageController = Class.extend(
    /** @lends {jscape.domain.As2DeleteMessageController.prototype} */
{
    deferred: null,

    start: function (managementService, domainName, messages) {
        this.managementService = managementService;
        this.domainName = domainName;
        this.deferred = $.Deferred();

        this._confirmDelete(messages)
                .done($.proxy(this._deleteConfirmed, this, messages))
                .fail($.proxy(function() { this.deferred.reject(); this.deferred = null; }, this));

        return this.deferred.promise();
    },

    _confirmDelete: function(messages) {
        return jscape.ConfirmDialog.confirm(
                window.R.string.AS2_MESSAGES_CONFIRM_DELETE_TITLE,
                window.R.string.AS2_MESSAGES_CONFIRM_DELETE_MESSAGE);
    },

    _deleteConfirmed: function(messages) {
        $.when.apply(jQuery, $.map(messages, $.proxy(function(message) { return this.managementService.deleteAs2Message(this.domainName, message.id);}, this)))
                .done($.proxy(function() { this.deferred.resolve(messages); this.deferred = null; }, this))
                .fail($.proxy(function() { this.deferred.reject(); this.deferred = null; }, this));
    }
});