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

/** @class */
jscape.WebUIType = Class.extend(
    /** @lends {jscape.WebUIType.prototype} */
{
    /** @constructor */
    initialize: function(code, defaultCode, value) {
        this.code = code;
        this.defaultCode = defaultCode;
        this.value = value;
    }
});
/** @const */
jscape.WebUIType.HTML = new jscape.WebUIType(1, null, "HTML");
jscape.WebUIType.APPLET = new jscape.WebUIType(2, null, "APPLET");
jscape.WebUIType.HTML_APPLET = new jscape.WebUIType(3, 1, "HTML_APPLET");
jscape.WebUIType.APPLET_HTML = new jscape.WebUIType(3, 2, "APPLET_HTML");
jscape.WebUIType.typeFor = function(code, defaultCode) {
    if (jscape.WebUIType.HTML.code == code) {
        return jscape.WebUIType.HTML;
    } else if (jscape.WebUIType.APPLET.code == code) {
        return jscape.WebUIType.APPLET;
    } else if (jscape.WebUIType.APPLET_HTML.defaultCode == defaultCode) {
        return jscape.WebUIType.APPLET_HTML;
    } else {
        return jscape.WebUIType.HTML_APPLET;
    }
};
jscape.WebUIType.valueOf = function(value) {
    if (jscape.WebUIType.HTML.value == value) {
        return jscape.WebUIType.HTML;
    } else if (jscape.WebUIType.APPLET.value == value) {
        return jscape.WebUIType.APPLET;
    } else if (jscape.WebUIType.APPLET_HTML.value == value) {
        return jscape.WebUIType.APPLET_HTML;
    } else {
        return jscape.WebUIType.HTML_APPLET;
    }
};
/** @class */
jscape.AS2Configuration = Class.extend(
    /** @lends {jscape.AS2Configuration.prototype} */
{
    /** @constructor */
    initialize: function(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) {
        this.protocol = "AS2";
        this.enabled = a || false;
        this.decryptionKeyProvider = b || null;
        this.receiptSigningKeyProvider = c || null;
        this.receiptSignatureAlgorithm = d || null;
        this.secondaryDecryptionKeyProvider = e || null;
        this.secondaryReceiptSigningKeyProvider = f || null;
        this.secondaryReceiptSignatureAlgorithm = g || null;
        this.messageEncryptionRequired = h || false;
        this.messageSignatureRequired = i || false;
        this.messageWithoutFilenameAllowed = j || false;
        this.keepingRawMessageFileRequired = k !== undefined ? !!k : true;
        this.fileOverwritingPolicy = l || jscape.AS2Configuration.FileOverwritingPolicy.PROHIBIT;
        this.unauthenticatedTransferBinding = m || null;
        this.uploadDirectory = n || "";
        this.receiptText = o || "";
        this.fromAddress = p || "";
    }
});
jscape.AS2Configuration.FileOverwritingPolicy = {
    PROHIBIT: "PROHIBIT", OVERWRITE: "OVERWRITE", GENERATE_UNIQUE_NAME: "GENERATE_UNIQUE_NAME",
    valueOf: function(value) { for (var key in this) { if (typeof this[key] === "string" && this[key].toLowerCase() == (value + "").toLowerCase()) { return this[key]; }} return null;}
};
jscape.AS2Configuration.fromJSON = function (data) {
    function signatureAlgorithmFor(value) {
        value = jscape.SignatureAlgorithm.valueOf(value);
        return value ? value.hashAlgorithm : null;
    }
    return data
            ? new jscape.AS2Configuration(data.enabled,
                                          jscape.ServerKeyProvider.fromJSON(data.decryptionKeyProvider),
                                          jscape.ServerKeyProvider.fromJSON(data.receiptSigningKeyProvider),
                                          signatureAlgorithmFor(data.receiptSignatureAlgorithm) ,
                                          jscape.ServerKeyProvider.fromJSON(data.secondaryDecryptionKeyProvider),
                                          jscape.ServerKeyProvider.fromJSON(data.secondaryReceiptSigningKeyProvider),
                                          signatureAlgorithmFor(data.secondaryReceiptSignatureAlgorithm),
                                          data.messageEncryptionRequired,
                                          data.messageSignatureRequired,
                                          data.messageWithoutFilenameAllowed,
                                          data.keepingRawMessageFileRequired,
                                          jscape.AS2Configuration.FileOverwritingPolicy.valueOf(data.fileOverwritingPolicy),
                                          data.unauthenticatedTransferBinding,
                                          data.uploadDirectory,
                                          data.receiptText,
                                          data.fromAddress)
            : null;
};
/** @class */
jscape.AS2Configuration.TransferBinding = Class.extend(
    /** @lends {jscape.AS2Configuration.TransferBinding.prototype} */
{
    /** @constructor */
    initialize: function(a, b) {
        this.domain = a || "";
        this.username = b || "";
    }
});

/** @class */
jscape.SelfRegistrationServiceDescriptor = Class.extend(
    /** @lends {jscape.SelfRegistrationServiceDescriptor.prototype} */
{
    /** @constructor */
    initialize: function(a, b, c) {
        this.showRegistrationLink = a || false;
        this.useEmailAddressAsLogin = b || false;
        this.captchaRequired = c || false;
    }
});
jscape.SelfRegistrationServiceDescriptor.fromJSON = function(data) {
    return data ? new jscape.SelfRegistrationServiceDescriptor(data.showRegistrationLink, data.useEmailAddressAsLogin, data.captchaRequired) : null;
};

/** @class */
jscape.WebConfiguration = Class.extend(
    /** @lends {jscape.WebConfiguration.prototype} */
{
    DEFAULTS: {sessionTimeout: 30 * 60 *1000, userInterface: 3, defaultUserInterface: 1, lostPasswordEnabled: true, domainVisible: true, includeServerPort: true, sslRenegotiationAllowed: true, theme: "default"},

    /** @constructor */
    initialize: function(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x) {
        this.httpEnabled = a || false;
        this.httpAddress = b || "";
        this.httpPort = parseInt(c) || 0;
        this.httpsEnabled = d || false;
        this.httpsAddress = e|| "";
        this.httpsPort = parseInt(f) || 0;
        this.keyAlias = g || "";
        this.fipsModeRequired = !!h || false;
        this.sessionTimeout = i || this.DEFAULTS.sessionTimeout;
        this.excludedCiphers = $.isArray(j) && j.length ? j : null;
        this.lostPasswordEnabled = k != undefined ? !!k : this.DEFAULTS.lostPasswordEnabled;
        this.redirectHttp = l || false;
        this.domainVisible = m != undefined ? !!m : this.DEFAULTS.domainVisible;
        this.domainDropdown = !!n || false;
        this.defaultDomain = o || "";
        this.clientCertificateRequired = !!p || false;
        this.serverName = q || "";
        this.includeServerPort = r != undefined ? !!r : this.DEFAULTS.includeServerPort;
        this.userInterface = parseInt(s) || this.DEFAULTS.userInterface;
        this.defaultUserInterface = parseInt(t) || this.DEFAULTS.defaultUserInterface;
        this.sslRenegotiationAllowed = u != undefined ? !!u : this.DEFAULTS.sslRenegotiationAllowed;
        this.captchaRequired = !!v || false;
        this.strictTransportSecurity = w || null;
        this.theme = x || this.DEFAULTS.theme;
    }
});
jscape.WebConfiguration.fromJSON = function(data) {
    return data
           ? new jscape.WebConfiguration(data.httpEnabled,
                                         data.httpAddress,
                                         data.httpPort,
                                         data.httpsEnabled,
                                         data.httpsAddress,
                                         data.httpsPort,
                                         data.keyAlias,
                                         data.fipsModeRequired,
                                         data.sessionTimeout,
                                         data.excludedCiphers,
                                         data.lostPasswordEnabled,
                                         data.redirectHttp,
                                         data.domainVisible,
                                         data.domainDropdown,
                                         data.defaultDomain,
                                         data.clientCertificateRequired,
                                         data.serverName,
                                         data.includeServerPort,
                                         data.userInterface,
                                         data.defaultUserInterface,
                                         data.sslRenegotiationAllowed,
                                         data.captchaRequired,
                                         jscape.StrictTransportSecurityPolicy.fromJSON(data.strictTransportSecurity),
                                         data.theme)
           : null;
};
/** @class */
jscape.StrictTransportSecurityPolicy = Class.extend(
    /** @lends {jscape.StrictTransportSecurityPolicy.prototype} */
{
    /** @constructor */
    initialize: function(a, b, c) {
        this.maxAgeSeconds = parseInt(a) || 0;
        this.includeSubDomains = !!b || false;
        this.preload = !!c || false;
    }
});
jscape.StrictTransportSecurityPolicy.fromJSON = function(data) {
    return data ? new jscape.StrictTransportSecurityPolicy(data.maxAgeSeconds, data.includeSubDomains, data.preload) : null;
};

/** @class */
jscape.DocumentViewerConfiguration = Class.extend(
    /** @lends {jscape.DocumentViewerConfiguration.prototype} */
{
    /** @constructor */
    initialize: function(a, b, c, d, e) {
        this.enabled = a || false;
        this.officeDirectory = b || "";
        this.swfToolDirectory = c || "";
        this.outputDirectory = d || "";
        this.threads = parseInt(e) || 10;
    }
});
jscape.DocumentViewerConfiguration.fromJSON = function(data) {
    return data ? $.extend(new jscape.DocumentViewerConfiguration(), data) : null;
};

/** @class */
jscape.ManagementWebServerConfiguration = Class.extend(
    /** @lends {jscape.ManagementWebServerConfiguration.prototype} */
{
    DEFAULTS: {httpHost: "127.0.0.1", httpPort: 11880, httpsHost: "127.0.0.1", httpsPort: 11443, sessionTimeout: 30 * 60 * 1000, theme: "default"},

    /** @constructor */
    initialize: function(a, b, c, d, e, f, g, h, i, j, k, l, m, n) {
        this.httpHost = a || this.DEFAULTS.httpHost;
        this.httpPort = parseInt(b) || this.DEFAULTS.httpPort;
        this.httpEnabled = !!c;
        this.httpsHost = d || this.DEFAULTS.httpsHost;
        this.httpsPort = parseInt(e) || this.DEFAULTS.httpsPort;
        this.httpsEnabled = !!f;
        this.httpsKeyAlias = g || "";
        this.fipsModeRequired = !!h;
        this.excludedCiphers = $.isArray(i) && i.length ? i : null;
        this.clientCertificateRequired = !!j;
        this.sslRenegotiationAllowed = !!k;
        this.sessionTimeout = parseInt(l) || this.DEFAULTS.sessionTimeout;
        this.strictTransportSecurity = m || null;
        this.theme = n || this.DEFAULTS.theme;
    }
});
jscape.ManagementWebServerConfiguration.fromJSON = function(data) {
    return data
            ? new jscape.ManagementWebServerConfiguration(data.httpHost,
                                                          data.httpPort,
                                                          data.httpEnabled,
                                                          data.httpsHost,
                                                          data.httpsPort,
                                                          data.httpsEnabled,
                                                          data.httpsKeyAlias,
                                                          data.fipsModeRequired,
                                                          data.excludedCiphers,
                                                          data.clientCertificateRequired,
                                                          data.sslRenegotiationAllowed,
                                                          data.sessionTimeout,
                                                          jscape.StrictTransportSecurityPolicy.fromJSON(data.strictTransportSecurity),
                                                          data.theme)
            : null;
};

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

        this.webController = new jscape.settings.WebConfigurationController();
        this.restConfigController = new jscape.settings.WebRestConfigurationController();
        this.as2ConfigController = new jscape.settings.AS2ConfigurationController();
        this.signupController = new jscape.settings.SelfRegistrationController();
        this.webResourcesController = new jscape.settings.WebResourcesController();
        this.docViewerController = new jscape.settings.DocumentViewerController();

        this.webController.onCreate(managementService, serverAddresses, serverKeys);
        this.restConfigController.onCreate(managementService, serverAddresses, serverKeys);
        this.as2ConfigController.onCreate(managementService, serverKeys);
        this.signupController.onCreate(managementService);
        this.webResourcesController.onCreate(managementService);
        this.docViewerController.onCreate(managementService);
    },

    onStart: function () {
        this._super();

        this.webController.onStart(this);
        this.restConfigController.onStart();
        this.as2ConfigController.onStart();
        this.signupController.onStart();
        this.webResourcesController.onStart();
        this.docViewerController.onStart();
    },

    onPause: function () {
        this._confirmAndApply($.grep([
                                         this.webController,
                                         this.restConfigController,
                                         this.as2ConfigController,
                                         this.signupController,
                                         this.webResourcesController,
                                         this.docViewerController
                                     ],
                                     function (controller) {
                                         return controller.hasChanged();
                                     }));
    },

    onResume: function() {
        this.webController.onResume();
        this.restConfigController.onResume();
        this.as2ConfigController.onResume();
        this.signupController.onResume();
        this.webResourcesController.onResume();
        this.docViewerController.onResume();
    },

    onWebConfigChange: function() {
        this.as2ConfigController.onResume();
    }
});

/** @class */
jscape.settings.WebConfigurationController = Class.extend(
    /** @lends {jscape.settings.WebConfigurationController.prototype} */
{
    DEFAULT_CONFIG: new jscape.WebConfiguration(false, "127.0.0.1", 80, false, "127.0.0.1", 443),
    DEFAULT_HSTS_POLICY: new jscape.StrictTransportSecurityPolicy(365 * 24 * 60 * 60, false, false),

    config: null,
    excludedCiphers: null,
    strictTransportSecurity: null,
    view: null,

    onCreate: function(managementService, serverAddresses, serverKeys) {
        this.managementService = managementService;
        this.inetAddresses = serverAddresses;
        this.serverKeys = serverKeys;

        this.ciphersController = new jscape.settings.SslCiphersController();
        this.policyController = new jscape.settings.HstsPolicyController();
    },

    onStart: function(listener) {
        this.listener = listener || jscape.settings.WebConfigurationController.LISTENER;

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

    onResume: function () {
        this.managementService.getWebServiceConfiguration()
                .done($.proxy(function (config) { this.config = config; }, this))
                .fail($.proxy(function () { this.config = this.DEFAULT_CONFIG; }, this))
                .always($.proxy(function () {
                            this.excludedCiphers = this._copyCiphers(this.config);
                            this.strictTransportSecurity = this._copyHstsSettings(this.config);
                            this.view && this._setupView(this.config);
                        }, this));
    },

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

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

    onDiscard: function() {
        this.excludedCiphers = this._copyCiphers(this.config);
        this.strictTransportSecurity = this._copyHstsSettings(this.config);
        this._setupView(this.config);
    },

    onSslCiphers: function() {
        return this.ciphersController.start(this.managementService, this.excludedCiphers || [])
                .done($.proxy(function(ciphers) { this.excludedCiphers = ciphers.length ? ciphers : null; }, this));
    },

    onHstsSettings: function() {
        var policy = this.strictTransportSecurity;
        return this.policyController.start(policy)
                .done($.proxy(function(policy) { this.strictTransportSecurity = policy; }, this))
    },

    _createConfiguration: function() {
        var uiType = jscape.WebUIType.valueOf(this.view.getUserInterface());
        var hstsPolicy = this.view.isHstsEnabled() ? this.strictTransportSecurity == null ? this.DEFAULT_HSTS_POLICY : this.strictTransportSecurity : null;
        return new jscape.WebConfiguration(this.view.isHttpEnabled(),
                                           this.view.getHttpHost(),
                                           this.view.getHttpPort(),
                                           this.view.isHttpsEnabled(),
                                           this.view.getHttpsHost(),
                                           this.view.getHttpsPort(),
                                           this.view.getHttpsKey(),
                                           this.view.isFipsRequired(),
                                           this.view.getSessionTimeout(),
                                           this.excludedCiphers,
                                           this.view.isShowLostPasswordLink(),
                                           this.view.isRedirectHttp(),
                                           !this.view.isHideDomain(),
                                           this.view.isSelectDomain(),
                                           this.view.getDefaultDomain(),
                                           this.view.isClientCertificateRequired(),
                                           this.view.getServerName(),
                                           this.view.isIncludeServerPort(),
                                           uiType.code,
                                           uiType.defaultCode,
                                           this.view.isSslRenegotiationAllowed(),
                                           this.view.isCaptchaRequired(),
                                           hstsPolicy,
                                           this.view.getTheme());
    },

    _copyCiphers: function (config) {
        return config && config.excludedCiphers ? [].concat(config.excludedCiphers) : null;
    },

    _copyHstsSettings: function(config) {
        return config && config.strictTransportSecurity ? $.extend({}, config.strictTransportSecurity) : null;
    },

    _setupView: function(config) {
        var serverKeyAliases = $.map(this.serverKeys, function(key) { return key.name; });

        if (config) {
            this.view.setHttpEnabled(config.httpEnabled);
            this.view.setHttpHosts(this.inetAddresses);
            this.view.setHttpsHosts(this.inetAddresses);
            this.view.setHttpHost(config.httpAddress);
            this.view.setHttpPort(config.httpPort);
            this.view.setHttpsEnabled(config.httpsEnabled);
            this.view.setHttpsHost(config.httpsAddress);
            this.view.setHttpsPort(config.httpsPort);
            this.view.setHttpsKeys(serverKeyAliases);
            this.view.setHttpsKey(config.keyAlias);
            this.view.setFipsRequired(config.fipsModeRequired);
            this.view.setClientCertificateRequired(config.clientCertificateRequired);
            this.view.setSslRenegotiationAllowed(config.sslRenegotiationAllowed);
            this.view.setServerName(config.serverName);
            this.view.setSessionTimeout(config.sessionTimeout);
            this.view.setIncludeServerPort(config.includeServerPort);
            this.view.setRedirectHttp(config.redirectHttp);
            this.view.setUserInterface(jscape.WebUIType.typeFor(config.userInterface, config.defaultUserInterface).value);
            this.view.setDefaultDomain(config.defaultDomain);
            this.view.setHideDomain(!config.domainVisible);
            this.view.setSelectDomain(config.domainDropdown);
            this.view.setShowLostPasswordLink(config.lostPasswordEnabled);
            this.view.setCaptchaRequired(config.captchaRequired);
            this.view.setHstsEnabled(config.strictTransportSecurity != null);
            this.view.setTheme(config.theme);
        }
    },

    _fireApplySuccess: function () {
        $(document).triggerHandler("broadcast", [window.R.string.APPLICATION_SUCCESS_APPLY]);
    }
});
jscape.settings.WebConfigurationController.LISTENER = {
    onWebConfigChange: $.noop
};

/** @class */
jscape.settings.WebConfigurationView = Class.extend(
    /** @lends {jscape.settings.WebConfigurationView.prototype} */
{
    TIME_FACTOR: 60 * 1000,
    DEFAULT_SESSION_TIMEOUT: 30,

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

        this.httpEnabled = $("input[name=bindplain]:checkbox", this.fieldset).change($.proxy(this._adjustPlainAddressFields, this));
        this.httpHost = $("select[name=plainhost]", this.fieldset).combobox({required: true, width: 170, panelWidth: 255, panelHeight: "auto", missingMessage: window.R.string.WEB_SERVICE_ERROR_BAD_HOST});
        this.httpPort = $("input[name=plainport]", this.fieldset).numberspinner({required: true, disabled: true, min: 1, max: 65535, width: 80});

        this.httpsEnabled = $("input[name=bindsecure]:checkbox", this.fieldset).change($.proxy(this._adjustSecureAddressFields, this));
        this.httpsHost = $("select[name=securehost]", this.fieldset).combobox({required: true, width: 170, panelWidth: 255, panelHeight: "auto", missingMessage: window.R.string.WEB_SERVICE_ERROR_BAD_HOST});
        this.httpsPort = $("input[name=secureport]", this.fieldset).numberspinner({required: true, disabled: true, min: 1, max: 65535, width: 80});

        this.privateKey = $("select[name=privatekey]", this.fieldset).combobox({required: true, editable: false, width: "15%", panelHeight: "auto"});
        this.theme = $("select[name=theme]", this.fieldset).combobox({required: false, editable: false, width: "15%", panelHeight: "auto"});
        this.clientCertificateRequired = $("input[name=certrequired]", this.fieldset);
        this.sslRenegotiation = $("input[name=renegotiationallowed]", this.fieldset);
        this.fipsRequired = $("input[name=fipsrequired]:checkbox", this.fieldset);
        this.sslCiphersButton = $("a[role=button][name=sslciphers]", this.fieldset).linkbutton({onClick: $.proxy(this._onClick$SslCiphersButton, this)});

        this.serverName = $("input[name=servername]", this.fieldset).textbox({required: false, onChange: $.proxy(this._onChange$ServerName, this), width: "35%"});
        this.serverName.textbox("textbox").on("input", $.proxy(this._onChange$ServerName, this));
        this.sessionTtl = $("input[name=sessionttl]", this.fieldset).numberspinner({required: true, min: 1, max: 999, value: this.DEFAULT_SESSION_TIMEOUT, width: 80});
        this.redirectHttp = $("input[name=redirecthttp]:checkbox", this.fieldset);
        this.includeServerPort = $("input[name=includeserverport]:checkbox", this.fieldset);
        this.hstsEnabled = $("input[name=enablehsts]:checkbox", this.fieldset).change($.proxy(function() {
            this.hstsSettingsButton.linkbutton(this.hstsEnabled.is(":checked") ? "enable" : "disable");
        }, this));
        this.hstsSettingsButton = $("a[role=button][name=hstssettings]", this.fieldset).linkbutton({onClick: $.proxy(this._onClick$HstsButton, this)});

        this.userInterface = $("select[name=ui]", this.fieldset).combobox({required: true, editable: false, width: "25%", panelHeight: "auto"});
        this.defaultDomain = $("input[name=defaultdomain]", this.fieldset).textbox({required: false, width: "35%"});
        this.hideDomain = $("input[name=hidedomain]:checkbox", this.fieldset).change($.proxy(function() {
            var checked = this.hideDomain.is(":checked");
            this.selectDomain.prop("disabled", checked);
            this.defaultDomain.textbox("textbox").validatebox("options").required = checked;
            this.defaultDomain.textbox("isValid");
        }, this));
        this.selectDomain = $("input[name=selectdomain]:checkbox", this.fieldset);
        this.lostPasswordLink = $("input[name=showlostpwdlink]:checkbox", this.fieldset);
        this.capthaRequired = $("input[name=logincaptcha]:checkbox", this.fieldset);

        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.WebConfigurationView.LISTENER;

        this.httpEnabled.change();
        this.httpsEnabled.change();
        this.hideDomain.change();
        this.hstsEnabled.change();
        this._onChange$ServerName();
    },

    isHttpEnabled: function() {
        return this.httpEnabled.is(":checked");
    },

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

    getHttpHost: function() {
        return this.httpHost.combobox("getValue") || this.httpHost.combobox("getText");
    },

    setHttpHost: function(value) {
        this.httpHost.combobox("setValue", value);
    },

    setHttpHosts: function(values) {
        this.httpHost.combobox("loadData", values);
    },

    getHttpPort: function() {
        return parseInt(this.httpPort.numberspinner("getValue"));
    },

    setHttpPort: function(value) {
        this.httpPort.numberspinner("setValue", parseInt(value));
    },

    isHttpsEnabled: function() {
        return this.httpsEnabled.is(":checked");
    },

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

    getHttpsHost: function() {
        return this.httpsHost.combobox("getValue") || this.httpsHost.combobox("getText");
    },

    setHttpsHost: function(value) {
        this.httpsHost.combobox("setValue", value);
    },

    setHttpsHosts: function(values) {
        this.httpsHost.combobox("loadData", values);
    },

    getHttpsPort: function() {
        return parseInt(this.httpsPort.numberspinner("getValue"));
    },

    setHttpsPort: function(value) {
        this.httpsPort.numberspinner("setValue", parseInt(value));
    },

    getHttpsKey: function() {
        return this.privateKey.combobox("getValue");
    },

    setHttpsKey: function(value) {
        this.privateKey.combobox("clear").combobox("select", value);
    },

    setHttpsKeys: function(values) {
        this.privateKey.combobox("loadData", values);
    },

    isFipsRequired: function() {
        return this.fipsRequired.is(":checked");
    },

    setFipsRequired: function(value) {
        this.fipsRequired.prop("checked", !!value);
    },

    getTheme: function() {
        return this.theme.combobox("getValue");
    },

    setTheme: function(value) {
        this.theme.combobox("setValue", value);
    },

    isClientCertificateRequired: function() {
        return this.clientCertificateRequired.is(":checked");
    },

    setClientCertificateRequired: function(value) {
        this.clientCertificateRequired.prop("checked", !!value);
    },

    isSslRenegotiationAllowed: function() {
        return this.sslRenegotiation.is(":checked");
    },

    setSslRenegotiationAllowed: function(value) {
        this.sslRenegotiation.prop("checked", !!value);
    },

    getServerName: function() {
        return this.serverName.textbox("getValue").trim();
    },

    setServerName: function(value) {
        this.serverName.textbox("setValue", value);
    },

    getSessionTimeout: function() {
        return parseInt(this.sessionTtl.numberspinner("getValue")) * this.TIME_FACTOR;
    },

    setSessionTimeout: function(value) {
        this.sessionTtl.numberspinner("setValue", parseInt(value) / this.TIME_FACTOR).numberspinner("validate");
    },

    isRedirectHttp: function() {
        return this.redirectHttp.is(":checked");
    },

    setRedirectHttp: function(value) {
        this.redirectHttp.prop("checked", value);
    },

    isIncludeServerPort: function() {
        return this.includeServerPort.is(":checked");
    },

    setIncludeServerPort: function(value) {
        this.includeServerPort.prop("checked", value);
    },

    getUserInterface: function() {
        return this.userInterface.combobox("getValue");
    },

    setUserInterface: function(value) {
        this.userInterface.combobox("setValue", value);
    },

    getDefaultDomain: function() {
        return this.defaultDomain.textbox("getValue");
    },

    setDefaultDomain: function(value) {
        this.defaultDomain.textbox("setValue", value);
    },

    isHideDomain: function() {
        return this.hideDomain.is(":checked");
    },

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

    isSelectDomain: function() {
        return this.selectDomain.is(":checked");
    },

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

    isShowLostPasswordLink: function() {
        return this.lostPasswordLink.is(":checked");
    },

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

    isCaptchaRequired: function() {
        return this.capthaRequired.is(":checked");
    },

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

    isHstsEnabled: function() {
        return this.hstsEnabled.is(":checked");
    },

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

    _onClick$SslCiphersButton: function() {
        this.sslCiphersButton.linkbutton("disable");
        this.listener.onSslCiphers().always($.proxy(function() {
            this.sslCiphersButton.linkbutton("enable");
        }, this));
    },

    _onClick$HstsButton: function() {
        this.hstsSettingsButton.linkbutton("disable");
        this.listener.onHstsSettings().always($.proxy(function() {
            this.hstsSettingsButton.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();
    },

    _onChange$ServerName: function() {
        var name = this.serverName.textbox("textbox").val().trim();
        this.includeServerPort.prop("disabled", name.length == 0);
    },

    _adjustPlainAddressFields: function() {
        var enabled = this.isHttpEnabled();
        this.httpHost.combobox(enabled ? "enable" : "disable").combobox(enabled ? "enableValidation" : "disableValidation");
        this.httpPort.numberspinner(enabled ? "enable" : "disable").numberspinner(enabled ? "enableValidation" : "disableValidation");
    },

    _adjustSecureAddressFields: function() {
        var enabled = this.isHttpsEnabled();
        this.httpsHost.combobox(enabled ? "enable" : "disable").combobox(enabled ? "enableValidation" : "disableValidation");
        this.httpsPort.numberspinner(enabled ? "enable" : "disable").numberspinner(enabled ? "enableValidation" : "disableValidation");
    }
});
jscape.settings.WebConfigurationView.LISTENER = {
    onSslCiphers: $.noop,
    onHstsSettings: $.noop,
    onApply: $.noop,
    onDiscard: $.noop
};

/** @class */
jscape.settings.HstsPolicyController = Class.extend(
    /** @lends {jscape.settings.HstsPolicyController.prototype} */
{
    DEFAULT_POLICY: new jscape.StrictTransportSecurityPolicy(365 * 24 * 60 * 60, false, false),

    deferred: null,

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

    onSubmit: function(dialog) {
        var policy = this._createPolicy(dialog);
        dialog.destroy();
        this.deferred.resolve(policy);
        this.deferred = null;
    },

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

    _createPolicy: function(dialog) {
        return new jscape.StrictTransportSecurityPolicy(dialog.getMaxAgeSeconds(),
                                                        dialog.isIncludeSubDomains(),
                                                        dialog.isPreload());
    },

    _setupDialog: function (policy) {
        policy = policy ? policy : this.DEFAULT_POLICY;
        var dialog = new jscape.settings.HstsPolicyDialog();
        dialog.setMaxAgeSeconds(policy.maxAgeSeconds);
        dialog.setIncludeSubDomains(policy.includeSubDomains);
        dialog.setPreload(policy.preload);
        return dialog;
    }
});

/** @class */
jscape.settings.HstsPolicyDialog = Class.extend(
    /** @lends {jscape.settings.HstsPolicyDialog.prototype} */
{
    /** @constructor */
    initialize: function() {
        this.dialog = $("#d-ssweb-hsts").clone().attr("id", "");
        this.dialog.dialog({
            width: 550, 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=policyfields]", this.dialog);

        this.maxAgeSeconds = $("input[name=maxage]", this.fieldset).numberspinner({required: true, min: 0, max: 365 * 24 * 60 * 60, width: 120});
        this.includeSubDomains = $("input[name=includesubdomains]:checkbox", this.fieldset);
        this.preload = $("input[name=preload]:checkbox", this.fieldset);
    },

    getMaxAgeSeconds: function() {
        return parseInt(this.maxAgeSeconds.numberspinner("getValue"));
    },

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

    isIncludeSubDomains: function() {
        return this.includeSubDomains.is(":checked");
    },

    setIncludeSubDomains: function(value) {
        this.includeSubDomains.prop("checked", !!value);
    },

    isPreload: function() {
        return this.preload.is(":checked");
    },

    setPreload: function(value) {
        this.preload.prop("checked", !!value);
    },

    show: function (listener) {
        this.listener = 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");
    },

    _onSubmit: function () {
        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.WebRestConfigurationController = Class.extend(
    /** @lends {jscape.settings.WebRestConfigurationController.prototype} */
{
    DEFAULT_CONFIG: new jscape.ManagementWebServerConfiguration("127.0.0.1", 11880, false, "127.0.0.1", 11443, false),
    DEFAULT_HSTS_POLICY: new jscape.StrictTransportSecurityPolicy(365 * 24 * 60 * 60, false, false),

    config: null,
    excludedCiphers: null,
    strictTransportSecurity: null,
    view: null,

    onCreate: function(managementService, serverAddresses, serverKeys) {
        this.managementService = managementService;
        this.inetAddresses = serverAddresses;
        this.serverKeys = serverKeys;

        this.sslCiphersController = new jscape.settings.SslCiphersController();
        this.policyController = new jscape.settings.HstsPolicyController();
    },

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

    onResume: function () {
        this.managementService.getManagementWebServerConfiguration()
                .done($.proxy(function (config) { this.config = config; }, this))
                .fail($.proxy(function () { this.config = this.DEFAULT_CONFIG; }, this))
                .always($.proxy(function () {
                            this.excludedCiphers = this._copyCiphers(this.config.excludedCiphers);
                            this.strictTransportSecurity = this._copyHstsSettings(this.config);
                            this.view && this._setupView(this.config);
                        }, this));
    },

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

    onApply: function () {
        var config = this._createConfiguration();
        return this._confirmServerRestart()
                .then($.proxy(function () { return this.managementService.setManagementWebServerConfiguration(config); }, this))
                .then($.proxy(function () {
                          var deferred = $.Deferred();
                          this._waitUntilServerRestart(config, deferred, 1000);
                          return deferred;
                      }, this))
                .done($.proxy(function() { this.config = config; }, this))
                .done($.proxy(this._redirect, this, config));
    },

    onDiscard: function() {
        this.excludedCiphers = this._copyCiphers(this.config.excludedCiphers);
        this.strictTransportSecurity = this._copyHstsSettings(this.config);
        this._setupView(this.config);
    },

    onChange: function() {
        this.view.setNote(this.hasChanged() ? window.R.string.WEB_SERVICE_WARNING_RESTART_REQUIRED : "");
    },

    onSslCiphers: function() {
        return this.sslCiphersController.start(this.managementService, this.excludedCiphers || [])
                .done($.proxy(function(ciphers) { this.excludedCiphers = ciphers.length ? ciphers : null; }, this));
    },

    onHstsSettings: function () {
        var policy = this.strictTransportSecurity;
        return this.policyController.start(policy)
                .done($.proxy(function (policy) { this.strictTransportSecurity = policy; }, this))
    },

    _copyCiphers: function(ciphers) {
        return ciphers ? [].concat(ciphers) : null;
    },

    _copyHstsSettings: function (config) {
        return config && config.strictTransportSecurity ? $.extend({}, config.strictTransportSecurity) : null;
    },

    _createConfiguration: function() {
        var hstsPolicy = this.view.isHstsEnabled() ? this.strictTransportSecurity == null ? this.DEFAULT_HSTS_POLICY : this.strictTransportSecurity : null;
        return new jscape.ManagementWebServerConfiguration(this.view.getHttpHost(),
                                                           this.view.getHttpPort(),
                                                           this.view.isHttpEnabled(),
                                                           this.view.getHttpsHost(),
                                                           this.view.getHttpsPort(),
                                                           this.view.isHttpsEnabled(),
                                                           this.view.getHttpsKey(),
                                                           this.view.isFipsRequired(),
                                                           this.excludedCiphers,
                                                           this.view.isClientCertificateRequired(),
                                                           this.view.isSslRenegotiationAllowed(),
                                                           this.view.getSessionTimeout(),
                                                           hstsPolicy,
                                                           this.view.getTheme());
    },

    _setupView: function(config) {
        var serverKeyAliases = $.map(this.serverKeys, function(key) { return key.name; });

        if (config) {
            this.view.setHttpHosts(this.inetAddresses);
            this.view.setHttpHost(config.httpHost);
            this.view.setHttpPort(config.httpPort);
            this.view.setHttpEnabled(config.httpEnabled);
            this.view.setHttpsHosts(this.inetAddresses);
            this.view.setHttpsHost(config.httpsHost);
            this.view.setHttpsPort(config.httpsPort);
            this.view.setHttpsEnabled(config.httpsEnabled);
            this.view.setHttpsKeys(serverKeyAliases);
            this.view.setHttpsKey(config.httpsKeyAlias);
            this.view.setFipsRequired(config.fipsModeRequired);
            this.view.setClientCertificateRequired(config.clientCertificateRequired);
            this.view.setSslRenegotiationAllowed(config.sslRenegotiationAllowed);
            this.view.setSessionTimeout(config.sessionTimeout);
            this.view.setHstsEnabled(config.strictTransportSecurity != null);
            this.view.setTheme(config.theme);
        }
    },

    _waitUntilServerRestart: function (config, deferred, delay) {
        setTimeout($.proxy(function () {
            this.managementService.testManagementWebServerConfiguration()
                    .done($.proxy(function (newConfig) {
                        if (!Object._equals(config, newConfig)) {
                            this._waitUntilServerRestart(config, deferred, delay * 2);
                        } else {
                            deferred.resolve();
                        }
                    }, this))
                    .fail($.proxy(function (jqXhr) {
                        if (jqXhr.status == 0 && !this._bindingChanged(this.config, config)) {
                            this._waitUntilServerRestart(config, deferred, delay * 2);
                        } else {
                            deferred.resolve();
                        }
                    }, this));
        }, this), delay);
    },

    _bindingChanged: function (o1, o2) {
        return this._secureConnection(o1)
                ? o1.httpsEnabled != o2.httpsEnabled || o1.httpsHost != o2.httpsHost || o1.httpsPort != o2.httpsPort
                : o1.httpEnabled != o2.httpEnabled || o1.httpHost != o2.httpHost || o1.httpPort != o2.httpPort;
    },

    _secureConnection: function(config) {
        return /^https/i.test(window.location.protocol) && config.httpsEnabled;
    },

    _redirect: function (config) {
        var secure = this._secureConnection(config);
        var host = secure ? config.httpsHost : config.httpHost;
        if ("0.0.0.0" === host) {
            window.location = "//" + window.location.host;
        } else {
            var port = secure ? config.httpsPort : config.httpPort;
            window.location = "//" + host + ((!secure && port == 80) || (secure && port == 443) ? "" : ":" + port);
        }
    },

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

    _confirmServerRestart: function () {
        return jscape.ConfirmDialog.confirm(window.R.string.WEB_SERVICE_CONFIRM_RESTART_TITLE,
                                            window.R.string.WEB_SERVICE_CONFIRM_RESTART_MESSAGE,
                                            false);
    }
});

/** @class */
jscape.settings.WebRestConfigurationView = Class.extend(
    /** @lends {jscape.settings.WebRestConfigurationView.prototype} */
{
    TIME_FACTOR: 60 * 1000,

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

        this.httpEnabled = $("input[name=bindplain]:checkbox", this.fieldset)
                .change($.proxy(this._onChange$Form, this))
                .change($.proxy(this._adjustPlainAddressFields, this));
        this.httpHost = $("select[name=plainhost]", this.fieldset).combobox({required: true, onChange: $.proxy(this._onChange$Form, this), width: 170, panelWidth: 255, panelHeight: "auto", missingMessage: window.R.string.WEB_SERVICE_ERROR_BAD_HOST});
        this.httpPort = $("input[name=plainport]", this.fieldset).numberspinner({required: true, disabled: true, min: 1, max: 65535, onChange: $.proxy(this._onChange$Form, this), width: 80});

        this.httpsEnabled = $("input[name=bindsecure]:checkbox", this.fieldset)
                .change($.proxy(this._onChange$Form, this))
                .change($.proxy(this._adjustSecureAddressFields, this));
        this.httpsHost = $("select[name=securehost]", this.fieldset).combobox({required: true, onChange: $.proxy(this._onChange$Form, this), width: 170, panelWidth: 255, panelHeight: "auto", missingMessage: window.R.string.WEB_SERVICE_ERROR_BAD_HOST});
        this.httpsPort = $("input[name=secureport]", this.fieldset).numberspinner({required: true, disabled: true, min: 1, max: 65535, onChange: $.proxy(this._onChange$Form, this), width: 80});

        this.privateKey = $("select[name=privatekey]", this.fieldset).combobox({required: true, editable: false, onChange: $.proxy(this._onChange$Form, this), width: "15%", panelHeight: "auto"});
        this.theme = $("select[name=theme]", this.fieldset).combobox({required: false, editable: false, onChange: $.proxy(this._onChange$Form, this), panelHeight: "auto", width: "15%"});
        this.fipsRequired = $("input[name=fipsrequired]:checkbox", this.fieldset);
        this.clientCertificateRequired = $("input[name=certrequired]", this.fieldset).change($.proxy(this._onChange$Form, this));
        this.sslRenegotiation = $("input[name=renegotiationallowed]", this.fieldset).change($.proxy(this._onChange$Form, this));
        this.sslCiphersButton = $("a[role=button][name=sslciphers]", this.fieldset).linkbutton({onClick: $.proxy(this._onClick$SslCiphersButton, this)});

        this.ttl = $("input[name=ttl]", this.fieldset).numberspinner({required: true, min: 1, max: 999, onChange: $.proxy(this._onChange$Form, this), width: 80});
        this.hstsEnabled = $("input[name=enablehsts]:checkbox", this.fieldset).change($.proxy(function() {
            this.hstsSettingsButton.linkbutton(this.hstsEnabled.is(":checked") ? "enable" : "disable");
        }, this));
        this.hstsSettingsButton = $("a[role=button][name=hstssettings]", this.fieldset).linkbutton({onClick: $.proxy(this._onClick$HstsButton, this)});

        this.note = $(".warning", this.fieldset).hide();

        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.WebRestConfigurationView.LISTENER;
        this._adjustPlainAddressFields();
        this._adjustSecureAddressFields();
    },

    isHttpEnabled: function() {
        return this.httpEnabled.is(":checked");
    },

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

    getHttpHost: function() {
        return this.httpHost.combobox("getValue") || this.httpHost.combobox("getText");
    },

    setHttpHost: function(value) {
        this.httpHost.combobox("setValue", value);
    },

    setHttpHosts: function(values) {
        this.httpHost.combobox("loadData", values);
    },

    getHttpPort: function() {
        return parseInt(this.httpPort.numberspinner("getValue"));
    },

    setHttpPort: function(value) {
        this.httpPort.numberspinner("setValue", parseInt(value));
    },

    isHttpsEnabled: function() {
        return this.httpsEnabled.is(":checked");
    },

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

    getHttpsHost: function() {
        return this.httpsHost.combobox("getValue") || this.httpsHost.combobox("getText");
    },

    setHttpsHost: function(value) {
        this.httpsHost.combobox("setValue", value);
    },

    setHttpsHosts: function(values) {
        this.httpsHost.combobox("loadData", values);
    },

    getHttpsPort: function() {
        return parseInt(this.httpsPort.numberspinner("getValue"));
    },

    setHttpsPort: function(value) {
        this.httpsPort.numberspinner("setValue", parseInt(value));
    },

    getHttpsKey: function() {
        return this.privateKey.combobox("getValue");
    },

    setHttpsKey: function(value) {
        this.privateKey.combobox("clear").combobox("select", value);
    },

    setHttpsKeys: function(values) {
        this.privateKey.combobox("loadData", values);
    },

    getTheme: function () {
        return this.theme.combobox("getValue");
    },

    setTheme: function (value) {
        this.theme.combobox("setValue", value);
    },

    isFipsRequired: function() {
        return this.fipsRequired.is(":checked");
    },

    setFipsRequired: function(value) {
        this.fipsRequired.prop("checked", !!value);
    },

    isClientCertificateRequired: function() {
        return this.clientCertificateRequired.is(":checked");
    },

    setClientCertificateRequired: function(value) {
        this.clientCertificateRequired.prop("checked", !!value);
    },

    isSslRenegotiationAllowed: function() {
        return this.sslRenegotiation.is(":checked");
    },

    setSslRenegotiationAllowed: function(value) {
        this.sslRenegotiation.prop("checked", !!value);
    },

    getSessionTimeout: function() {
        return parseInt(this.ttl.numberspinner("getValue")) * this.TIME_FACTOR;
    },

    setSessionTimeout: function(value) {
        this.ttl.numberspinner("setValue", parseInt(value) / this.TIME_FACTOR).numberspinner("validate");
    },

    isHstsEnabled: function() {
        return this.hstsEnabled.is(":checked");
    },

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

    setNote: function (text) {
        if (text && text.trim().length) {
            this.note.text(text).show();
        } else {
            this.note.text("").hide();
        }
    },

    _onClick$SslCiphersButton: function() {
        this.sslCiphersButton.linkbutton("disable");
        this.listener.onSslCiphers().always($.proxy(function() {
            this.sslCiphersButton.linkbutton("enable");
        }, this));
    },

    _onClick$HstsButton: function () {
        this.hstsSettingsButton.linkbutton("disable");
        this.listener.onHstsSettings().always($.proxy(function () {
            this.hstsSettingsButton.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();
    },

    _onChange$Form: function() {
        if (this.listener) {
            this.listener.onChange();
        }
    },

    _adjustPlainAddressFields: function() {
        var enabled = this.isHttpEnabled();
        this.httpHost.combobox(enabled ? "enable" : "disable").combobox(enabled ? "enableValidation" : "disableValidation");
        this.httpPort.numberspinner(enabled ? "enable" : "disable").numberspinner(enabled ? "enableValidation" : "disableValidation");
    },

    _adjustSecureAddressFields: function() {
        var enabled = this.isHttpsEnabled();
        this.httpsHost.combobox(enabled ? "enable" : "disable").combobox(enabled ? "enableValidation" : "disableValidation");
        this.httpsPort.numberspinner(enabled ? "enable" : "disable").numberspinner(enabled ? "enableValidation" : "disableValidation");
    }
});
jscape.settings.WebRestConfigurationView.LISTENER = {
    onChange: $.noop,
    onSslCiphers: $.noop,
    onApply: $.noop,
    onDiscard: $.noop
};

/** @class */
jscape.settings.SslCiphersController = Class.extend(
    /** @lends {jscape.settings.SslCiphersController.prototype} */
{
    /** @const */
    STRONG_CIPHERS: [
        "SSL_RSA_WITH_RC4_128_MD5",
        "SSL_RSA_WITH_RC4_128_SHA",
        "SSL_RSA_WITH_3DES_EDE_CBC_SHA",
        "SSL_RSA_WITH_AES_128_CBC_SHA",
        "SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA",
        "SSL_DHE_RSA_WITH_AES_128_CBC_SHA",
        "SSL_DHE_DSS_WITH_AES_128_CBC_SHA",
        "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA",
        "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA",
        "SSL_DHE_DSS_WITH_RC4_128_SHA",
        "SSL_KRB5_WITH_RC4_128_SHA",
        "SSL_KRB5_WITH_RC4_128_MD5",
        "SSL_KRB5_WITH_3DES_EDE_CBC_SHA",
        "SSL_KRB5_WITH_3DES_EDE_CBC_MD5",
        "TLS_RSA_WITH_AES_128_CBC_SHA",
        "TLS_DHE_RSA_WITH_AES_128_CBC_SHA",
        "TLS_DHE_DSS_WITH_AES_128_CBC_SHA",
        "TLS_KRB5_WITH_RC4_128_SHA",
        "TLS_KRB5_WITH_RC4_128_MD5",
        "TLS_KRB5_WITH_3DES_EDE_CBC_SHA",
        "TLS_KRB5_WITH_3DES_EDE_CBC_MD5"
    ],
    MEDIUM_CIPHERS: [
        "SSL_DHE_RSA_WITH_DES_CBC_SHA",
        "SSL_DHE_DSS_WITH_DES_CBC_SHA",
        "SSL_RSA_WITH_DES_CBC_SHA",
        "SSL_RSA_FIPS_WITH_DES_CBC_SHA",
        "SSL_KRB5_WITH_DES_CBC_SHA",
        "SSL_KRB5_WITH_DES_CBC_MD5",
        "TLS_KRB5_WITH_DES_CBC_SHA",
        "TLS_KRB5_WITH_DES_CBC_MD5"
    ],

    deferred: null,
    ciphers: null,

    /** @constructor */
    initialize: function() {
        this.MEDIUM_CIPHERS = this.MEDIUM_CIPHERS.concat(this.STRONG_CIPHERS);
    },

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

    onSelectMedium: function(dialog) {
        dialog.setCiphers(this.MEDIUM_CIPHERS);
    },

    onSelectStrong: function(dialog) {
        dialog.setCiphers(this.STRONG_CIPHERS);
    },

    onSubmit: function(dialog) {
        var excludedCiphers = this._mergeCiphers(dialog.getCiphers(), true);
        dialog.destroy();
        this.deferred.resolve(excludedCiphers);
        this.deferred = null;
    },

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

    _setupDialog: function (excludedCiphers) {
        var dialog = new jscape.settings.SslCiphersDialog();
        if (this.ciphers == null) {
            this.managementService.getServerParameters()
                    .done($.proxy(function (params) {
                              this.ciphers = params.sslCiphers;
                              dialog.setSslCiphers(params.sslCiphers);
                              dialog.setCiphers(this._mergeCiphers(excludedCiphers, true));
                          }, this))
                    .fail($.proxy(function () { this.ciphers = null; }, this));
        } else {
            dialog.setSslCiphers(this.ciphers);
            dialog.setCiphers(this._mergeCiphers(excludedCiphers, true));
        }
        return dialog;
    },

    _mergeCiphers: function(ciphers, exclude) {
        return $.grep(this.ciphers, function (cipher) { return $.inArray(cipher, ciphers) != -1; }, exclude);
    }
});

/** @class */
jscape.settings.SslCiphersDialog = Class.extend(
    /** @lends {jscape.settings.SslCiphersDialog.prototype} */
{
    /** @constructor */
    initialize: function() {
        this.dialog = $("#d-settings-ciphers").clone().attr("id", new Date().getTime().toString(36));
        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=sslciphersfields]", this.dialog);
        this.data = $("table[role=grid][aria-label=sslciphers]", this.fieldset);
        this.data.datagrid({
            fit: true,
            fitColumns: true,
            showHeader: false,
            remoteSort: false,
            singleSelect: false,
            selectOnCheck: true,
            checkOnSelect: true,
            toolbar: "#{0} div.viewpane-toolbar".supplant({0: this.dialog.attr("id")}),
            onLoadSuccess: $.proxy(this._adjustButtonsState, this),
            idField: "value",
            columns: [[
                {field: "value", checkbox: true},
                {field: "text", sortable: true}
            ]]
        });
        this.data.filter(".datagrid-body td").css("border", "transparent");

        this.selectAllButton = $("a[role=button][name=all]", this.fieldset).linkbutton({toggle: true, onClick: $.proxy(this._onClick$SelectAllButton, this)});
        this.selectMediumButton = $("a[role=button][name=medium]", this.fieldset).linkbutton({disabled: true, onClick: $.proxy(this._onClick$SelectMediumButton, this)});
        this.selectStrongButton = $("a[role=button][name=strong]", this.fieldset).linkbutton({disabled: true, onClick: $.proxy(this._onClick$SelectStrongButton, this)});
    },

    getCiphers: function() {
        return $.map(this.data.datagrid("getChecked"), function(row) { return row.value; });
    },

    setCiphers: function (values) {
        if (values && values.length) {
            this.data.datagrid("unselectAll");
            for (var i = 0; i < values.length; i++) {
                this.data.datagrid("selectRecord", values[i]);
            }
        } else {
            this.data.datagrid("clearChecked");
        }
    },

    setSslCiphers: function(values) {
        this.data.datagrid("loadData", $.map(values, function(value) { return {text: value, value: value};}));
    },

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

    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$SelectAllButton: function() {
        var text = this.selectAllButton.text();
        this.selectAllButton.html(this.selectAllButton.html().replace(text, this.selectAllButton.data("toggle-text")));
        this.selectAllButton.data("toggle-text", text);

        if (this.selectAllButton.linkbutton("options").selected) {
            this.data.datagrid("selectAll");
        } else {
            this.data.datagrid("unselectAll");
        }
    },

    _onClick$SelectMediumButton: function() {
        this.listener.onSelectMedium(this);
    },

    _onClick$SelectStrongButton: function() {
        this.listener.onSelectStrong(this);
    },

    _adjustButtonsState: function() {
        var enabled = this.data.datagrid("getData").length != 0;
        this.selectAllButton.linkbutton(enabled ? "enable" : "disable");
        this.selectMediumButton.linkbutton(enabled ? "enable" : "disable");
        this.selectStrongButton.linkbutton(enabled ? "enable" : "disable");
    },

    _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.settings.SslCiphersDialog.LISTENER = {
    onSelectMedium: $.noop,
    onSelectStrong: $.noop,
    onSubmit: $.noop,
    onCancel: $.noop
};

/** @class */
jscape.settings.AS2ConfigurationController = Class.extend(
    /** @lends {jscape.settings.AS2ConfigurationController.prototype} */
{
    DEFAULT_CONFIG: new jscape.AS2Configuration(false, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, "/as2"),

    config: null,
    view: null,

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

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

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

    onResume: function() {
        this.managementService.getAs2ServiceConfiguration()
                .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));
    },

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

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

    onDiscard: function() {
        this._setupView(this.config);
    },

    onChangePrimaryReceiptSigningKey: function (keyAlias) {
        if (keyAlias != null) {
            var algorithms = this._receiptSignatureAlgorithmsFor(keyAlias);
            this.view.setPrimaryReceiptSignatureAlgorithms($.map(algorithms, function(entry) { return entry.hashAlgorithm; }));
        }
    },

    onChangeSecondaryReceiptSigningKey: function (keyAlias) {
        if (keyAlias != null) {
            var algorithms = this._receiptSignatureAlgorithmsFor(keyAlias);
            this.view.setSecondaryReceiptSignatureAlgorithms($.map(algorithms, function(entry) { return entry.hashAlgorithm; }));
        }
    },

    onChangeBindTransfersDomain: function(domainName) {
        this.managementService.getAccountNames(domainName)
                .done($.proxy(function(names) { this.view.setAvailableUsers(names); }, this));
    },

    _receiptSignatureAlgorithmsFor: function(keyAlias) {
        for (var i = 0; i < this.serverKeys.length; i++) {
            var key = this.serverKeys[i];
            if (keyAlias == key.name) {
                var keyAlgorithm = key.keyAlgorithm;
                return jscape.SignatureAlgorithm.filter(function(entry) { return entry.asymmetricalAlgorithm == keyAlgorithm; });
            }
        }
        return [];
    },

    _createConfiguration: function () {
        return new jscape.AS2Configuration(this.view.getEnabled(),
                                           this.view.getPrimaryDecryptionKey() != null ? new jscape.ServerKeyProvider(this.view.getPrimaryDecryptionKey()) : null,
                                           this.view.getPrimaryReceiptSigningKey() != null ? new jscape.ServerKeyProvider(this.view.getPrimaryReceiptSigningKey()) : null,
                                           this.view.getPrimaryReceiptSignatureAlgorithm(),
                                           this.view.getSecondaryDecryptionKey() != null ? new jscape.ServerKeyProvider(this.view.getSecondaryDecryptionKey()) : null,
                                           this.view.getSecondaryReceiptSigningKey() != null ? new jscape.ServerKeyProvider(this.view.getSecondaryReceiptSigningKey()) : null,
                                           this.view.getSecondaryReceiptSignatureAlgorithm(),
                                           this.view.getMessageEncryptionRequired(),
                                           this.view.getMessageSignatureRequired(),
                                           this.view.getMessageWithoutFilenameAllowed(),
                                           this.view.getKeepingRawMessageFileRequired(),
                                           this.view.getFileOverwritingPolicy(),
                                           this.view.isBindUnauthenticatedTransfers() ? new jscape.AS2Configuration.TransferBinding(this.view.getBindTransfersDomain(), this.view.getBindTransfersUser()) : null,
                                           this.view.getUploadDirectory(),
                                           this.view.getReceiptText(),
                                           this.view.getFromAddress());
    },

    _setupView: function (config) {
        var serverKeys = $.map(this.serverKeys, function(key) { return key.name; });
        var receiptAlgorithms = [];
        $.each(jscape.SignatureAlgorithm.values(), function(_, entry) {
            if ($.inArray(entry.hashAlgorithm, receiptAlgorithms) == -1) {
                receiptAlgorithms.push(entry.hashAlgorithm);
            }
        });
        this.view.setPrimaryDecryptionKeys(serverKeys);
        this.view.setPrimaryReceiptSigningKeys(serverKeys);
        this.view.setPrimaryReceiptSignatureAlgorithms(receiptAlgorithms);
        this.view.setSecondaryDecryptionKeys(serverKeys);
        this.view.setSecondaryReceiptSigningKeys(serverKeys);
        this.view.setSecondaryReceiptSignatureAlgorithms(receiptAlgorithms);

        if (config) {
            this.view.setEnabled(config.enabled);
            this.view.setPrimaryDecryptionKey(config.decryptionKeyProvider && config.decryptionKeyProvider.keyAlias);
            this.view.setPrimaryReceiptSigningKey(config.receiptSigningKeyProvider && config.receiptSigningKeyProvider.keyAlias);
            this.view.setPrimaryReceiptSignatureAlgorithm(config.receiptSignatureAlgorithm);
            this.view.setSecondaryDecryptionKey(config.secondaryDecryptionKeyProvider && config.secondaryDecryptionKeyProvider.keyAlias);
            this.view.setSecondaryReceiptSigningKey(config.secondaryReceiptSigningKeyProvider && config.secondaryReceiptSigningKeyProvider.keyAlias);
            this.view.setSecondaryReceiptSignatureAlgorithm(config.secondaryReceiptSignatureAlgorithm);
            this.view.setMessageEncryptionRequired(config.messageEncryptionRequired);
            this.view.setMessageSignatureRequired(config.messageSignatureRequired);
            this.view.setMessageWithoutFilenameAllowed(config.messageWithoutFilenameAllowed);
            this.view.setKeepingRawMessageFileRequired(config.keepingRawMessageFileRequired);
            this.view.setFileOverwritingPolicy(config.fileOverwritingPolicy == jscape.AS2Configuration.FileOverwritingPolicy.PROHIBIT ? null : config.fileOverwritingPolicy);
            this.view.setUploadDirectory(config.uploadDirectory);
            this.view.setReceiptText(config.receiptText);
            this.view.setFromAddress(config.fromAddress);
        }

        var transferBinding = config ? config.unauthenticatedTransferBinding : null;
        this.managementService.getDomainNames()
                .done($.proxy(function (names) {
                          this.view.setAvailableDomains(names);
                          if (transferBinding) {
                              this.view.setBindUnauthenticatedTransfers(true);
                              this.view.setBindTransfersDomain(transferBinding.domain);
                              this.view.setBindTransfersUser(transferBinding.username);
                          }
                      }, this));
    },

    _initValidators: function () {
        var v = new jscape.Validator();
        v.rule("astwo_uploaddir", $.proxy(this._validatorAs2UploadDir, this));
    },

    _validatorAs2UploadDir: function (value) {
        return value && value.length != 0 && value.charAt(0) == "/";
    },

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

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

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

        this.usePrimaryDecryptKey = $("input[name=useprimarydecryptkey]:checkbox", this.fieldset)
                .change($.proxy(function () { this.primaryDecryptKey.combobox(this.usePrimaryDecryptKey.is(":checked:not(:disabled)") ? "enable" : "disable"); }, this));
        this.primaryDecryptKey = $("select[name=primarydecryptkey]", this.fieldset).combobox({editable: false, disabled: true, width: 120, panelHeight: "auto"});

        this.usePrimarySignKey = $("input[name=useprimarysignkey]:checkbox", this.fieldset);
        this.usePrimarySignKey.change($.proxy(function() {
            var enabled = this.usePrimarySignKey.is(":checked:not(:disabled)");
            this.primarySignKey.combobox(enabled ? "enable" : "disable");
            this.primaryReceiptSignature.combobox(enabled ? "enable" : "disable");
        }, this));
        this.primarySignKey = $("select[name=primaryreceiptsingkey]", this.fieldset).combobox({width: 120, editable: false, disabled: true, panelHeight: "auto", onChange: $.proxy(this._onChange$PrimarySigningKey, this)});
        this.primaryReceiptSignature = $("select[name=primaryreceiptsignature]", this.fieldset).combobox({width: 120, editable: false, disabled: true, panelHeight: "auto"});

        this.useSecondaryDecryptKey = $("input[name=usesecondarydecryptkey]:checkbox", this.fieldset)
                .change($.proxy(function () { this.secondaryDecryptKey.combobox(this.useSecondaryDecryptKey.is(":checked:not(:disabled)") ? "enable" : "disable"); }, this));
        this.secondaryDecryptKey = $("select[name=secondarydecryptkey]", this.fieldset).combobox({editable: false, disabled: true, width: 120, panelHeight: "auto"});

        this.useSecondarySignKey = $("input[name=usesecondarysignkey]:checkbox", this.fieldset);
        this.useSecondarySignKey.change($.proxy(function() {
            var enabled = this.useSecondarySignKey.is(":checked:not(:disabled)");
            this.secondarySignKey.combobox(enabled ? "enable" : "disable");
            this.secondaryReceiptSignature.combobox(enabled ? "enable" : "disable");
        }, this));
        this.secondarySignKey = $("select[name=secondaryreceiptsingkey]", this.fieldset).combobox({width: 120, editable: false, disabled: true, panelHeight: "auto", onChange: $.proxy(this._onChange$SecondarySigningKey, this)});
        this.secondaryReceiptSignature = $("select[name=secondaryreceiptsignature]", this.fieldset).combobox({width: 120, editable: false, disabled: true, panelHeight: "auto"});

        this.messageEncryptRequired = $("input[name=encryptrequired]:checkbox", this.fieldset);
        this.messageSignatureRequired = $("input[name=signaturerequired]:checkbox", this.fieldset);
        this.messageWithoutFilenameAllowed = $("input[name=allowmessagewofile]:checkbox", this.fieldset);
        this.messageRawFileKept = $("input[name=keeprawfile]:checkbox", this.fieldset);
        this.fileOverwriting = $("input[name=fileoverwriting]:checkbox", this.fieldset).change($.proxy(function() {
            var enabled = this.fileOverwriting.is(":checked:not(:disabled)");
            this.fileOverwritingPolicy.combobox(enabled ? "enable" : "disable").combobox(enabled ? "enableValidation" : "disableValidation");
        }, this));
        this.fileOverwritingPolicy = $("select[name=fileoverwritingpolicy]", this.fieldset).combobox({editable: false, validType: "non_empty", onLoadSuccess: $.noop, width: 120, panelHeight: "auto"});

        this.bindTransfers = $("input[name=bindtransfers]:checkbox", this.fieldset);
        this.bindTransfers.change($.proxy(function() {
            var enabled = this.bindTransfers.is(":checked:not(:disabled)");
            this.transferUser.combobox(enabled ? "enable": "disable", !enabled).combobox(enabled ? "enableValidation" : "disableValidation");
            this.transferDomain.combobox(enabled ? "enable": "disable", !enabled).combobox(enabled ? "enableValidation" : "disableValidation");
        }, this));
        this.transferUser = $("input[name=transferuser]", this.fieldset).combobox({
            required: true, editable: false, width: 120, onLoadSuccess: $.noop,
            validType: "as2_user_nonempty", missingMessage: window.R.string.AS2_ERROR_BAD_TRANSFER_BINDING
        });
        this.transferDomain = $("input[name=transfdomain]", this.fieldset).combobox({
            required: true, editable: false, width: 120,
            onLoadSuccess: $.noop, onChange: $.proxy(this._onChange$BindTransfersDomain, this),
            validType: "non_empty", missingMessage: window.R.string.AS2_ERROR_BAD_TRANSFER_BINDING, invalidMessage: window.R.string.AS_ERROR_BAD_TRANAFER_DOMAIN
        });

        this.uploadDir = $("input[name=uploaddir]", this.fieldset).textbox({required: true, validType: "astwo_uploaddir", missingMessage: window.R.string.AS2_ERROR_BAD_UPLOAD_DIR, invalidMessage: window.R.string.AS2_ERROR_BAD_UPLOAD_DIR, width: "50%"});
        this.receiptText = $("textarea[name=receiptext]", this.fieldset).textbox({multiline: true, width: "40%", height: 90});
        this.fromAddress = $("input[name=from]", this.fieldset).textbox({validType: "email", width: "40%"});

        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.AS2ConfigurationView.LISTENER;
        this._adjustFieldState();
    },

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

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

    getPrimaryDecryptionKey: function() {
        return this.usePrimaryDecryptKey.is(":checked:not(:disabled)") ? this.primaryDecryptKey.combobox("getValue") : null;
    },

    setPrimaryDecryptionKey: function(value) {
        this.usePrimaryDecryptKey.prop("checked", !!value).change();
        if (value) {
            this.primaryDecryptKey.combobox("clear").combobox("select", value)
        }
    },

    setPrimaryDecryptionKeys: function(values) {
        this.primaryDecryptKey.combobox("loadData", values);
    },

    getPrimaryReceiptSigningKey: function() {
        return this.usePrimarySignKey.is(":checked:not(:disabled)") ? this.primarySignKey.combobox("getValue") : null;
    },

    setPrimaryReceiptSigningKey: function(value) {
        this.usePrimarySignKey.prop("checked", !!value).change();
        if (value) {
            this.primarySignKey.combobox("clear").combobox("select", value)
        }
    },

    setPrimaryReceiptSigningKeys: function(values) {
        this.primarySignKey.combobox("loadData", values);
    },

    getPrimaryReceiptSignatureAlgorithm: function() {
        return this.primaryReceiptSignature.combobox("options").disabled ? null : this.primaryReceiptSignature.combobox("getValue");
    },

    setPrimaryReceiptSignatureAlgorithm: function(value) {
        if (value) {
            this.primaryReceiptSignature.combobox("select", value);
        }
    },

    setPrimaryReceiptSignatureAlgorithms: function(values) {
        this.primaryReceiptSignature.combobox("loadData", values);
    },

    getSecondaryDecryptionKey: function() {
        return this.useSecondaryDecryptKey.is(":checked:not(:disabled)") ? this.secondaryDecryptKey.combobox("getValue") : null;
    },

    setSecondaryDecryptionKey: function(value) {
        this.useSecondaryDecryptKey.prop("checked", !!value).change();
        if (value) {
            this.secondaryDecryptKey.combobox("clear").combobox("select", value)
        }
    },

    setSecondaryDecryptionKeys: function(values) {
        this.secondaryDecryptKey.combobox("loadData", values);
    },

    getSecondaryReceiptSigningKey: function() {
        return this.useSecondarySignKey.is(":checked:not(:disabled)") ? this.secondarySignKey.combobox("getValue") : null;
    },

    setSecondaryReceiptSigningKey: function(value) {
        this.useSecondarySignKey.prop("checked", !!value).change();
        if (value) {
            this.secondarySignKey.combobox("clear").combobox("select", value)
        }
    },

    setSecondaryReceiptSigningKeys: function(values) {
        this.secondarySignKey.combobox("loadData", values);
    },

    getSecondaryReceiptSignatureAlgorithm: function() {
        return this.secondaryReceiptSignature.combobox("options").disabled ? null : this.secondaryReceiptSignature.combobox("getValue");
    },

    setSecondaryReceiptSignatureAlgorithm: function(value) {
        if (value) {
            this.secondaryReceiptSignature.combobox("select", value);
        }
    },

    setSecondaryReceiptSignatureAlgorithms: function(values) {
        this.secondaryReceiptSignature.combobox("loadData", values);
    },

    getMessageEncryptionRequired: function() {
        return this.messageEncryptRequired.is(":checked");
    },

    setMessageEncryptionRequired: function(value) {
        this.messageEncryptRequired.prop("checked", !!value);
    },

    getMessageSignatureRequired: function() {
        return this.messageSignatureRequired.is(":checked");
    },

    setMessageSignatureRequired: function(value) {
        this.messageSignatureRequired.prop("checked", !!value);
    },

    getMessageWithoutFilenameAllowed: function() {
        return this.messageWithoutFilenameAllowed.is(":checked");
    },

    setMessageWithoutFilenameAllowed: function(value) {
        this.messageWithoutFilenameAllowed.prop("checked", !!value);
    },

    getKeepingRawMessageFileRequired: function() {
        return this.messageRawFileKept.is(":checked");
    },

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

    getFileOverwritingPolicy: function() {
        return this.fileOverwriting.is(":checked") ? this.fileOverwritingPolicy.combobox("getValue") : null;
    },

    setFileOverwritingPolicy: function(value) {
        if (value != null) {
            this.fileOverwriting.prop("checked", true).change();
            this.fileOverwritingPolicy.combobox("select", value);
        } else {
            this.fileOverwriting.prop("checked", false).change();
            this.fileOverwritingPolicy.combobox("reset");
        }
    },

    isBindUnauthenticatedTransfers: function() {
        return this.bindTransfers.is(":checked");
    },

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

    getBindTransfersDomain: function() {
        return this.transferDomain.combobox("getValue");
    },

    setBindTransfersDomain: function(value) {
        this.transferDomain.combobox("clear").combobox("select", value);
    },

    setAvailableDomains: function(values) {
        this.transferDomain.combobox("loadData", values);
    },

    getBindTransfersUser: function() {
        return this.transferUser.combobox("getValue");
    },

    setBindTransfersUser: function(value) {
        this.transferUser.combobox("clear").combobox("setValue", value);
    },

    setAvailableUsers: function(values) {
        var value = this.transferUser.combobox("getValue");
        this.transferUser.combobox("clear").combobox("loadData", values)
                .combobox("select", value).combobox("validate");
    },

    getUploadDirectory: function() {
        return this.uploadDir.textbox("getValue");
    },

    setUploadDirectory: function(value) {
        this.uploadDir.textbox("setValue", value);
    },

    getReceiptText: function() {
        return this.receiptText.textbox("getValue");
    },

    setReceiptText: function(value) {
        this.receiptText.textbox("setValue", value);
    },

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

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

    _onChange$PrimarySigningKey: function() {
        var key = this.primarySignKey.combobox("getValue");
        this.listener && this.listener.onChangePrimaryReceiptSigningKey(key);
    },

    _onChange$SecondarySigningKey: function() {
        var key = this.secondarySignKey.combobox("getValue");
        this.listener && this.listener.onChangeSecondaryReceiptSigningKey(key);
    },

    _onChange$BindTransfersDomain: function(newValue) {
        if (newValue) {
            this.listener.onChangeBindTransfersDomain(newValue);
        }
    },

    _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.usePrimaryDecryptKey.prop("disabled", !enabled).change();
        this.usePrimarySignKey.prop("disabled", !enabled).change();
        this.useSecondaryDecryptKey.prop("disabled", !enabled).change();
        this.useSecondarySignKey.prop("disabled", !enabled).change();
        this.messageEncryptRequired.prop("disabled", !enabled);
        this.messageSignatureRequired.prop("disabled", !enabled);
        this.messageWithoutFilenameAllowed.prop("disabled", !enabled);
        this.messageRawFileKept.prop("disabled", !enabled);
        this.fileOverwriting.prop("disabled", !enabled).change();
        this.bindTransfers.prop("disabled", !enabled).change();
        this.uploadDir.textbox(enabled ? "enable" : "disable");
        this.receiptText.textbox(enabled ? "enable" : "disable");
        this.fromAddress.textbox(enabled ? "enable": "disable");

        this.fieldset.form("validate");
    }
});
jscape.settings.AS2ConfigurationView.LISTENER = {
    onChangePrimaryReceiptSigningKey: $.noop,
    onChangeSecondaryReceiptSigningKey: $.noop,
    onChangeBindTransfersDomain: $.noop,
    onApply: $.noop,
    onDiscard: $.noop
};

/** @class */
jscape.settings.SelfRegistrationController = Class.extend(
    /** @lends {jscape.settings.SelfRegistrationController.prototype} */
{
    DEFAULT_DESCRIPTOR: new jscape.SelfRegistrationServiceDescriptor(),

    descriptor: null,
    view: null,

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

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

    onResume: function() {
        this.managementService.getRegistrationServiceConfiguration()
                .done($.proxy(function(descriptor) { this.descriptor = descriptor; }, this))
                .fail($.proxy(function() { this.descriptor = this.DEFAULT_DESCRIPTOR; }, this))
                .always($.proxy(function() { this.view && this._setupView(this.descriptor); }, this));
    },

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

    onApply: function() {
        return this.managementService.setRegistrationServiceConfiguration(this._createDescriptor())
                .done($.proxy(function (descriptor) { this.descriptor = descriptor; }, this))
                .done($.proxy(this._fireApplySuccess, this));
    },

    onDiscard: function() {
        this._setupView(this.descriptor);
    },

    _createDescriptor: function() {
        return new jscape.SelfRegistrationServiceDescriptor(this.view.isShowRegistrationLink(),
                                                            this.view.isUseEmailAsLogin(),
                                                            this.view.isCaptchaRequired());
    },

    _setupView: function(descriptor) {
        if (descriptor) {
            this.view.setShowRegistrationLink(descriptor.showRegistrationLink);
            this.view.setUseEmailAsLogin(descriptor.useEmailAddressAsLogin);
            this.view.setCaptchaRequired(descriptor.captchaRequired);
        }
    },

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

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

        this.showLink = $("input[name=showlink]:checkbox", this.fieldset);
        this.useEmailAsLogin = $("input[name=emailaslogin]:checkbox", this.fieldset);
        this.requireCaptcha = $("input[name=requirecaptcha]:checkbox", this.fieldset);

        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.SelfRegistrationView.LISTENER;
    },

    isShowRegistrationLink: function() {
        return this.showLink.is(":checked");
    },

    setShowRegistrationLink: function(value) {
        this.showLink.prop("checked", !!value);
    },

    isUseEmailAsLogin: function() {
        return this.useEmailAsLogin.is(":checked");
    },

    setUseEmailAsLogin: function(value) {
        this.useEmailAsLogin.prop("checked", !!value);
    },

    isCaptchaRequired: function() {
        return this.requireCaptcha.is(":checked");
    },

    setCaptchaRequired: function(value) {
        this.requireCaptcha.prop("checked", !!value);
    },

    _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();
    }
});
jscape.settings.SelfRegistrationView.LISTENER = {
    onApply: $.noop,
    onDiscard: $.noop
};

/** @class */
jscape.settings.AddLanguageDialog = Class.extend(
    /** @lends {jscape.settings.AddLanguageDialog.prototype} */
{
    /** @constructor */
    initialize: function() {
        this.dialog = $("#d-sswres-add").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.language = $("select[name=language]", this.dialog).combobox({required: true, editable: false, width: "60%"});
    },

    getLanguage: function() {
        return this.language.combobox("getValue");
    },

    getDisplayName: function() {
        return this.language.combobox("getText");
    },

    disableLanguages: function (values) {
        if (values.length == 0) {
            return;
        }
        var data = this.language.combobox("getData");
        var valueField = this.language.combobox("options").valueField;
        $.each(data, function (index, entry) {
            entry.disabled = $.inArray(entry[valueField], values) != -1;
        });
        this.language.combobox("loadData", data);
    },

    show: function (listener) {
        this.listener = listener;
        this.dialog.dialog("center").dialog("open");

        $.each(this.language.combobox("getData"), $.proxy(function (_, entry) {
            if (!entry.disabled) {
                this.language.combobox("select", entry);
                return false;
            }
        }, this));
    },

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

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

    _onSubmit: function () {
        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.WebResourcesController = Class.extend(
    /** @lends {jscape.settings.WebResourcesController.prototype} */
{
    DEFAULT_LANG: "",

    resources: null,
    logoData: null,
    view: null,

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

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

    onResume: function () {
        this.managementService.getWebServiceResources()
                .done($.proxy(function (resources, logoData) {
                                  this.resources = this._copyResources(resources);
                                  this.logoData = logoData;
                                  this.view && this._setupView(resources, logoData);
                              }, this))
                .fail($.proxy(function () {
                                  this.resources = [];
                                  this.logoData = null;
                                 this.view && this._setupView([], null);
                              }, this));
    },

    hasChanged: function() {
        return (this.resources != null && !Object._equals(this.resources, this._createResources()))
               || (this.logoData != null && !Object._equals(this.logoData, this._createLogoData()));
    },

    onApply: function () {
        var resources = this._createResources();
        var logoData = this._createLogoData();
        return this.managementService.setWebServiceResources(resources, logoData)
                .done($.proxy(function () {
                          this.resources = this._copyResources(resources);
                          this.logoData = logoData;
                          this._setupView(resources, this.logoData);
                      }, this))
                .done($.proxy(this._fireApplySuccess, this));
    },

    onDiscard: function() {
        var resources = this.resources;
        this.resources = this._copyResources(resources);
        this._setupView(resources, this.logoData);
    },

    onChangeLogo: function (file) {
        if (file && file.type.match("image.*") && window.FileReader) {
            var type = file.type;
            var reader = new FileReader();
            reader.onload = $.proxy(function (e) {
                this.view.setLogoData(e.target.result, type);
                reader.onload = null;
                type = reader = null;
            }, this);
            reader.readAsDataURL(file);
        } else {
            this.view.setLogoData(null);
        }
    },

    onAddLanguage: function() {
        var dialog = new jscape.settings.AddLanguageDialog();
        dialog.disableLanguages($.map(this.view.getResources(), function(resource) { return resource.lang; }));
        dialog.show({
            onSubmit: $.proxy(function(d) {
                var lang = d.getLanguage();
                var displayName = d.getDisplayName();
                d.destroy();
                this._languageAdded(lang, displayName);
            }, this),
            onCancel: function(d) { d.destroy(); }
        });
    },

    onResetLanguages: function() {
        var resources = this.resources;
        this.resources = this._copyResources(resources);
        this.view.setResources(resources);
        this.view.selectLanguage(this.DEFAULT_LANG);
    },

    _languageAdded: function(language, displayName) {
        var defaultResources = $.grep(this.resources, function(item) { return item.isDefault(); });
        var defaultProperties = defaultResources.length ? defaultResources[0].properties : {};
        var newResources = new jscape.WebResources(language, displayName, $.extend({}, defaultProperties));
        this.view.setResources(this.view.getResources().concat(newResources));
        this.view.selectLanguage(language);
    },

    _copyResources: function(resources) {
        return $.map(resources, function(resource) { return resource.clone(); });
    },

    _createResources: function() {
        return this.view.getResources();
    },

    _createLogoData: function() {
        return this.view.getLogoData();
    },

    _setupView: function(resources, logoData) {
        this.view.setResources(resources);
        this.view.setLogoData(logoData);
    },

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

/** @class */
jscape.settings.WebResourcesView = Class.extend(
    /** @lends {jscape.settings.WebResourcesView.prototype} */
{
    DATA_URL: {pattern: /data:image\/.*;base64,(.+)/, template: "data:{0};base64,{1}", placeholder: "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"},

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

        this.logo = $("div.logo-preview>img", this.fieldset);
        this.logoFile = $("input[name=logo]", this.fieldset).css({width: 0, height: 0, opacity: 0, position: "absolute", left: "-10000px"});
        this.logoFile.change($.proxy(this._onChange$Logo, this));
        this.logoButton = $("a[role=button][name=changelogo]", this.fieldset).linkbutton({onClick: $.proxy(function() { this.logoFile.click(); }, this)});
        this.logo.parent().click($.proxy(function() { this.logoFile.click(); }, this));

        this.language = $("select[name=language]", this.fieldset);
        this.language.combobox({
            required: true, editable: false, width: 170, panelHeight: "auto",
            valueField: "lang", textField: "displayName", selectOnNavigation: false,
            onChange: $.proxy(this._onChange$Language, this)
        });

        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",
            onAfterEdit: $.proxy(this._commitChanges, this)
        });

        this.addButton = $("a[role=button][name=add]", this.fieldset).linkbutton({onClick: $.proxy(this._onClick$AddButton, this)});
        this.resetButton = $("a[role=button][name=reset]", this.fieldset).linkbutton({onClick: $.proxy(this._onClick$ResetButton, 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)});
    },

    getLogoData: function () {
        var dataUrl = this.logo.attr("src");
        return dataUrl && dataUrl != this.DATA_URL.placeholder ? dataUrl.replace(this.DATA_URL.pattern, "$1") : "";
    },

    setLogoData: function (data, type) {
        data = data ? data : this.DATA_URL.placeholder;
        this.logo[0].src = this.DATA_URL.pattern.test(data) ? data : this.DATA_URL.template.supplant({0: (type || "image/png"), 1: data || ""});
    },

    getResources: function() {
        var data = this.language.combobox("getData");
        return $.map(data, function(item) { if (item.isDefault()) { item.displayName = ""; } return item; });
    },

    setResources: function (values) {
        var data = $.map(values || [], function(item) { if (item.isDefault()) { item.displayName = "default"; } return item; });
        this.language.combobox("loadData", data);
        this._onChange$Language();
    },

    selectLanguage: function (value) {
        this.language.combobox("select", value);
    },

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

    _onChange$Logo: function (e) {
        var files = e.target.files;
        if (files && files.length) {
            this.listener.onChangeLogo(files[0]);
        }
        return false;
    },

    _onChange$Language: function() {
        var language = this.language.combobox("getValue");
        var properties = this._propertiesFor(language);
        if (properties != null) {
            this._selectProperties(properties);
        }
        return false;
    },

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

    _onClick$ResetButton: function() {
        this.listener.onResetLanguages();
    },

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

    _commitChanges: function(_, data) {
        var language = this.language.combobox("getValue");
        var properties = this._propertiesFor(language);
        if (properties != null) {
            properties[data.name] = data.value;
        }
    },

    _selectProperties: function(properties) {
        var data = $.map(properties, function(value, key) { return {name: key, value: value, editor: "text"}});
        this.data.propertygrid("loading").propertygrid("loadData", data).propertygrid("loaded");
    },

    _propertiesFor: function (language) {
        var data = this.language.combobox("getData");
        for (var i = 0; i < data.length; i++) {
            var resources = data[i];
            if (resources.lang == language) {
                return resources.properties;
            }
        }
        return null;
    }
});
jscape.settings.WebResourcesView.LISTENER = {
    onChangeLogo: $.noop,
    onAddLanguage: $.noop,
    onResetLanguages: $.noop,
    onApply: $.noop,
    onDiscard: $.noop
};

/** @class */
jscape.settings.DocumentViewerController = Class.extend(
    /** @lends {jscape.settings.DocumentViewerController.prototype} */
{
    /** @const */
    DEFAULT_CONFIG: new jscape.DocumentViewerConfiguration(false, null, null, null, 10),

    config: null,
    allowed: false,
    view: null,

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

    onCreate: function(managementService) {
        this.managementService = managementService;
        this.allowed = false;
    },

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

    onResume: function () {
        this.managementService.getDocumentViewerAllowed()
                .then($.proxy(function (value) {
                          this.allowed = !!value;
                          return this.allowed
                                  ? this.managementService.getDocumentViewerConfiguration()
                                  : $.Deferred().reject().promise();
                      }, this))
                .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));
    },

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

    onApply: function () {
        if (!this.allowed) {
            return $.Deferred().resolve().promise();
        }
        return this.managementService.setDocumentViewerConfiguration(this._createConfiguration())
                .done($.proxy(function (config) { this.config = config; }, this))
                .done($.proxy(this._fireApplySuccess, this));
    },

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

    onSelectDirectory: function () {
        return new SelectPathController($.proxy(this.managementService.listFileSystem, this.managementService),
                                        $.proxy(this.managementService.createFileSystemDir, this.managementService))
                .selectDirectory().then(function (entry) { return entry.path; });
    },

    _createConfiguration: function() {
        return new jscape.DocumentViewerConfiguration(this.view.getEnabled(),
                                                      this.view.getOfficeDir(),
                                                      this.view.getSwfToolDir(),
                                                      this.view.getOutputDir(),
                                                      this.view.getThreadCount());
    },

    _setupView: function(config) {
        if (config) {
            this.view.setEnabled(config.enabled);
            this.view.setOfficeDir(config.officeDirectory);
            this.view.setSwfToolDir(config.swfToolDirectory);
            this.view.setOutputDir(config.outputDirectory);
            this.view.setThreadCount(config.threads);
        }
    },

    _initValidators: function() {
        var v = new jscape.Validator();
        v.rule("docviewer_allowed", $.proxy(function() { return this.allowed; }, this));
    },

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

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

        this.enabled = $("input[name=enabled]:checkbox", this.fieldset)
                .click($.proxy(this._onClick$Enabled, this))
                .change($.proxy(this._adjustFieldState, this));

        this.officeDir = $("input[name=officedir]", this.fieldset).textbox({required: true, validType: "non_empty", missingMessage: window.R.string.DOC_VIEWER_ERROR_BAD_OFFICE_DIR, invalidMessage: window.R.string.DOC_VIEWER_ERROR_BAD_OFFICE_DIR, tipPosition: "bottom",  width: "65%"});
        this.officeDirBrowseButton = $("a[role=button][name=browseofficedir]", this.fieldset).linkbutton({onClick: $.proxy(this._onClick$OfficeDirBrowseButton, this)});

        this.swfToolDir = $("input[name=swftooldir]", this.fieldset).textbox({width: "65%"});
        this.swfToolDirBrowseButton = $("a[role=button][name=browseswftooldir]", this.fieldset).linkbutton({onClick: $.proxy(this._onClick$SwfToolDirBrowseButton, this)});

        this.outputDir = $("input[name=outdir]", this.fieldset).textbox({required: true, validType: "non_empty", missingMessage: window.R.string.DOC_VIEWER_ERROR_BAD_OUTPUT_DIR, invalidMessage: window.R.string.DOC_VIEWER_ERROR_BAD_OUTPUT_DIR, tipPosition: "bottom", width: "65%"});
        this.outputDirBrowseButton = $("a[role=button][name=browseoutdir]", this.fieldset).linkbutton({onClick: $.proxy(this._onClick$OutputDirBrowseButton, this)});

        this.threadCount = $("input[name=threads]", this.fieldset).numberspinner({required: true, min: 1, max: 100, width: 80});

        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.DocumentViewerView.LISTENER;
        this._adjustFieldState();
    },

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

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

    getOfficeDir: function() {
        return this.officeDir.textbox("getValue");
    },

    setOfficeDir: function(value) {
        this.officeDir.textbox("setValue", value);
    },

    getSwfToolDir: function() {
        return this.swfToolDir.textbox("getValue");
    },

    setSwfToolDir: function(value) {
        this.swfToolDir.textbox("setValue", value);
    },

    getOutputDir: function() {
        return this.outputDir.textbox("getValue");
    },

    setOutputDir: function(value) {
        this.outputDir.textbox("setValue", value);
    },

    getThreadCount: function() {
        return parseInt(this.threadCount.numberspinner("getValue"));
    },

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

    _onClick$Enabled: function(e) {
        if (this.getEnabled()) {
            var allowed = new jscape.Validator().isSatisfied("docviewer_allowed");
            if (!allowed) {
                e.preventDefault();
                e.stopImmediatePropagation();
                this.enabled.prop("checked", false).change();

                $.messager.alert(window.R.string.DIALOG_TITLE_ERROR,
                                 window.R.string.DOC_VIEWER_ERROR_NOT_ALLOWED,
                                 "error");
            }
        }
    },

    _onClick$OfficeDirBrowseButton: function() {
        this.listener.onSelectDirectory()
                .done($.proxy(function (path) {
                          this.setOfficeDir(path);
                          this.officeDir.textbox("textbox").select();
                      }, this));
    },

    _onClick$SwfToolDirBrowseButton: function() {
        this.listener.onSelectDirectory()
                .done($.proxy(function(path) {
                                  this.setSwfToolDir(path);
                                  this.swfToolDir.textbox("textbox").select();
                              }, this));
    },

    _onClick$OutputDirBrowseButton: function() {
        this.listener.onSelectDirectory()
                .done($.proxy(function(path) {
                                  this.setOutputDir(path);
                                  this.outputDir.textbox("textbox").select();
                              }, 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();
    },

    _adjustFieldState: function() {
        var enabled = this.getEnabled();
        $.each([this.officeDir, this.swfToolDir, this.outputDir], function(_, input) {
            input.textbox(enabled ? "enable" : "disable");
        });
        $.each([this.officeDirBrowseButton, this.swfToolDirBrowseButton, this.outputDirBrowseButton], function(_, button) {
            button.linkbutton(enabled ? "enable" : "disable");
        });
        this.threadCount.numberspinner(enabled ? "enable" : "disable");

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