jscape.settings = jscape.settings || {};

/** @class */
jscape.LinkExpiresRange = Class.extend(
    /** @lends {jscape.LinkExpiresRange.prototype} */
{
    /** @constructor */
    initialize: function(a, b, c) {
        this.lowerBound = parseInt(a) || 0;
        this.upperBound = parseInt(b) || 0;
        this.step = parseInt(c) || 0;
    }
});
jscape.LinkExpiresRange.fromJSON = function(data) {
    return data ? new jscape.LinkExpiresRange(data.lowerBound, data.upperBound, data.step) : null;
};

/** @class */
jscape.EmailServiceConfiguration = Class.extend(
    /** @lends {jscape.EmailServiceConfiguration.prototype} */
{
    DEFAULTS: {connectionType: "PLAIN", port: 25, linkExpiresRange: new jscape.LinkExpiresRange(5, 90, 5), maxDownloadsDefault: 5},

    /** @constructor */
    initialize: function(a, b, c, d, e, f, g, h, i, j, k, l, m, o, p, q, r, s, t, u) {
        this.enabled = a || false;
        this.host = b || "";
        this.port = parseInt(c) || this.DEFAULTS.port;
        this.connectionType = d || this.DEFAULTS.connectionType;
        this.username = e || "";
        this.password = f || "";
        this.sender = g || "";
        this.replyTo = h || "";
        this.debugFile = i || "";
        this.encryptionKeyAlias = j || "";
        this.signingKeyAlias = k || "";
        this.enableAdHocTransfer = l || false;
        this.enablePasswordProtection = m || false;
        this.passwordProtectionType = parseInt(o) || null;
        this.linkExpiresRange = p || this.DEFAULTS.linkExpiresRange;
        this.maxDownloadsDefault = parseInt(q) || this.DEFAULTS.maxDownloadsDefault;
        this.publicContactRecipientsAllowed = r || false;
        this.topLevelDomainRecipientsAllowed = s || false;
        this.allowedTopLevelDomains = t || [];
        this.properties = u || {};
    }
});
jscape.EmailServiceConfiguration.fromJSON = function (data) {
    return data
           ? new jscape.EmailServiceConfiguration(data.enabled, data.host, data.port, data.connectionType, data.username, data.password, data.sender, data.replyTo,
                                                  data.debugFile, data.encryptionKeyAlias, data.signingKeyAlias, data.enableAdHocTransfer, data.enablePasswordProtection,
                                                  data.passwordProtectionType, jscape.LinkExpiresRange.fromJSON(data.linkExpiresRange), data.maxDownloadsDefault,
                                                  data.publicContactRecipientsAllowed, data.topLevelDomainRecipientsAllowed, data.allowedTopLevelDomains, data.properties)
           : null;
};

/** @class */
jscape.settings.EmailModule = jscape.settings.SettingsModule.extend(
    /** @lends {jscape.settings.EmailModule.prototype} */
{
    onCreate: function(managementService) {
        this._super.apply(this, arguments);

        this.controller = new jscape.settings.EmailConfigurationController();
        this.controller.onCreate(managementService);
    },

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

    onPause: function () {
        if (this.controller.hasChanged()) {
            this._confirmAndApply([this.controller]);
        }
    },

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

/** @class */
jscape.settings.EmailConfigurationController = Class.extend(
    /** @lends {jscape.settings.EmailConfigurationController.prototype} */
{
    VARIABLES: [
        "domain", "username", "URL", "date", "message", "password",
        "transferEntries", "entry.filename", "entry.filesize",
        "entry.downloadUrl", "entry.expirationDate", "entry.maxDownloads"
    ],
    DEFAULT_CONFIG: new jscape.EmailServiceConfiguration(),

    config: null,
    encryptionKeys: null,
    signingKeys: null,
    view: null,

    /** @constructor */
    initialize: function() {
        this._initValidators();
    },

    onCreate: function(managementService) {
        this.managementService = managementService;
        this.encryptionKeys = [];
        this.signingKeys = [];

        this.adHocController = new jscape.settings.AdHocTransferController();
        this.adHocController.onCreate(managementService);
        this.testController = new jscape.settings.TestEmailServerController();
        this.variableController = new jscape.FreemarkerVariableController();
    },

    onStart: function() {
        if (this.view == null) {
            this.view = new jscape.settings.EmailServiceView();
        }
        if (this.resourcesView == null) {
            this.resourcesView = new jscape.settings.EmailResourcesView();
        }
        this.view.show(this);
        this.resourcesView.show(this);

        this.adHocController.onStart({
            onApply: $.proxy(this.onApply, this),
            onDiscard: $.proxy(this.onDiscard, this)
        });
    },

    hasChanged: function () {
        return this.config != null && !Object._equals(this.config, this._createConfiguration());
    },

    onResume: function () {
        this._loadPgpKeys()
                .always($.proxy(function () {
                            this.managementService.getEmailServiceConfiguration()
                                    .done($.proxy(function (config) { this.config = config; }, this))
                                    .fail($.proxy(function () { this.config = this.DEFAULT_CONFIG; }, this))
                                    .always($.proxy(function () {
                                                this.view && this._setupView(this.config);
                                                this.adHocController.onResume(this.config);
                                            }, this));
                        }, this));
    },

    onApply: function () {
        return this.managementService.setEmailServiceConfiguration(this._createConfiguration())
                .done($.proxy(function (config) { this.config = config; }, this))
                .done($.proxy(this._fireApplySuccess, this));
    },

    onDiscard: function() {
        this._setupView(this.config);
        this.adHocController.onResume(this.config);
        return $.Deferred().resolve().promise();
    },

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

    onTestServer: function() {
        return this.testController.start(this.managementService, this._createConfiguration());
    },

    onAddVariable: function(input) {
        this.variableController.start(input, this.VARIABLES);
    },

    _loadPgpKeys: function () {
        return $.when(this.managementService.getPgpPublicKeys(),
                      this.managementService.getPgpSecretKeys())
                .done($.proxy(function (publicKeys, secretKeys) {
                          publicKeys = $.map(publicKeys, function (key) { return key.name; });
                          secretKeys = $.map(secretKeys, function (key) {return key.name; });
                          this.encryptionKeys = publicKeys.concat(secretKeys);
                          this.signingKeys = secretKeys;
                      }, this))
                .fail($.proxy(function () {
                          this.encryptionKeys = [];
                          this.signingKeys = [];
                      }, this));
    },

    _createConfiguration: function () {
        var adhoc = this.adHocController._createConfiguration();
        return new jscape.EmailServiceConfiguration(this.view.getEnabled(),
                                                    this.view.getHost(),
                                                    this.view.getPort(),
                                                    this.view.getConnectionType(),
                                                    this.view.getUsername(),
                                                    this.view.getPassword(),
                                                    this.view.getFromAddress(),
                                                    this.view.getReplyToAddress(),
                                                    this.view.getDebugFile(),
                                                    this.view.getEncryptionKey(),
                                                    this.view.getSigningKey(),
                                                    adhoc.enableAdHocTransfer,
                                                    adhoc.enablePasswordProtection,
                                                    adhoc.passwordProtectionType,
                                                    adhoc.linkExpiresRange,
                                                    adhoc.maxDownloadsDefault,
                                                    adhoc.publicContactRecipientsAllowed,
                                                    adhoc.topLevelDomainRecipientsAllowed,
                                                    adhoc.allowedTopLevelDomains,
                                                    this.resourcesView.getResources());
    },

    _setupView: function(config) {
        if (config) {
            this.view.setHost(config.host);
            this.view.setPort(config.port);
            this.view.setConnectionType(config.connectionType);
            this.view.setUsername(config.username);
            this.view.setPassword(config.password);
            this.view.setFromAddress(config.sender);
            this.view.setReplyToAddress(config.replyTo);
            this.view.setDebugFile(config.debugFile);
            this.view.setEnabled(config.enabled);
            this.view.setEncryptionKeys(this.encryptionKeys);
            this.view.setEncryptionKey(config.encryptionKeyAlias);
            this.view.setSigningKeys(this.signingKeys);
            this.view.setSigningKey(config.signingKeyAlias);

            this.resourcesView.setResources($.extend({}, config.properties));
        }
    },

    _initValidators: function() {
        var v = new jscape.Validator();
        v.nonEmptyRule("smtp_host_nonempty", window.R.string.EMAIL_SERVICE_ERROR_BAD_HOST);
    },

    _fireApplySuccess: function () {
        $(document).triggerHandler("broadcast", [window.R.string.APPLICATION_SUCCESS_APPLY]);
    }
});

/** @class */
jscape.settings.EmailServiceView = Class.extend(
    /** @lends {jscape.settings.EmailServiceView.prototype} */
{
    /** @constructor */
    initialize: function() {
        this.fieldset = $("fieldset[name=emailsettingsfields]");

        this.enabled = $("input[name=enabled]:checkbox", this.fieldset).change($.proxy(this._adjustFieldState, this));
        this.host = $("input[name=host]", this.fieldset).textbox({required: true, validType: "smtp_host_nonempty", missingMessage: window.R.string.EMAIL_SERVICE_ERROR_BAD_HOST, width: "40%"});
        this.port = $("input[name=port]", this.fieldset).numberspinner({required: true, min: 1, max: 65535, width: 120});
        this.connectionType = $("select[name=conntype]", this.fieldset).combobox({required: true, editable: false, width: 120, panelHeight: "auto"});
        this.username = $("input[name=username]", this.fieldset).textbox({width: "30%"});
        this.password = $("input[name=password]", this.fieldset).textbox({type: "password", width: "30%"});

        this.debugFile = $("input[name=debugfile]", this.fieldset).textbox({width: "40%"});
        this.browseButton = $("a[role=button][name=browsefile]", this.fieldset).linkbutton({disabled: true, onClick: $.proxy(this._onClick$BrowseButton, this)});

        this.fromAddress = $("input[name=from]", this.fieldset).textbox({required: true, validType: "email", missingMessage: window.R.string.EMAIL_SERVICE_ERROR_BAD_EMAIL, width: "30%"});
        this.replyToAddress = $("input[name=replyto]", this.fieldset).textbox({required: false, validType: "email", invalidMessage: window.R.string.EMAIL_SERVICE_ERROR_BAD_EMAIL, width: "30%"});

        this.encrypt = $("input[name=encrypt]:checkbox", this.fieldset).change($.proxy(this._adjustEncryptKeyFieldState, this));
        this.encryptionKey = $("select[name=encryptkey]", this.fieldset).combobox({
            required: true,
            editable: true,
            limitToList: true,
            disabled: true,
            panelHeight: "auto",
            width: 170,
            formatter: function(rowData) { var t = rowData[$(this).combobox("options").textField]; return t.escapeXml(); }
        });

        this.sign = $("input[name=sign]:checkbox", this.fieldset).change($.proxy(this._adjustSignKeyFieldState, this));
        this.signingKey = $("select[name=signkey]", this.fieldset).combobox({
            required: true,
            editable: true,
            limitToList: true,
            disabled: true,
            panelHeight: "auto",
            width: 170,
            formatter: function(rowData) { var t = rowData[$(this).combobox("options").textField]; return t.escapeXml(); }
        });

        this.testButton = $("a[role=button][name=test]", this.fieldset).linkbutton({onClick: $.proxy(this._onClick$TestButton, this)});
        this.applyButton = $("a[role=button][name=apply]", this.fieldset).linkbutton({onClick: $.proxy(this._onClick$ApplyButton, this)});
        this.discardButton = $("a[role=button][name=discard]", this.fieldset).linkbutton({onClick: $.proxy(this._onClick$DiscardButton, this)});
    },

    show: function(listener) {
        this.listener = listener || jscape.settings.EmailServiceView.LISTENER;
        this._adjustFieldState();
        this._adjustEncryptKeyFieldState();
        this._adjustSignKeyFieldState();
    },

    getEnabled: function() {
        return this.enabled.is(":checked");
    },

    setEnabled: function(value) {
        this.enabled.prop("checked", !!value).change();
    },

    getHost: function() {
        return this.host.textbox("getValue");
    },

    setHost: function(value) {
        this.host.textbox("setValue", value);
    },

    getPort: function() {
        return parseInt(this.port.numberspinner("getValue"));
    },

    setPort: function(value) {
        this.port.numberspinner("setValue", parseInt(value)).numberspinner("validate");
    },

    getConnectionType: function() {
        return this.getEnabled() ? this.connectionType.combobox("getValue") : null;
    },

    setConnectionType: function(value) {
        this.connectionType.combobox("select", value);
    },

    getUsername: function() {
        return this.username.textbox("getValue");
    },

    setUsername: function(value) {
        this.username.textbox("setValue", value);
    },

    getPassword: function() {
        return this.password.textbox("getValue");
    },

    setPassword: function(value) {
        this.password.textbox("setValue", value);
    },

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

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

    getFromAddress: function() {
        return this.fromAddress.textbox("getValue");
    },

    setFromAddress: function(value) {
        this.fromAddress.textbox("setValue", value);
    },

    getReplyToAddress: function() {
        return this.replyToAddress.textbox("getValue");
    },

    setReplyToAddress: function(value) {
        this.replyToAddress.textbox("setValue", value);
    },

    getEncryptionKey: function() {
        return this.encrypt.is(":checked:not(:disabled)") ? this.encryptionKey.combobox("getValue") : null;
    },

    setEncryptionKey: function(value) {
        if (value) {
            this.encrypt.prop("checked", true);
            this.encryptionKey.combobox("select", value);
        } else {
            this.encrypt.prop("checked", false);
        }
    },

    setEncryptionKeys: function(values) {
        this.encryptionKey.combobox("loadData", values);
    },

    getSigningKey: function() {
        return this.sign.is(":checked:not(:disabled)") ? this.signingKey.combobox("getValue") : null;
    },

    setSigningKey: function(value) {
        this.sign.prop("checked", !!value).change();
        if (value) {
            this.signingKey.combobox("clear").combobox("select", value);
        }
    },

    setSigningKeys: function(values) {
        this.signingKey.combobox("loadData", values);
    },

    _onClick$BrowseButton: function () {
        this.listener.onSelectDebugFile()
                .done($.proxy(function (path) {
                          this.setDebugFile(path);
                          this.debugFile.textbox("textbox").select();
                      }, this));
    },

    _onClick$TestButton: function() {
        if (this.fieldset.form("validate")) {
            this.testButton.linkbutton("disable");
            this.listener.onTestServer().always($.proxy(function() { this.testButton.linkbutton("enable"); }, this));
        }
    },

    _onClick$ApplyButton: function() {
        if (this.fieldset.form("validate")) {
            this.applyButton.linkbutton("disable");
            this.listener.onApply()
                    .always($.proxy(function() { this.applyButton.linkbutton("enable"); }, this));
        }
    },

    _onClick$DiscardButton: function() {
        this.listener.onDiscard();
    },

    _adjustEncryptKeyFieldState: function() {
        var enabled = this.encrypt.is(":checked:not(:disabled)");
        this.encryptionKey.combobox(enabled ? "enable" : "disable")
                .combobox(enabled ? "enableValidation" : "disableValidation")
                .combobox("validate");
    },

    _adjustSignKeyFieldState: function() {
        var enabled = this.sign.is(":checked:not(:disabled)");
        this.signingKey.combobox(enabled ? "enable" : "disable")
                .combobox(enabled ? "enableValidation" : "disableValidation")
                .combobox("validate");
    },

    _adjustFieldState: function() {
        var enabled = this.getEnabled();
        this.host.textbox(enabled ? "enable" : "disable").textbox(enabled ? "enableValidation" : "disableValidation");
        this.port.numberspinner(enabled ? "enable" : "disable").numberspinner(enabled ? "enableValidation" : "disableValidation");
        this.connectionType.combobox(enabled ? "enable" : "disable").combobox(enabled ? "enableValidation" : "disableValidation");
        this.username.textbox(enabled ? "enable" : "disable");
        this.password.textbox(enabled ? "enable" : "disable");
        this.debugFile.textbox(enabled ? "enable" : "disable");
        this.fromAddress.textbox(enabled ? "enable" : "disable").textbox(enabled ? "enableValidation" : "disableValidation");
        this.replyToAddress.textbox(enabled ? "enable" : "disable").textbox(enabled ? "enableValidation" : "disableValidation");
        this.browseButton.linkbutton(enabled ? "enable" : "disable");
        this.testButton.linkbutton(enabled ? "enable" : "disable");
        this.encrypt.prop("disabled", !enabled).change();
        this.sign.prop("disabled", !enabled).change();

        this.fieldset.form("validate");
    }
});
jscape.settings.EmailServiceView.LISTENER = {
    onSelectDebugFile: $.noop,
    onTestServer: $.noop,
    onApply: $.noop,
    onDiscard: $.noop
};

/** @class */
jscape.settings.AdHocTopLevelDomainDialog = Class.extend(
    /** @lends {jscape.settings.AdHocTopLevelDomainDialog.prototype} */
{
    /** @constructor */
    initialize: function() {
        this.dialog = $("#sseft-dialog-tld").clone().attr("id", "");
        this.dialog.dialog({
            width: 530, 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=adhoctldfields]", this.dialog);
        this.domain = $("input[name=domain]", this.fieldset).textbox({required: true, validType: ["non_empty", "adhoc_tld_unique"], missingMessage: window.R.string.ADHOC_TRANSFER_ERROR_BAD_DOMAIN, invalidMessage: window.R.string.ADHOC_TRANSFER_ERROR_BAD_DOMAIN, width: "60%"});
    },

    getDomain: function() {
        return this.domain.textbox("getValue");
    },

    setDomain: function(value) {
        this.domain.textbox("setValue", value || "");
        if (value && value.trim().length) {
            this.domain.textbox("textbox").validatebox("options").validType = ["non_empty", "adhoc_tld_unique['" + value + "']"];
        }
    },

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

    show: function (listener) {
        this.listener = listener;
        this.dialog.dialog("center").dialog("open");
        this.fieldset.form("validate");
        this.domain.textbox("textbox").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");
    },

    _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;
    }
});

/** @class */
jscape.settings.AdHocTransferController = Class.extend(
    /** @lends {jscape.settings.AdHocTransferController.prototype} */
{
    domains: null,
    view: null,

    /** @constructor */
    initialize: function() {
        this._initValidators();
    },

    onCreate: function(managementService) {
        this.managementService = managementService;
        this.domains = [];

        this.addController = new jscape.settings.AddAdHocTLDController();
        this.editController = new jscape.settings.EditAdHocTLDController();
    },

    onStart: function(listener) {
        this.listener = listener;

        if (this.view == null) {
            this.view = new jscape.settings.AdHocTransferView();
        }
        this.view.show(this);
    },

    onResume: function(config) {
        this.domains = config ? config.allowedTopLevelDomains : [];
        this.view && this._setupView(config);
    },

    onAddDomain: function() {
        this.addController.start().done($.proxy(this._tldAdded, this));
    },

    onEditDomain: function(domain) {
        var index = $.inArray(domain, this.domains);
        if (index != -1) {
            this.editController.start(domain).done($.proxy(this._tldEdited, this, index));
        }
    },

    onDeleteDomain: function(domain) {
        this.view.showConfirmDelete(domain).done($.proxy(this._tldDeleted, this, domain));
    },

    onApply: function() {
        return this.listener.onApply();
    },

    onDiscard: function() {
        return this.listener.onDiscard();
    },

    _tldAdded: function(domain) {
        this.domains.push(domain);
        this.view.setTopLevelDomains(this.domains);
        this.view.selectItem(domain);
    },

    _tldEdited: function(index, domain) {
        this.domains[index] = domain;
        this.view.setTopLevelDomains(this.domains);
        this.view.selectItem(domain);
    },

    _tldDeleted: function (domain) {
        var index = $.inArray(domain, this.domains);
        if (index != -1) {
            this.domains.splice(index, 1);
            this.view.setTopLevelDomains(this.domains);

            if (this.domains.length) {
                index = Math.max(0, Math.min(index, this.domains.length - 1));
                this.view.selectItem(this.domains[index]);
            }
        }
    },

    _createConfiguration: function () {
        return {
            enableAdHocTransfer: this.view.getEnabled(),
            enablePasswordProtection: this.view.getProtectionEnabled(),
            passwordProtectionType: this.view.getProtectionType(),
            linkExpiresRange: this.view.getLinkExpiresRange(),
            maxDownloadsDefault: this.view.getMaxDownloadsDefault(),
            publicContactRecipientsAllowed: this.view.getRecipientsPublicContactAllowed(),
            topLevelDomainRecipientsAllowed: this.view.getRecipientsTopLevelDomainAllowed(),
            allowedTopLevelDomains: this.view.getTopLevelDomains()
        }
    },

    _setupView: function(config) {
        if (config) {
            this.view.setEnabled(config.enableAdHocTransfer);
            this.view.setProtectionEnabled(config.enablePasswordProtection);
            this.view.setProtectionType(config.passwordProtectionType);
            this.view.setLinkExpiresRange(config.linkExpiresRange);
            this.view.setMaxDownloadsDefault(config.maxDownloadsDefault);
            this.view.setRecipientsPublicContactAllowed(config.publicContactRecipientsAllowed);
            this.view.setRecipientsTopLevelDomainAllowed(config.topLevelDomainRecipientsAllowed);
            this.view.setTopLevelDomains(this.domains);
        }
    },

    _initValidators: function() {
        var v = new jscape.Validator();
        v.rule("adhoc_tld_unique", $.proxy(this._tldNotExists, this), window.R.string.ADHOC_TRANSFER_ERROR_DOMAIN_EXISTS);
    },

    _tldNotExists: function(value, excludes) {
        return $.inArray(value, this.domains) == -1 || (excludes && $.inArray(value, excludes) != -1);
    }
});

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

    start: function() {
        this.deferred = $.Deferred();
        this._setupDialog().show(this);
        return this.deferred.promise();
    },

    onSubmit: function(dialog) {
        var domain = dialog.getDomain();
        dialog.destroy();
        this.deferred.resolve(domain);
    },

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

    _setupDialog: function () {
        var dialog = new jscape.settings.AdHocTopLevelDomainDialog();
        dialog.setTitle(window.R.string.ADHOC_TRANSFER_ADD_TITLE);
        dialog.setDomain(null);
        return dialog;
    }
});

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

    start: function(domain) {
        this.deferred = $.Deferred();
        this._setupDialog(domain).show(this);
        return this.deferred.promise();
    },

    onSubmit: function(dialog) {
        var domain = dialog.getDomain();
        dialog.destroy();
        this.deferred.resolve(domain);
    },

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

    _setupDialog: function(domain) {
        var dialog = new jscape.settings.AdHocTopLevelDomainDialog();
        dialog.setTitle(window.R.string.ADHOC_TRANSFER_EDIT_TITLE);
        dialog.setDomain(domain);
        return dialog;
    }
});

/** @class */
jscape.settings.AdHocTransferView = Class.extend(
    /** @lends {jscape.settings.AdHocTransferView.prototype} */
{
    DEFAULT_LINK_EXPIRES_RANGE: new jscape.LinkExpiresRange(5, 90, 5),
    DEFAULT_MAX_DOWNLOADS: 5,

    /** @constructor */
    initialize: function() {
        this.fieldset = $("fieldset[name=adhocservicefields]");

        this.enable = $("input[name=enable]:checkbox", this.fieldset).change($.proxy(this._adjustFieldState, this));

        this.linkExpiresBegin = $("input[name=exprangebegin]", this.fieldset).numberspinner({min: 1, max: 90, width: 50, onChange: $.proxy(this._adjustLinkExpiresRange, this)});
        this.linkExpiresEnd = $("input[name=exprangeend]", this.fieldset).numberspinner({min: 1, max: 90, width: 50, onChange: $.proxy(this._adjustLinkExpiresRange, this)});
        this.linkExpiresStep = $("input[name=exprangestep]", this.fieldset).numberspinner({min: 1, max: 90, width: 50, onChange: $.proxy(this._adjustLinkExpiresRange, this)});
        this.maxDownloads = $("input[name=maxdownloads]", this.fieldset).numberspinner({disabled: true, min: 1, max: 10000, width: 70});

        this.protectEnabled = $("input[name=pwdprotectenabled]:checkbox", this.fieldset);
        this.protectEnabled.change($.proxy(function() {
            var enabled = this.protectEnabled.is(":checked") && !this.protectEnabled.is(":disabled");
            this.protectType.combobox(enabled ? "enable" : "disable");
        }, this));
        this.protectType = $("select[name=pwdprotect]", this.fieldset).combobox({editable: false, width: "20%", panelHeight: "auto"});

        this.recipientsPublicContactAllowed = $("input[name=recipientpubcontactallowed]:checkbox", this.fieldset);
        this.recipientsTopLevelDomainAllowed = $("input[name=recipienttldallowed]:checkbox", this.fieldset);
        this.tld = $("table[role=grid][aria-label=topleveldomains]", this.fieldset);
        this.tld.datagrid({
            fit: true,
            fitColumns: true,
            singleSelect: true,
            remoteSort: false,
            onSelect: $.proxy(this._adjustButtonsState, this),
            onSortColumn: $.proxy(this._adjustButtonsState, this),
            onDblClickRow: $.proxy(this._onClick$EditButton, this),
            columns: [[
                {field: "name", title: $("thead th:nth-child(1)", this.tld).text(), resizable: true, sortable: true, width: 100, formatter: function(_, row) { return String(row || "").escapeXml(); }}
            ]]
        });

        this.addButton = $("a[role=button][name=addtld]", this.fieldset).linkbutton({onClick: $.proxy(this._onClick$AddButton, this)});
        this.editButton = $("a[role=button][name=edittld]", this.fieldset).linkbutton({disabled: true, onClick: $.proxy(this._onClick$EditButton, this)});
        this.deleteButton = $("a[role=button][name=deletetld]", this.fieldset).linkbutton({disabled: true, onClick: $.proxy(this._onClick$DeleteButton, this)});
        this.applyButton = $("a[role=button][name=apply]", this.fieldset).linkbutton({onClick: $.proxy(this._onClick$ApplyButton, this)});
        this.discardButton = $("a[role=button][name=discard]", this.fieldset).linkbutton({onClick: $.proxy(this._onClick$DiscardButton, this)});
    },

    show: function(listener) {
        this.listener = listener || jscape.settings.AdHocTransferView.LISTENER;
        this.tld.datagrid("resize");
        this._adjustLinkExpiresRange();
        this._adjustFieldState();
        this._adjustButtonsState();
    },

    showConfirmDelete: function(domain) {
        return jscape.ConfirmDialog.confirm(window.R.string.ADHOC_TRANSFER_DELETE_TITLE,
                                            window.R.string.ADHOC_TRANSFER_DELETE_MESSAGE.supplant({0: domain}));
    },

    getEnabled: function() {
        return this.enable.is(":checked");
    },

    setEnabled: function(value) {
        this.enable.prop("checked", !!value).change();
    },

    getLinkExpiresRange: function() {
        return new jscape.LinkExpiresRange(parseInt(this.linkExpiresBegin.numberspinner("getValue")),
                                           parseInt(this.linkExpiresEnd.numberspinner("getValue")),
                                           parseInt(this.linkExpiresStep.numberspinner("getValue")));
    },

    setLinkExpiresRange: function(value) {
        value = value || this.DEFAULT_LINK_EXPIRES_RANGE;
        this.linkExpiresEnd.numberspinner("setValue", value.upperBound);
        this.linkExpiresBegin.numberspinner("setValue", value.lowerBound);
        this.linkExpiresStep.numberspinner("setValue", value.step);
    },

    getMaxDownloadsDefault: function() {
        return parseInt(this.maxDownloads.numberspinner("getValue"));
    },

    setMaxDownloadsDefault: function(value) {
        this.maxDownloads.numberspinner("setValue", value || this.DEFAULT_MAX_DOWNLOADS);
    },

    getProtectionEnabled: function() {
        return this.protectEnabled.is(":checked");
    },

    setProtectionEnabled: function(value) {
        this.protectEnabled.prop("checked", !!value).change();
    },

    getProtectionType: function() {
        return parseInt(this.protectType.combobox("getValue"), 10);
    },

    setProtectionType: function(value) {
        value = value ? value.toString() : "";
        this.protectType.combobox("clear").combobox("setValue", value).combobox("select", value);
    },

    getRecipientsPublicContactAllowed: function() {
        return this.recipientsPublicContactAllowed.is(":checked");
    },

    setRecipientsPublicContactAllowed: function(value) {
        this.recipientsPublicContactAllowed.prop("checked", !!value);
    },

    getRecipientsTopLevelDomainAllowed: function() {
        return this.recipientsTopLevelDomainAllowed.is(":checked");
    },

    setRecipientsTopLevelDomainAllowed: function(value) {
        this.recipientsTopLevelDomainAllowed.prop("checked", !!value);
    },

    getTopLevelDomains: function() {
        return this.tld.datagrid("getRows");
    },

    setTopLevelDomains: function(values) {
        this.tld.datagrid("loading").datagrid("loadData", values).datagrid("loaded");
    },

    selectItem: function (value) {
        this.tld.datagrid("selectRow", this.tld.datagrid("getRowIndex", value));
    },

    _onClick$AddButton: function() {
        this.listener.onAddDomain();
    },

    _onClick$EditButton: function() {
        this.listener.onEditDomain(this.tld.datagrid("getSelected"));
    },

    _onClick$DeleteButton: function() {
        this.listener.onDeleteDomain(this.tld.datagrid("getSelected"));
    },

    _onClick$ApplyButton: function() {
        if (this.fieldset.form("validate")) {
            this.applyButton.linkbutton("disable");
            this.listener.onApply()
                    .always($.proxy(function() { this.applyButton.linkbutton("enable"); }, this));
        }
    },

    _onClick$DiscardButton: function() {
        this.listener.onDiscard();
    },

    _adjustFieldState: function() {
        var enabled = this.getEnabled();
        this.linkExpiresBegin.numberspinner(enabled ? "enable" : "disable");
        this.linkExpiresEnd.numberspinner(enabled ? "enable" : "disable");
        this.linkExpiresStep.numberspinner(enabled ? "enable" : "disable");
        this.maxDownloads.numberspinner(enabled ? "enable" : "disable");
        this.protectEnabled.prop("disabled", !enabled).change();
    },

    _adjustLinkExpiresRange: function() {
        var range = this.getLinkExpiresRange();
        var begin = range.lowerBound;
        var end = range.upperBound;

        this.linkExpiresBegin.numberspinner("options").max = end;

        if (begin > end) {
            this.linkExpiresBegin.numberspinner("setValue", end);
            this.linkExpiresStep.numberspinner("options").max = 1;
        } else {
            var step = range.step;
            var maxStep = end - begin;
            this.linkExpiresStep.numberspinner("options").max = maxStep;
            if (step > maxStep) {
                this.linkExpiresStep.numberspinner("setValue", maxStep);
            }
        }
    },

    _adjustButtonsState: function() {
        var enabled = this.tld.datagrid("getSelected") != null;
        this.editButton.linkbutton(enabled ? "enable" : "disable");
        this.deleteButton.linkbutton(enabled ? "enable" : "disable");
    }
});
jscape.settings.AdHocTransferView.LISTENER = {
    onAddDomain: $.noop,
    onEditDomain: $.noop,
    onDeleteDomain: $.noop,
    onApply: $.noop,
    onDiscard: $.noop
};

/** @class */
jscape.settings.EmailResourcesView = Class.extend(
    /** @lends {jscape.settings.EmailResourcesView.prototype} */
{
    rowIndex: -1,

    /** @constructor */
    initialize: function() {
        this.fieldset = $("fieldset[name=emailresourcesfields]");

        this.data = $("table[role=grid][aria-label=resources]", this.fieldset);
        this.data.propertygrid({
            fit: true,
            fitColumns: true,
            showGroup: false,
            scrollbarSize: 0,
            sortName: "name",
            sortOrder: "asc",
            onClickRow: $.proxy(this._adjustButtonsState, this),
            onBeforeEdit: $.proxy(function(index) { this.rowIndex = index; }, this),
            onCancelEdit: $.proxy(function() { this.rowIndex = -1; }, this)
        });

        this.addVariableButton = $("a[role=button][name=addvariable]", this.fieldset).linkbutton({disabled: true, onClick: $.proxy(this._onClick$AddVariableButton, this)});
        this.applyButton = $("a[role=button][name=apply]", this.fieldset).linkbutton({onClick: $.proxy(this._onClick$ApplyButton, this)});
        this.discardButton = $("a[role=button][name=discard]", this.fieldset).linkbutton({onClick: $.proxy(this._onClick$DiscardButton, this)});
    },

    show: function(listener) {
        this.listener = listener || jscape.settings.EmailResourcesView.LISTENER;
        this.data.propertygrid("resize");
        this._adjustButtonsState();
    },

    getResources: function() {
        var resources = {};
        var rows = this.data.propertygrid("getRows");
        for (var i = 0; i < rows.length; i++) {
            var row = rows[i];
            resources[row.name] = row.value;
        }
        return resources;
    },

    setResources: function(resources) {
        var data = [];
        for (var key in resources) {
            if (resources.hasOwnProperty(key)) {
                data.push({name: key, value: resources[key], editor: "textarea"});
            }
        }
        this.data.propertygrid("loadData", data);
    },

    _onClick$AddVariableButton: function() {
        var index = this.rowIndex;

        if (index != -1) {
            this.data.propertygrid("selectRow", index).propertygrid("beginEdit", index);
            this.data.propertygrid("options").editIndex = index;
            var editor = this.data.propertygrid("getEditor", {index: index, field: "value"});
            if (editor != null) {
                var input = $(editor.target);
                this.listener.onAddVariable(input);
            }
        }
    },

    _onClick$ApplyButton: function() {
        if (this.fieldset.form("validate")) {
            this.applyButton.linkbutton("disable");
            this.listener.onApply()
                    .always($.proxy(function() { this.applyButton.linkbutton("enable"); }, this));
        }
    },

    _onClick$DiscardButton: function() {
        this.listener.onDiscard();
    },

    _adjustButtonsState: function() {
        var enabled = this.data.propertygrid("getSelected") != null;
        this.addVariableButton.linkbutton(enabled ? "enable" : "disable");
    }
});
jscape.settings.EmailResourcesView.LISTENER = {
    onAddVariable: $.noop,
    onApply: $.noop,
    onDiscard: $.noop
};

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

    start: function(managementService, descriptor) {
        this.managementService = managementService;
        this.descriptor = descriptor;
        this.deferred = $.Deferred();
        this._setupDialog().show(this);
        return this.deferred.promise();
    },

    onSubmit: function (dialog) {
        var recipient = dialog.getRecipient();
        dialog.destroy();

        this.managementService.testEmailServer(this.descriptor, recipient)
                .done($.proxy(this._testPassed, this))
                .fail($.proxy(this._testFailed, this));
    },

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

    _setupDialog: function() {
        return new jscape.settings.TestEmailServerDialog();
    },

    _testPassed: function() {
        $.messager.alert(window.R.string.EMAIL_SERVICE_TEST_SUCCESS_TITLE,
                         window.R.string.EMAIL_SERVICE_TEST_SUCCESS_MESSAGE,
                         "info");
        this.deferred.resolve();
        this.deferred = null;
    },

    _testFailed: function() {
        this.deferred.reject();
        this.deferred = null;
    }
});

/** @class */
jscape.settings.TestEmailServerDialog = Class.extend(
    /** @lends {jscape.settings.TestEmailServerDialog.prototype} */
{
    /** @constructor */
    initialize: function() {
        this.dialog = $("#sses-dialog-test").clone().attr("id", "");
        this.dialog.dialog({
            width: 530, 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=emailsettingstestfields]", this.dialog);

        this.recipient = $("input[name=recipient]", this.fieldset).textbox({required: true, validType: "email", missingMessage: window.R.string.EMAIL_SERVICE_ERROR_BAD_RECIPIENT, invalidMessage: window.R.string.EMAIL_SERVICE_ERROR_BAD_RECIPIENT, width: "70%"});
    },

    getRecipient: function() {
        return this.recipient.textbox("getValue");
    },

    show: function (listener) {
        this.listener = listener;
        this.dialog.dialog("center").dialog("open");
        this.fieldset.form("validate");
        this.recipient.textbox("textbox").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");
    },

    _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;
    }
});