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

/** @class */
jscape.ServiceConfiguration = Class.extend(
        /** @lends {jscape.Service.prototype} */
{
    initialize: function (a) {
        this.protocol = a || undefined;
    },

    clone: function() {
        var attrs = {};
        $.each(["uploadForms", "languages"], $.proxy(function(_, prop) {
            if ($.type(this[prop]) == "array") {
                attrs[prop] = $.map(this[prop], function(entry) { return entry.clone(); });
            }
        }, this));
        return $.extend(new jscape.ServiceConfiguration(), this, attrs);
    }
});
jscape.ServiceConfiguration.fromJSON = function(data) {
    if (data) {
        $.each({
                   "uploadForms": function(value) { return $.map(value || [], jscape.UploadForm.fromJSON); },
                   "languages": function(value) { return $.map(value || [], jscape.WebResources.fromJSON); }
               },
               function(prop, provider) { if (data.hasOwnProperty(prop)) { data[prop] = provider(data[prop]); }}
        );
        if (data.hasOwnProperty("theme") && !data.theme) {
            data.theme = "default";
        }
        return $.extend(new jscape.ServiceConfiguration(), data);
    }
    return null;
};
jscape.ServiceConfiguration.ftp = function(timeout, dataTimeout, banner, passiveIp, portRange, sendBuffer, receiveBuffer, transferMode, dataConnectionMode, ciphers, shutdownCommandSsl, shutdownDataSsl, commandClientCertificate, dataClientCertificate, forceDataEncryption, blockPasv, blockBounce, tcpNoDelay, networkCharset, fileCharset) {
    return $.extend(new jscape.ServiceConfiguration(jscape.Service.Protocol.FTP), {
        timeout: parseInt(timeout) || 0, dataTimeout: parseInt(dataTimeout) || 0, welcomeMessage: banner || "", passiveIp: passiveIp || "", portRange: portRange || null,
        sendBufferSize: parseInt(sendBuffer) || null, receiveBufferSize: parseInt(receiveBuffer) || null, defaultTransferMode: transferMode == "IMAGE" ? transferMode : "ASCII",
        dataConnectionMode: dataConnectionMode || "ALL", cipherSuites: ciphers || undefined,
        shutdownSsl: !!shutdownCommandSsl, shutdownDataSsl: !!shutdownDataSsl, commandRequireClientCertificate: !!commandClientCertificate, dataRequireClientCertificate: !!dataClientCertificate, forceDataEncryption: !!forceDataEncryption,
        blockPasvAttack: !!blockPasv, blockBounceAttack: !!blockBounce, tcpNoDelayEnabled: !!tcpNoDelay, networkCharset: networkCharset, fileCharset: fileCharset
    });
};
jscape.ServiceConfiguration.aftp = function(timeout, dataTimeout, tcpNoDelay, maxLossListSize, ciphers) {
    return $.extend(new jscape.ServiceConfiguration(jscape.Service.Protocol.AFTP), {timeout: parseInt(timeout) || 0, dataTimeout: parseInt(dataTimeout) || 0, tcpNoDelayEnabled: !!tcpNoDelay, maxLossListSize: parseInt(maxLossListSize) || 0, cipherSuites: ciphers || undefined});
};
jscape.ServiceConfiguration.sftp = function(timeout, version, startupBanner, authBanner, sendBuffer, receiveBuffer, tcpNoDelay, disableExpandedLongName, sshKexes, sshCiphers, sshMacs, sshCompressions) {
    return $.extend(new jscape.ServiceConfiguration(jscape.Service.Protocol.SFTP), {
        timeout: parseInt(timeout) || 0, softwareVersion: version || "JSCAPE", startupBanner: startupBanner || "", authBanner: authBanner || "", sendBufferSize: parseInt(sendBuffer) || null, receiveBufferSize: parseInt(receiveBuffer) || null,
        tcpNoDelayEnabled: !!tcpNoDelay, disableRealPathExpandedLongName: !!disableExpandedLongName, supportedKexes: sshKexes, supportedCiphers: sshCiphers, supportedMacs: sshMacs, supportedCompressions: sshCompressions
    });
};
jscape.ServiceConfiguration.oftp = function(timeout, maxDataBufferSize, maxCredit, ciphers, protocols) {
    return $.extend(new jscape.ServiceConfiguration(jscape.Service.Protocol.OFTP), {
        timeout: parseInt(timeout) || 0, maxDataExchangeBufferSize: parseInt(maxDataBufferSize) || 0, maxCredit: parseInt(maxCredit) || 0,
        cipherSuites: ciphers || undefined, enabledProtocols: protocols || undefined
    });
};
jscape.ServiceConfiguration.tftp = function(retransmitAttempts, retransmitInterval, dirListingGenerationEnabled, fileHashGenerationEnabled) {
    return $.extend(new jscape.ServiceConfiguration(jscape.Service.Protocol.TFTP), {
        maxRetransmitAttempts: parseInt(retransmitAttempts) || 0, retransmitInterval: parseInt(retransmitInterval) || 0, directoryListingGenerationEnabled: !!dirListingGenerationEnabled, fileHashGenerationEnabled: !!fileHashGenerationEnabled
    });
};
jscape.ServiceConfiguration.http = function(theme, logoData, timeout, logoutUrl, autoLogout, selfRegistration, appletEnabled, docViewerEnabled, adHocEnabled, showTransferType, showLoginInfo, showAccountLink, showSearch, uploadForms, uploadFormRequired, languages, aftpNatHost) {
    return $.extend(new jscape.ServiceConfiguration(jscape.Service.Protocol.HTTP), {
        theme: theme || "default", logoData: logoData || "", timeout: parseInt(timeout) || 0, logoutUrl: logoutUrl || undefined, autoLogout: autoLogout || null, selfRegistration: selfRegistration || new jscape.SelfRegistrationConfiguration(),
        appletEnabled: !!appletEnabled, documentViewerEnabled: !!docViewerEnabled, adHocTransferEnabled: !!adHocEnabled,
        showTransferType: !!showTransferType, showLoginInfo: !!showLoginInfo, showAccountLink: !!showAccountLink, showSearch: !!showSearch,
        uploadForms: uploadForms || [], uploadFormRequired: !!uploadFormRequired, languages: languages, aftpNatHost: aftpNatHost || null
    });
};
jscape.ServiceConfiguration.webdav = function(theme, logoData, logoutUrl, showLoginInfo, showAccountLink, languages) {
    return $.extend(new jscape.ServiceConfiguration(jscape.Service.Protocol.WEBDAV), {
        theme: theme || "default", logoData: logoData || "", logoutUrl: logoutUrl || undefined, showLoginInfo: !!showLoginInfo, showAccountLink: !!showAccountLink, languages: languages || []
    });
};
/** @class */
jscape.SelfRegistrationConfiguration = Class.extend(
    /** @lends {jscape.SelfRegistrationConfiguration.prototype} */
{
    /** @constructor */
    initialize: function(a, b) {
        this.enabled = a || false;
        this.accountTemplate = b || "Default";
    }
});
jscape.SelfRegistrationConfiguration.fromJSON = function(data) {
    return new jscape.SelfRegistrationConfiguration(data || data.enabled, data && data.accountTemplate);
};

/** @class */
jscape.UploadForm = Class.extend(
    /** @lends {jscape.UploadForm.prototype} */
{
    /** @constructor */
    initialize: function(a, b, c, d, e, f) {
        this.name = a || "";
        this.description = b || "";
        this.enabled = !!c;
        this.batch = !!d;
        this.group = e || null;
        this.inputs = f || [];
    },

    clone: function() {
        return new jscape.UploadForm(this.name, this.description, this.enabled, this.batch, this.group, $.map(this.inputs, function(entry) { return entry.clone(); }));
    }
});
jscape.UploadForm.fromJSON = function(data) {
    return $.extend(new jscape.UploadForm(), data, {inputs: $.map(data.inputs || [], jscape.UploadForm.Input.fromJSON)});
};
/** @class */
jscape.UploadForm.Input = Class.extend(
    /** @lends {jscape.UploadForm.Input.prototype} */
{
    /** @constructor */
    initialize: function(a, b, c, d, e) {
        this.type = a || jscape.UploadForm.Input.TYPE.TEXT;
        this.name = b || "";
        this.label = c || "";
        this.value = $.isArray(d) ? d.join(",") : d || "";
        this.required = e !== undefined ? !!e : true;
    },

    clone: function() {
        return new jscape.UploadForm.Input(this.type, this.name, this.label, this.value, this.required);
    },

    toJSON: function() {
        var multivalue = $.inArray(this.type, [jscape.UploadForm.Input.TYPE.DROPDOWN, jscape.UploadForm.Input.TYPE.MULTISELECT, jscape.UploadForm.Input.TYPE.RADIO]) != -1;
        return $.extend({type: this.type, name: this.name, label: this.label, required: this.required}, multivalue ? {values: this.value.split(",")} : {value: this.value});
    }
});
jscape.UploadForm.Input.fromJSON = function(data) {
    return new jscape.UploadForm.Input(data.type, data.name, data.label, data.value || data.values, data.required);
};
jscape.UploadForm.Input.TYPE = {TEXT: 'TEXT', MEMO: 'MEMO', DROPDOWN: 'DROPDOWN', MULTISELECT: 'MULTISELECT', RADIO: 'RADIO'};


/** @class */
jscape.domain.FtpConfigurationController = Class.extend(
    /** @lends {jscape.domain.FtpConfigurationController.prototype} */
{
    DEFAULT_CONFIG: jscape.ServiceConfiguration.ftp(300000, 60000),

    view: null,
    config: null,
    copy: null,
    sslCiphers: null,

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

        this.ciphersController = new jscape.domain.SslCiphersController();
    },

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

    onResume: function () {
        this.managementService.getServiceConfiguration(this.domainName, jscape.Service.Protocol.FTP)
                .done($.proxy(function (config) { this.config = config || this.DEFAULT_CONFIG; }, this))
                .fail($.proxy(function () { this.config = this.DEFAULT_CONFIG; }, this))
                .always($.proxy(function () {
                            this.copy = this.config.clone();
                            this.sslCiphers = this.config.cipherSuites || null;
                            this._setupView(this.config);
                        }, this));
    },

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

    onApply: function() {
        var config = this._createConfiguration();
        return this.managementService.setServiceConfiguration(this.domainName, jscape.Service.Protocol.FTP, config)
                .done($.proxy(function() {
                    this.config = config;
                    this.copy = this.config.clone();
                    this._setupView(this.config);
                }, this))
                .done($.proxy(this._fireApplySuccess, this));
    },

    onDiscard: function() {
        this.config = this.copy;
        this.copy = this.config.clone();
        this.sslCiphers = this.config && this.config.cipherSuites || null;
        this._setupView(this.config);
    },

    onSslCiphers: function() {
        this.ciphersController.start(this.managementService, this.domainName, this.sslCiphers)
                .done($.proxy(function(ciphers) { this.sslCiphers = ciphers; }, this));
    },

    _createConfiguration: function() {
        return jscape.ServiceConfiguration.ftp(this.view.getTimeout(),
                                               this.view.getDataTimeout(),
                                               this.view.getBanner(),
                                               this.view.getPassiveIp(),
                                               this.view.getPassivePortRange(),
                                               this.view.getSendBufferSize(),
                                               this.view.getReceiveBufferSize(),
                                               this.view.getDefaultTransferMode(),
                                               this.view.getDataConnectionMode(),
                                               this.sslCiphers,
                                               this.view.isShutdownCommandSsl(),
                                               this.view.isShutdownDataSsl(),
                                               this.view.isCommandRequireClientCertificate(),
                                               this.view.isDataRequireClientCertificate(),
                                               this.view.isForceDataEncryption(),
                                               this.view.isBlockPasvAttack(),
                                               this.view.isBlockBounceAttack(),
                                               this.view.getTcpNoDelay(),
                                               this.view.getNetworkCharset(),
                                               this.view.getFileCharset());
    },

    _setupView: function(config) {
        if (config && this.view) {
            this.view.setTimeout(config.timeout);
            this.view.setDataTimeout(config.dataTimeout);
            this.view.setBanner(config.welcomeMessage);
            this.view.setPassiveIp(config.passiveIp);
            this.view.setPassivePortRange(config.portRange);
            this.view.setSendBufferSize(config.sendBufferSize);
            this.view.setReceiveBufferSize(config.receiveBufferSize);
            this.view.setDefaultTransferMode(config.defaultTransferMode);
            this.view.setDataConnectionMode(config.dataConnectionMode);
            this.view.setShutdownCommandSsl(config.shutdownSsl);
            this.view.setShutdownDataSsl(config.shutdownDataSsl);
            this.view.setCommandRequireClientCertificate(config.commandRequireClientCertificate);
            this.view.setDataRequireClientCertificate(config.dataRequireClientCertificate);
            this.view.setForceDataEncryption(config.forceDataEncryption);
            this.view.setBlockPasvAttack(config.blockPasvAttack);
            this.view.setBlockBounceAttack(config.blockBounceAttack);
            this.view.setTcpNoDelay(config.tcpNoDelayEnabled);
            this.view.setNetworkCharset(config.networkCharset);
            this.view.setFileCharset(config.fileCharset);
        }
    },

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

/** @class */
jscape.domain.FtpConfigurationView = Class.extend(
    /** @lends {jscape.domain.FtpConfigurationView.prototype} */
{
    TIMEOUT_FACTOR: 60 * 1000,
    BUFFER_FACTOR: 1024,
    DEFAULT_CHARSET: "UTF-8",

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

        this.banner = $("textarea[name=banner]", this.fieldset).textbox({multiline: true, width: "70%", height: 90});

        this.timeout = $("input[name=cmdtimeout]", this.fieldset).numberspinner({required: true, min: 0, max: 999, value: 5, width: 80});
        this.dataTimeout = $("input[name=datatimeout]", this.fieldset).numberspinner({required: true, min: 0, max: 999, value: 1, width: 80});
        this.passiveIp = $("input[name=passiveip]", this.fieldset).textbox({required: false, validType: "length[1,255]", invalidMessage: window.R.string.SERVICES_ERROR_BAD_PASSIVE_IP, width: "70%"});

        this.usePortRange = $("input[name=passiveportrange]:checkbox", this.fieldset);
        this.usePortRange.change($.proxy(function() {
            var enabled = this.usePortRange.is(":checked");
            $.each([this.portRangeStart, this.portRangeEnd], function(_, input) {
                input.numberspinner(enabled ? "enable" : "disable").numberspinner(enabled ? "enableValidation" : "disableValidation");
            });
        }, this));
        this.portRangeStart = $("input[name=passiveportpstart]", this.fieldset).numberspinner({required: true, min: 1, max: 65535, value: 10000, width: 80, onChange: $.proxy(this._adjustPortRange, this)});
        this.portRangeEnd = $("input[name=passiveportpend]", this.fieldset).numberspinner({required: true, min: 1, max: 65535, value: 20000, width: 80, onChange: $.proxy(this._adjustPortRange, this)});

        this.useSendBuffer = $("input[name=usesendbuffer]:checkbox", this.fieldset);
        this.useSendBuffer.change($.proxy(function() {
            var enabled = this.useSendBuffer.is(":checked");
            this.sendBufferSize.numberspinner(enabled ? "enable" : "disable").numberspinner(enabled ? "enableValidation" : "disableValidation");
        }, this));
        this.sendBufferSize = $("input[name=sendbuffer]", this.fieldset).numberspinner({required: true, min: 64, max: 1024, increment: 64, value: 64, width: 80});

        this.useReceiveBuffer = $("input[name=usereceivebuffer]:checkbox", this.fieldset);
        this.useReceiveBuffer.change($.proxy(function() {
            var enabled = this.useReceiveBuffer.is(":checked");
            this.receiveBufferSize.numberspinner(enabled ? "enable" : "disable").numberspinner(enabled ? "enableValidation" : "disableValidation");
        }, this));
        this.receiveBufferSize = $("input[name=receivebuffer]", this.fieldset).numberspinner({required: true, min: 64, max: 1024, increment: 64, value: 64, width: 80});

        this.defaultTransferMode = $("input[name=transfermode]:radio", this.fieldset);
        this.dataConnectionMode = $("input[name=dataconnectionmode]:radio", this.fieldset);
        this.forceDataEncryption = $("input[name=forcedataencryption]:checkbox", this.fieldset);
        this.commandRequireClientCertificate = $("input[name=cmdrequireclientcrt]:checkbox", this.fieldset);
        this.dataRequireClientCertificate = $("input[name=datarequireclientcrt]:checkbox", this.fieldset);
        this.shutdownCommandSsl = $("input[name=shutdowncmdssl]:checkbox", this.fieldset);
        this.shutdownDataSsl = $("input[name=shutdowndatassl]:checkbox", this.fieldset);
        this.blockBounceAttack = $("input[name=blockbounce]:checkbox", this.fieldset);
        this.blockPasvAttack = $("input[name=blockpasv]:checkbox", this.fieldset);
        this.tcpNoDelay = $("input[name=tcpnodelay]:checkbox", this.fieldset);

        this.networkCharset = $("select[name=networkcharset]", this.fieldset).combobox({required: true, editable: false, width: 140});
        this.fileCharset = $("select[name=filecharset]", this.fieldset).combobox({required: true, editable: false, width: 140});
        this.threatAsciiAsImage = $("input[name=asciiasimage]:checkbox", this.fieldset);
        this.threatAsciiAsImage.change($.proxy(function() {
            var enabled = !this.threatAsciiAsImage.is(":checked");
            this.fileCharset.combobox(enabled ? "enable" : "disable").combobox(enabled ? "enableValidation" : "disableValidation");
        }, this));

        this.ciphersButton = $("a[role=button][name=sslciphers]", this.fieldset).linkbutton({onClick: $.proxy(this._onClick$CiphersButton, 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)});
    },

    getBanner: function() {
        return this.banner.textbox("getValue").trim();
    },

    setBanner: function(value) {
        this.banner.textbox("setValue", value);
    },

    getTimeout: function() {
        return parseInt(this.timeout.numberspinner("getValue")) * this.TIMEOUT_FACTOR;
    },

    setTimeout: function(value) {
        this.timeout.numberspinner("setValue", parseInt(value) / this.TIMEOUT_FACTOR);
    },

    getDataTimeout: function() {
        return parseInt(this.dataTimeout.numberspinner("getValue")) * this.TIMEOUT_FACTOR;
    },

    setDataTimeout: function(value) {
        this.dataTimeout.numberspinner("setValue", parseInt(value) / this.TIMEOUT_FACTOR);
    },

    getPassiveIp: function() {
        return this.passiveIp.textbox("getValue").trim();
    },

    setPassiveIp: function(value) {
        this.passiveIp.textbox("setValue", value);
    },

    getPassivePortRange: function() {
        return this.usePortRange.is(":checked")
                ? {lowerBound: parseInt(this.portRangeStart.numberspinner("getValue")), upperBound: parseInt(this.portRangeEnd.numberspinner("getValue"))}
                : null;
    },

    setPassivePortRange: function(value) {
        if (value && value.lowerBound && value.upperBound) {
            this.usePortRange.prop("checked", true).change();
            this.portRangeEnd.numberspinner("setValue", parseInt(value.upperBound));
            this.portRangeStart.numberspinner("setValue", parseInt(value.lowerBound));
        } else {
            this.usePortRange.prop("checked", false).change();
        }
    },

    getSendBufferSize: function() {
        return this.useSendBuffer.is(":checked") ? parseInt(this.sendBufferSize.numberspinner("getValue")) * this.BUFFER_FACTOR : null;
    },

    setSendBufferSize: function(value) {
        this.useSendBuffer.prop("checked", value != null).change();
        if (value != null) {
            this.sendBufferSize.numberspinner("setValue", parseInt(value) / this.BUFFER_FACTOR);
        }
    },

    getReceiveBufferSize: function() {
        return this.useReceiveBuffer.is(":checked") ? parseInt(this.receiveBufferSize.numberspinner("getValue")) * this.BUFFER_FACTOR : null;
    },

    setReceiveBufferSize: function(value) {
        this.useReceiveBuffer.prop("checked", value != null).change();
        if (value != null) {
            this.receiveBufferSize.numberspinner("setValue", parseInt(value) / this.BUFFER_FACTOR);
        }
    },

    getDefaultTransferMode: function () {
        return this.defaultTransferMode.filter(":checked").val();
    },

    setDefaultTransferMode: function (value) {
        this.defaultTransferMode.filter("[value=" + value + "]").prop("checked", true);
    },

    getDataConnectionMode: function() {
        return this.dataConnectionMode.filter(":checked").val();
    },

    setDataConnectionMode: function(value) {
        this.dataConnectionMode.filter("[value=" + value + "]").prop("checked", true);
    },

    isForceDataEncryption: function() {
        return this.forceDataEncryption.is(":checked");
    },

    setForceDataEncryption: function(value) {
        this.forceDataEncryption.prop("checked", !!value);
    },

    isCommandRequireClientCertificate: function() {
        return this.commandRequireClientCertificate.is(":checked");
    },

    setCommandRequireClientCertificate: function(value) {
        this.commandRequireClientCertificate.prop("checked", !!value);
    },

    isDataRequireClientCertificate: function() {
        return this.dataRequireClientCertificate.is(":checked");
    },

    setDataRequireClientCertificate: function(value) {
        this.dataRequireClientCertificate.prop("checked", !!value);
    },

    isShutdownCommandSsl: function() {
        return this.shutdownCommandSsl.is(":checked");
    },

    setShutdownCommandSsl: function(value) {
        this.shutdownCommandSsl.prop("checked", !!value);
    },

    isShutdownDataSsl: function() {
        return this.shutdownDataSsl.is(":checked");
    },

    setShutdownDataSsl: function(value) {
        this.shutdownDataSsl.prop("checked", !!value);
    },

    isBlockBounceAttack: function() {
        return this.blockBounceAttack.is(":checked");
    },

    setBlockBounceAttack: function(value) {
        this.blockBounceAttack.prop("checked", !!value);
    },

    isBlockPasvAttack: function() {
        return this.blockPasvAttack.is(":checked");
    },

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

    getTcpNoDelay: function() {
        return this.tcpNoDelay.is(":checked");
    },

    setTcpNoDelay: function(value) {
        this.tcpNoDelay.prop("checked", !!value);
    },

    getNetworkCharset: function() {
        return this.networkCharset.combobox("getValue");
    },

    setNetworkCharset: function(value) {
        this.networkCharset.combobox("setValue", value || this.DEFAULT_CHARSET);
    },

    getFileCharset: function() {
        return this.threatAsciiAsImage.is(":checked") ? null : this.fileCharset.combobox("getValue");
    },

    setFileCharset: function(value) {
        this.threatAsciiAsImage.prop("checked", value == null).change();
        this.fileCharset.combobox("setValue", value != null ? value : this.DEFAULT_CHARSET);
    },

    show: function(listener) {
        this.listener = listener || jscape.domain.FtpConfigurationView.LISTENER;
        this._adjustPortRange();
    },

    _onClick$CiphersButton: function() {
        this.listener.onSslCiphers();                                   S
    },

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

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

    _adjustPortRange: function() {
        var range = this.getPassivePortRange();
        if (range != null) {
            function _validate(spinner, validType, validParams) {
                $(spinner).numberspinner("textbox").validatebox({validType: validType, validParams: validParams});
                return spinner.numberspinner("isValid");
            }
            _validate(this.portRangeStart, "in_range", [this.portRangeStart.numberspinner("options").min, range.upperBound]);
            _validate(this.portRangeEnd, "in_range", [range.lowerBound, this.portRangeEnd.numberspinner("options").max]);
        }
    }
});
jscape.domain.FtpConfigurationView.LISTENER = {
    onSslCiphers: $.noop,
    onApply: $.noop,
    onDiscard: $.noop
};

/** @class */
jscape.domain.SftpConfigurationController = Class.extend(
    /** @lends {jscape.domain.SftpConfigurationController.prototype} */
{
    DEFAULT_CONFIG: jscape.ServiceConfiguration.sftp(300000, "JSCAPE"),

    view: null,
    config: null,
    copy: null,
    algorithms: null,

    initialize: function() {
        this._initValidators();
    },

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

        this.algorithmsController = new jscape.domain.SftpAlgorithmsController();
    },

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

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

    onResume: function() {
        this.managementService.getServiceConfiguration(this.domainName, jscape.Service.Protocol.SFTP)
                .done($.proxy(function (config) { this.config = config || this.DEFAULT_CONFIG; }, this))
                .fail($.proxy(function () { this.config = this.DEFAULT_CONFIG; }, this))
                .always($.proxy(function () {
                            this.copy = this.config.clone();
                            this._initAlgorithms();
                            this._setupView(this.config);
                        }, this));
    },

    onApply: function() {
        var config = this._createConfiguration();
        return this.managementService.setServiceConfiguration(this.domainName, jscape.Service.Protocol.SFTP, config)
                .done($.proxy(function() {
                    this.config = config;
                    this.copy = this.config.clone();
                    this._initAlgorithms();
                    this._setupView(this.config);
                }, this))
                .done($.proxy(this._fireApplySuccess, this));
    },

    onDiscard: function() {
        this.config = this.copy;
        this.copy = this.config.clone();
        this._initAlgorithms();
        this._setupView(this.config);
    },

    onSftpAlgorithms: function() {
        this.algorithmsController.start(this.managementService, this.domainName, this.algorithms)
                .done($.proxy(function(algorithms) { this.algorithms = algorithms; }, this));
    },

    _initAlgorithms: function() {
        this.algorithms = this.config
                ? {kexes: this.config.supportedKexes, ciphers: this.config.supportedCiphers, macs: this.config.supportedMacs, compressions: this.config.supportedCompressions}
                : {};
    },

    _createConfiguration: function() {
        return jscape.ServiceConfiguration.sftp(this.view.getTimeout(),
                                                this.view.getVersion(),
                                                this.view.getStartupBanner(),
                                                this.view.getAuthenticationBanner(),
                                                this.view.getSendBufferSize(),
                                                this.view.getReceiveBufferSize(),
                                                this.view.getTcpNoDelay(),
                                                this.view.isDisableExpandedLongName(),
                                                this.algorithms.kexes,
                                                this.algorithms.ciphers,
                                                this.algorithms.macs,
                                                this.algorithms.compressions);
    },

    _setupView: function (config) {
        if (config && this.view) {
            this.view.setTimeout(config.timeout);
            this.view.setVersion(config.softwareVersion);
            this.view.setStartupBanner(config.startupBanner);
            this.view.setAuthenticationBanner(config.authBanner);
            this.view.setSendBufferSize(config.sendBufferSize);
            this.view.setReceiveBufferSize(config.receiveBufferSize);
            this.view.setTcpNoDelay(config.tcpNoDelayEnabled);
            this.view.setDisableExpandedLongName(config.disableRealPathExpandedLongName);
        }
    },

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

    _initValidators: function() {
        var v = new jscape.Validator();
        v.rule("sftp_software_version", function(val) { return /^[^\s]+$/gi.test(val); }, window.R.string.SERVICES_ERROR_BAD_SFTP_VERSION);
    }
});

/** @class */
jscape.domain.SftpConfigurationView = Class.extend(
    /** @lends {jscape.domain.SftpConfigurationView.prototype} */
{
    TIMEOUT_FACTOR: 60 * 1000,
    BUFFER_FACTOR: 1024,

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

        this.version = $("input[name=version]", this.fieldset).textbox({width: "70%", validType: "sftp_software_version"});
        this.startupBanner = $("textarea[name=startupbanner]", this.fieldset).textbox({multiline: true, width: "70%", height: 90});
        this.authBanner = $("textarea[name=authbanner]", this.fieldset).textbox({multiline: true, width: "70%", height: 90});

        this.timeout = $("input[name=timeout]", this.fieldset).numberspinner({required: true, min: 0, max: 999, value: 5, width: 80});

        this.useSendBuffer = $("input[name=usesendbuffer]:checkbox", this.fieldset);
        this.useSendBuffer.change($.proxy(function() {
            var enabled = this.useSendBuffer.is(":checked");
            this.sendBufferSize.numberspinner(enabled ? "enable" : "disable").numberspinner(enabled ? "enableValidation" : "disableValidation");
        }, this));
        this.sendBufferSize = $("input[name=sendbuffer]", this.fieldset).numberspinner({required: true, min: 64, max: 1024, increment: 64, value: 64, width: 80});

        this.useReceiveBuffer = $("input[name=usereceivebuffer]:checkbox", this.fieldset);
        this.useReceiveBuffer.change($.proxy(function() {
            var enabled = this.useReceiveBuffer.is(":checked");
            this.receiveBufferSize.numberspinner(enabled ? "enable" : "disable").numberspinner(enabled ? "enableValidation" : "disableValidation");
        }, this));
        this.receiveBufferSize = $("input[name=receivebuffer]", this.fieldset).numberspinner({required: true, min: 64, max: 1024, increment: 64, value: 64, width: 80});

        this.tcpNoDelay = $("input[name=tcpnodelay]:checkbox", this.fieldset);
        this.disableLongName = $("input[name=disablelongname]:checkbox", this.fieldset);

        this.algorithmsButton = $("a[role=button][name=algorithms]", this.fieldset).linkbutton({onClick: $.proxy(this._onClick$AlgorithmsButton, 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)});
    },

    getTimeout: function() {
        return parseInt(this.timeout.numberspinner("getValue")) * this.TIMEOUT_FACTOR;
    },

    setTimeout: function(value) {
        this.timeout.numberspinner("setValue", parseInt(value) / this.TIMEOUT_FACTOR);
    },

    getVersion: function() {
        return this.version.textbox("getValue").trim();
    },

    setVersion: function(value) {
        this.version.textbox("setValue", value);
    },

    getStartupBanner: function() {
        return this.startupBanner.textbox("getValue");
    },

    setStartupBanner: function(value) {
        this.startupBanner.textbox("setValue", value);
    },

    getAuthenticationBanner: function() {
        return this.authBanner.textbox("getValue");
    },

    setAuthenticationBanner: function(value) {
        this.authBanner.textbox("setValue", value);
    },

    getSendBufferSize: function() {
        return this.useSendBuffer.is(":checked") ? parseInt(this.sendBufferSize.numberspinner("getValue")) * this.BUFFER_FACTOR : null;
    },

    setSendBufferSize: function(value) {
        this.useSendBuffer.prop("checked", value != null).change();
        if (value != null) {
            this.sendBufferSize.numberspinner("setValue", parseInt(value) / this.BUFFER_FACTOR);
        }
    },

    getReceiveBufferSize: function() {
        return this.useReceiveBuffer.is(":checked") ? parseInt(this.receiveBufferSize.numberspinner("getValue")) * this.BUFFER_FACTOR : null;
    },

    setReceiveBufferSize: function(value) {
        this.useReceiveBuffer.prop("checked", value != null).change();
        if (value != null) {
            this.receiveBufferSize.numberspinner("setValue", parseInt(value) / this.BUFFER_FACTOR);
        }
    },

    getTcpNoDelay: function() {
        return this.tcpNoDelay.is(":checked");
    },

    setTcpNoDelay: function(value) {
        this.tcpNoDelay.prop("checked", !!value);
    },

    isDisableExpandedLongName: function() {
        return this.disableLongName.is(":checked");
    },

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

    show: function(listener) {
        this.listener = listener || jscape.domain.SftpConfigurationView.LISTENER;
    },

    _onClick$AlgorithmsButton: function() {
        this.listener.onSftpAlgorithms();
    },

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

    _onClick$DiscardButton: function() {
        this.listener.onDiscard();
    }
});
jscape.domain.SftpConfigurationView.LISTENER = {
    onSftpAlgorithms: $.noop,
    onApply: $.noop,
    onDiscard: $.noop
};

/** @class */
jscape.domain.AftpConfigurationController = Class.extend(
    /** @lends {jscape.domain.AftpConfigurationController.prototype} */
{
    DEFAULT_CONFIG: jscape.ServiceConfiguration.aftp(300000, 60000, true, 10),

    view: null,
    config: null,
    copy: null,
    sslCiphers: null,

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

        this.ciphersController = new jscape.domain.SslCiphersController();
    },

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

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

    onResume: function() {
        this.managementService.getServiceConfiguration(this.domainName, jscape.Service.Protocol.AFTP)
                .done($.proxy(function (config) { this.config = config || this.DEFAULT_CONFIG; }, this))
                .fail($.proxy(function () { this.config = this.DEFAULT_CONFIG; }, this))
                .always($.proxy(function () {
                            this.copy = this.config.clone();
                            this.sslCiphers = this.config.cipherSuites || null;
                            this._setupView(this.config);
                        }, this));
    },

    onApply: function() {
        var config = this._createConfiguration();
        return this.managementService.setServiceConfiguration(this.domainName, jscape.Service.Protocol.AFTP, config)
                .done($.proxy(function() {
                    this.config = config;
                    this.copy = this.config.clone();
                    this._setupView(this.config);
                }, this))
                .done($.proxy(this._fireApplySuccess, this));
    },

    onDiscard: function() {
        this.config = this.copy;
        this.copy = this.config.clone();
        this.sslCiphers = this.config && this.config.cipherSuites || null;
        this._setupView(this.config);
    },

    onSslCiphers: function() {
        this.ciphersController.start(this.managementService, this.domainName, this.sslCiphers)
                .done($.proxy(function(ciphers) { this.sslCiphers = ciphers; }, this));
    },

    _createConfiguration: function() {
        return jscape.ServiceConfiguration.aftp(this.view.getTimeout(),
                                                this.view.getDataTimeout(),
                                                this.view.getTcpNoDelay(),
                                                this.view.getMaxLossListSize(),
                                                this.sslCiphers);
    },

    _setupView: function(config) {
        if (config && this.view) {
            this.view.setTimeout(config.timeout);
            this.view.setDataTimeout(config.dataTimeout);
            this.view.setTcpNoDelay(config.tcpNoDelayEnabled);
            this.view.setMaxLossListSize(config.maxLossListSize);
        }
    },

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

/** @class */
jscape.domain.AftpConfigurationView = Class.extend(
    /** @lends {jscape.domain.AftpConfigurationView.prototype} */
{
    TIMEOUT_FACTOR: 60 * 1000,

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

        this.timeout = $("input[name=cmdtimeout]", this.fieldset).numberspinner({required: true, min: 0, max: 999, value: 5, width: 80});
        this.dataTimeout = $("input[name=datatimeout]", this.fieldset).numberspinner({required: true, min: 0, max: 999, value: 5, width: 80});
        this.tcpNoDelay = $("input[name=tcpnodelay]:checkbox", this.fieldset);
        this.lossListSize = $("input[name=losslistsize]", this.fieldset).numberspinner({required: true, min: 1, max: 99, value: 10, width: 60});

        this.ciphersButton = $("a[role=button][name=sslciphers]", this.fieldset).linkbutton({onClick: $.proxy(this._onClick$CiphersButton, 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)});
    },

    getTimeout: function() {
        return parseInt(this.timeout.numberspinner("getValue")) * this.TIMEOUT_FACTOR;
    },

    setTimeout: function(value) {
        this.timeout.numberspinner("setValue", parseInt(value) / this.TIMEOUT_FACTOR);
    },

    getDataTimeout: function() {
        return parseInt(this.dataTimeout.numberspinner("getValue")) * this.TIMEOUT_FACTOR;
    },

    setDataTimeout: function(value) {
        this.dataTimeout.numberspinner("setValue", parseInt(value) / this.TIMEOUT_FACTOR);
    },

    getTcpNoDelay: function() {
        return this.tcpNoDelay.is(":checked");
    },

    setTcpNoDelay: function(value) {
        this.tcpNoDelay.prop("checked", !!value);
    },

    getMaxLossListSize: function() {
        return parseInt(this.lossListSize.numberspinner("getValue"));
    },

    setMaxLossListSize: function(value) {
        this.lossListSize.numberspinner("setValue", parseInt(value));
    },

    show: function(listener) {
        this.listener = listener || jscape.domain.AftpConfigurationView.LISTENER;
    },

    _onClick$CiphersButton: function() {
        this.listener.onSslCiphers();
    },

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

    _onClick$DiscardButton: function() {
        this.listener.onDiscard();
    }
});
jscape.domain.AftpConfigurationView.LISTENER = {
    onSslCiphers: $.noop,
    onApply: $.noop,
    onDiscard: $.noop
};

/** @class */
jscape.domain.OftpConfigurationController = Class.extend(
    /** @lends {jscape.domain.OftpConfigurationController.prototype} */
{
    DEFAULT_CONFIG: jscape.ServiceConfiguration.oftp(30 * 1000, 4096, 10),

    view: null,
    config: null,
    copy: null,
    sslCiphers: null,

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

        this.ciphersController = new jscape.domain.SslCiphersController();
    },

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

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

    onResume: function() {
        this.managementService.getServiceConfiguration(this.domainName, jscape.Service.Protocol.OFTP)
                .done($.proxy(function(config) { this.config = config || this.DEFAULT_CONFIG; }, this))
                .fail($.proxy(function() { this.config = this.DEFAULT_CONFIG; }, this))
                .always($.proxy(function() {
                            this.copy = this.config.clone();
                            this.sslCiphers = this.config.cipherSuites || null;
                            this._setupView(this.config);
                        }, this));
    },

    onApply: function() {
        var config = this._createConfiguration();
        return this.managementService.setServiceConfiguration(this.domainName, jscape.Service.Protocol.OFTP, config)
                .done($.proxy(function() {
                    this.config = config;
                    this.copy = this.config.clone();
                    this._setupView(this.config);
                }, this))
                .done($.proxy(this._fireApplySuccess, this));
    },

    onDiscard: function() {
        this.config = this.copy;
        this.copy = this.config.clone();
        this.sslCiphers = this.config && this.config.cipherSuites || null;
        this._setupView(this.config);
    },

    onSslCiphers: function() {
        this.ciphersController.start(this.managementService, this.domainName, this.sslCiphers)
                .done($.proxy(function(ciphers) { this.sslCiphers = ciphers; }, this));
    },

    _createConfiguration: function() {
        return jscape.ServiceConfiguration.oftp(this.view.getTimeout(),
                                                this.view.getMaxDataBufferSize(),
                                                this.view.getMaxCredit(),
                                                this.sslCiphers,
                                                this.config.enabledProtocols);
    },

    _setupView: function(config) {
        if (config && this.view) {
            this.view.setTimeout(config.timeout);
            this.view.setMaxDataBufferSize(config.maxDataExchangeBufferSize);
            this.view.setMaxCredit(config.maxCredit);
        }
    },

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

/** @class */
jscape.domain.OftpConfigurationView = Class.extend(
    /** @lends {jscape.domain.OftpConfigurationView.prototype} */
{
    TIMEOUT_FACTOR: 1000,

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

        this.timeout = $("input[name=timeout]", this.fieldset).numberspinner({required: true, min: 0, max: 999, width: 80});
        this.dataBuffer = $("input[name=buffer]", this.fieldset).numberspinner({required: true, min: 128, max: 99999, increment: 10, width: 100});
        this.credit = $("input[name=credit]", this.fieldset).numberspinner({required: true, min: 1, max: 999, width: 80});

        this.ciphersButton = $("a[role=button][name=sslciphers]", this.fieldset).linkbutton({onClick: $.proxy(this._onClick$CiphersButton, 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)});
    },

    getTimeout: function() {
        return parseInt(this.timeout.numberspinner("getValue")) * this.TIMEOUT_FACTOR;
    },

    setTimeout: function(value) {
        this.timeout.numberspinner("setValue", parseInt(value) / this.TIMEOUT_FACTOR).numberspinner("validate");
    },

    getMaxDataBufferSize: function() {
        return parseInt(this.dataBuffer.numberspinner("getValue"));
    },

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

    getMaxCredit: function() {
        return parseInt(this.credit.numberspinner("getValue"));
    },

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

    show: function(listener) {
        this.listener = listener || jscape.domain.OftpConfigurationView.LISTENER;
    },

    _onClick$CiphersButton: function () {
        this.listener.onSslCiphers();
    },

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

    _onClick$DiscardButton: function() {
        this.listener.onDiscard();
    }
});
jscape.domain.OftpConfigurationView.LISTENER = {
    onSslCiphers: $.noop,
    onApply: $.noop,
    onDiscard: $.noop
};

/** @class */
jscape.domain.TftpConfigurationController = Class.extend(
    /** @lends {jscape.domain.TftpConfigurationController.prototype} */
{
    DEFAULT_CONFIG: jscape.ServiceConfiguration.tftp(6, 3000, true, true),

    view: null,
    config: null,

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

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

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

    onResume: function() {
        this.managementService.getServiceConfiguration(this.domainName, jscape.Service.Protocol.TFTP)
                .done($.proxy(function(config) { this.config = config || this.DEFAULT_CONFIG.clone(); }, this))
                .fail($.proxy(function() { this.config = this.DEFAULT_CONFIG.clone(); }, this))
                .always($.proxy(function() { this._setupView(this.config); }, this));
    },

    onApply: function() {
        var config = this._createConfiguration();
        return this.managementService.setServiceConfiguration(this.domainName, jscape.Service.Protocol.TFTP, config)
                .done($.proxy(function() {
                    this.config = config.clone();
                    this._setupView(config);
                }, this))
                .done($.proxy(this._fireApplySuccess, this));
    },

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

    _createConfiguration: function() {
        return jscape.ServiceConfiguration.tftp(this.view.getMaxRetransmitAttempts(),
                                                this.view.getRetransmitInterval(),
                                                this.view.isDirectoryListingGenerationEnabled(),
                                                this.view.isFileHashGenerationEnabled());
    },

    _setupView: function(config) {
        if (config && this.view) {
            this.view.setMaxRetransmitAttempts(config.maxRetransmitAttempts);
            this.view.setRetransmitInterval(config.retransmitInterval);
            this.view.setDirectoryListingGenerationEnabled(config.directoryListingGenerationEnabled);
            this.view.setFileHashGenerationEnabled(config.fileHashGenerationEnabled);
        }
    },

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

/** @class */
jscape.domain.TftpConfigurationView = Class.extend(
    /** @lends {jscape.domain.TftpConfigurationView.prototype} */
{
    TIME_FACTOR: 1000,

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

        this.retransmitAttempts = $("input[name=retransmitattempts]", this.fieldset).numberspinner({required: true, min: 0, max: 100, width: 80});
        this.retransmitInterval = $("input[name=retransmitinterval]", this.fieldset).numberspinner({required: true, min: 1, max: 255, width: 80});
        this.dirListingGeneration = $("input[name=generatedirlisting]", this.fieldset);
        this.fileHashGeneration = $("input[name=generatefilehash]", 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)});
    },

    getMaxRetransmitAttempts: function() {
        return parseInt(this.retransmitAttempts.numberspinner("getValue"));
    },

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

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

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

    isDirectoryListingGenerationEnabled: function() {
        return this.dirListingGeneration.is(":checked");
    },

    setDirectoryListingGenerationEnabled: function(value) {
        this.dirListingGeneration.prop("checked", !!value);
    },

    isFileHashGenerationEnabled: function() {
        return this.fileHashGeneration.is(":checked");
    },

    setFileHashGenerationEnabled: function(value) {
        this.fileHashGeneration.prop("checked", !!value);
    },

    show: function(listener) {
        this.listener = listener || jscape.domain.TftpConfigurationView.LISTENER;
    },

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

    _onClick$DiscardButton: function() {
        this.listener.onDiscard();
    }
});
jscape.domain.TftpConfigurationView.LISTENER = {
    onApply: $.noop,
    onDiscard: $.noop
};

/** @class */
jscape.domain.HttpConfigurationController = Class.extend(
    /** @lends {jscape.domain.HttpConfigurationController.prototype} */
{
    DEFAULT_CONFIG: jscape.ServiceConfiguration.http("", "", 600000, "", null, null, false, true, true, true, true, true, true),

    view: null,
    config: null,
    languages: null,
    uploadForms: null,

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

        this.formsController = new jscape.domain.UploadFormsController();
        this.resourcesController = new jscape.domain.WebResourcesController();
    },

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

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

    onResume: function() {
        this.managementService.getServiceConfiguration(this.domainName, jscape.Service.Protocol.HTTP)
                .done($.proxy(function (config) { this.config = config || this.DEFAULT_CONFIG.clone(); }, this))
                .fail($.proxy(function () { this.config = this.DEFAULT_CONFIG.clone(); }, this))
                .always($.proxy(function () {
                            this.languages = this.config.languages;
                            this.uploadForms = this.config.uploadForms;
                            this._setupView(this.config);
                        }, this));
    },

    onApply: function() {
        var config = this._createConfiguration();
        return this.managementService.setServiceConfiguration(this.domainName, jscape.Service.Protocol.HTTP, config)
                .done($.proxy(function () {
                          this.config = config.clone();
                          this.languages = this.config.languages;
                          this.uploadForms = this.config.uploadForms;
                          this._fireApplySuccess();
                      }, this));
    },

    onDiscard: function() {
        var config = this.config;
        this.config = config.clone();
        this.languages = this.config.languages;
        this.uploadForms = this.config.uploadForms;
        this._setupView(this.config);
    },

    onSetupForms: function () {
        var forms = $.map(this.uploadForms, function (form) { return form.clone(); });
        this.managementService.getGroupNames(this.domainName)
                .always($.proxy(function (groupNames) {
                            this.formsController.start(forms, groupNames)
                                    .done($.proxy(function (values) {
                                              this.uploadForms = values;
                                          }, this));
                        }, this));
    },

    onSetupResources: function() {
        var copy = $.map(this.languages, function(lang) { return lang.clone(); });
        this.resourcesController.start(this.managementService, this.domainName, jscape.Service.Protocol.HTTP, copy)
                .done($.proxy(function(values) {
                    this.languages = values;
                }, this));
    },

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

    _createConfiguration: function() {
        var signupTemplate = this.view.getSelfRegistrationTemplate();
        return jscape.ServiceConfiguration.http(this.view.getTheme(),
                                                this.view.getLogoData(),
                                                this.view.getTimeout(),
                                                this.view.getLogoutUrl(),
                                                this.view.getAutoLogout(),
                                                new jscape.SelfRegistrationConfiguration(signupTemplate != null, signupTemplate),
                                                this.view.isAppletEnabled(),
                                                this.view.isDocumentViewerEnabled(),
                                                this.view.isAdHocTransferEnabled(),
                                                this.view.isShowTransferMode(),
                                                this.view.isShowLoginInfo(),
                                                this.view.isShowAccountLink(),
                                                this.view.isShowSearch(),
                                                this.uploadForms,
                                                this.view.isUploadFormRequired(),
                                                this.languages,
                                                this.view.getAftpNatHost());
    },

    _setupView: function(config) {
        if (config && this.view) {
            this.view.setTheme(config.theme);
            this.view.setLogoData(config.logoData);
            this.view.setTimeout(config.timeout);
            this.view.setLogoutUrl(config.logoutUrl);
            this.view.setAutoLogout(config.autoLogout);
            this.view.setAppletEnabled(config.appletEnabled);
            this.view.setDocumentViewerEnabled(config.documentViewerEnabled);
            this.view.setAdHocTransferEnabled(config.adHocTransferEnabled);
            this.view.setShowTransferMode(config.showTransferType);
            this.view.setShowLoginInfo(config.showLoginInfo);
            this.view.setShowAccountLink(config.showAccountLink);
            this.view.setShowSearch(config.showSearch);
            this.view.setAftpNatHost(config.aftpNatHost);
            this.view.setUploadFormRequired(config.uploadFormRequired);
        }
        this.managementService.getAccountTemplateNames(this.domainName)
                .done($.proxy(function (templates) {
                          this.view.setSelfRegistrationTemplates(templates.sort());
                          if (config) {
                              this.view.setSelfRegistrationTemplate(config.selfRegistration && config.selfRegistration.enabled
                                                                    ? config.selfRegistration.accountTemplate
                                                                    : null);
                          }
                      }, this));
    },

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

/** @class */
jscape.domain.HttpConfigurationView = Class.extend(
    /** @lends {jscape.domain.HttpConfigurationView.prototype} */
{
    DATA_URL: {pattern: /data:image\/.*;base64,(.+)/, template: "data:{0};base64,{1}", placeholder: "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"},
    DEFAULT_TEMPLATE_NAME: "Default",
    TIMEOUT_FACTOR: 60 * 1000,
    GRACE_PERIOD_FACTOR: 1000,

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

        this.theme = $("select[name=theme]", this.fieldset).combobox({required: false, editable: false, panelHeight: "auto", width: "20%"});

        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.logoutUrl = $("input[name=logouturl]", this.fieldset).textbox({required: false, width: "50%"});

        this.timeout = $("input[name=timeout]", this.fieldset).numberspinner({required: true, min: 1, max: 180, width: 70});

        this.autoLogoutEnabled = $("input[name=autologout]:checkbox", this.fieldset);
        this.autoLogoutEnabled.change($.proxy(function() {
            var enabled = this.autoLogoutEnabled.is(":checked");
            $.each([this.autoLogoutTimeout, this.autoLogoutGracePeriod], function(_, input) {
                input.numberspinner(enabled ? "enable" : "disable").numberspinner(enabled ? "enableValidation" : "disableValidation");
            })
        }, this));
        this.autoLogoutTimeout = $("input[name=autologouttimeout]", this.fieldset).numberspinner({required: true, min: 1, max: 180, value: 1, width: 70});
        this.autoLogoutGracePeriod = $("input[name=autologoutgraceperiod]", this.fieldset).numberspinner({required: true, min: 10, max: 600, value: 10, increment: 10, width: 70});

        this.signupEnabled = $("input[name=signupallowed]:checkbox", this.fieldset).prop("disabled", true);
        this.signupEnabled.change($.proxy(function() {
            var enabled = this.signupEnabled.is(":checked");
            this.signupAccountTemplate.combobox(enabled ? "enable" : "disable").combobox(enabled ? "enableValidation" : "disableValidation");
        }, this));
        this.signupAccountTemplate = $("select[name=signuptemplate]", this.fieldset);
        this.signupAccountTemplate.combobox({
            required: true,
            editable: true,
            limitToList: true,
            disabled: true,
            panelHeight: "auto",
            onLoadSuccess: $.proxy(function (data) {
                if (data.length) {
                    this.signupEnabled.prop("disabled", false);
                    this.signupAccountTemplate.combobox("select", this.DEFAULT_TEMPLATE_NAME).combobox("resize", 170);
                } else {
                    this.signupEnabled.prop("disabled", true);
                }
            }, this)
        });

        this.appletEnabled = $("input[name=appletallowed]:checkbox", this.fieldset);
        this.docViewerEnabled = $("input[name=docviewerallowed]:checkbox", this.fieldset);
        this.adHocTransferEnabled = $("input[name=adhoctransferallowed]:checkbox", this.fieldset);
        this.showLogin = $("input[name=showlogin]:checkbox", this.fieldset);
        this.showSearch = $("input[name=showsearch]:checkbox", this.fieldset);
        this.showTransferMode = $("input[name=showtransfermode]:checkbox", this.fieldset);
        this.showAccount = $("input[name=showaccount]:checkbox", this.fieldset);

        this.aftpNatHost = $("input[name=aftpnathost]", this.fieldset).textbox({width: "50%"});

        this.resourcesButton = $("a[role=button][name=resources]", this.fieldset).linkbutton({onClick: $.proxy(this._onClick$ResourcesButton, this)});
        this.uploadFormsButton = $("a[role=button][name=uploadforms]", this.fieldset).linkbutton({onClick: $.proxy(this._onClick$FormsButton, this)});
        this.uploadFormRequired = $("input[name=uploadformrequired]: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)});
    },

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

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

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

    getTimeout: function() {
        return parseInt(this.timeout.numberspinner("getValue")) * this.TIMEOUT_FACTOR;
    },

    setTimeout: function(value) {
        this.timeout.numberspinner("setValue", parseInt(value) / this.TIMEOUT_FACTOR);
    },

    getLogoutUrl: function() {
        return this.logoutUrl.textbox("getValue");
    },

    setLogoutUrl: function(value) {
        this.logoutUrl.textbox("setValue", value);
    },

    getAutoLogout: function() {
        return this.autoLogoutEnabled.is(":checked")
                ? {timeout: parseInt(this.autoLogoutTimeout.numberspinner("getValue")) * this.TIMEOUT_FACTOR, gracePeriod: parseInt(this.autoLogoutGracePeriod.numberspinner("getValue")) * this.GRACE_PERIOD_FACTOR}
                : null;
    },

    setAutoLogout: function(value) {
        if (value && value.timeout) {
            this.autoLogoutEnabled.prop("checked", true).change();
            this.autoLogoutTimeout.numberspinner("setValue", parseInt(value.timeout) / this.TIMEOUT_FACTOR).numberspinner("isValid");
            this.autoLogoutGracePeriod.numberspinner("setValue", parseInt(value.gracePeriod) / this.GRACE_PERIOD_FACTOR).numberspinner("isValid");
        } else {
            this.autoLogoutEnabled.prop("checked", false).change();
        }
    },

    getSelfRegistrationTemplate: function() {
        return this.signupEnabled.is(":checked") ? this.signupAccountTemplate.combobox("getValue") : null;
    },

    setSelfRegistrationTemplate: function(value) {
        this.signupEnabled.prop("checked", value != null).change();
        if (value != null) {
            this.signupAccountTemplate.combobox("select", value);
        }
    },

    setSelfRegistrationTemplates: function(values) {
        this.signupAccountTemplate.combobox("loadData", values);
    },

    isAppletEnabled: function() {
        return this.appletEnabled.is(":checked");
    },

    setAppletEnabled: function(value) {
        this.appletEnabled.prop("checked", !!value);
    },

    isDocumentViewerEnabled: function() {
        return this.docViewerEnabled.is(":checked");
    },

    setDocumentViewerEnabled: function(value) {
        this.docViewerEnabled.prop("checked", !!value);
    },

    isAdHocTransferEnabled: function() {
        return this.adHocTransferEnabled.is(":checked");
    },

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

    isShowTransferMode: function() {
        return this.showTransferMode.is(":checked");
    },
    setShowTransferMode: function(value) {
        this.showTransferMode.prop("checked", !!value);
    },

    isShowSearch: function() {
        return this.showSearch.is(":checked");
    },

    setShowSearch: function(value) {
        this.showSearch.prop("checked", !!value);
    },

    isShowLoginInfo: function() {
        return this.showLogin.is(":checked");
    },

    setShowLoginInfo: function(value) {
        this.showLogin.prop("checked", !!value);
    },

    isShowAccountLink: function() {
        return this.showAccount.is(":checked");
    },

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

    getAftpNatHost: function() {
        return this.aftpNatHost.textbox("getValue").trim();
    },

    setAftpNatHost: function(value) {
        this.aftpNatHost.textbox("setValue", value);
    },

    isUploadFormRequired: function() {
        return this.uploadFormRequired.is(":checked");
    },

    setUploadFormRequired: function(value) {
        this.uploadFormRequired.prop("checked", !!value);
    },

    show: function(listener) {
        this.listener = listener || jscape.domain.HttpConfigurationView.LISTENER;
        this.fieldset.form("validate");
    },


    _onClick$FormsButton: function() {
        this.listener.onSetupForms();
    },

    _onClick$ResourcesButton: function() {
        this.listener.onSetupResources();
    },

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

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

    _onClick$DiscardButton: function() {
        this.listener.onDiscard();
    }
});
jscape.domain.HttpConfigurationView.LISTENER = {
    onSetupForms: $.noop,
    onSetupResources: $.noop,
    onChangeLogo: $.noop,
    onApply: $.noop,
    onDiscard: $.noop
};

/** @class */
jscape.domain.WebDavConfigurationController = Class.extend(
    /** @lends {jscape.domain.WebDavConfigurationController.prototype} */
{
    DEFAULT_CONFIG: jscape.ServiceConfiguration.webdav("", "", "", true, false),

    view: null,
    config: null,
    languages: null,

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

        this.resourcesController = new jscape.domain.WebResourcesController();
    },

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

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

    onResume: function () {
        this.managementService.getServiceConfiguration(this.domainName, jscape.Service.Protocol.WEBDAV)
                .done($.proxy(function (config) { this.config = config || this.DEFAULT_CONFIG.clone(); }, this))
                .fail($.proxy(function () { this.config = this.DEFAULT_CONFIG.clone(); }, this))
                .always($.proxy(function () {
                            this.languages = this.config.languages;
                            this._setupView(this.config);
                        }, this));
    },

    onApply: function () {
        var config = this._createConfiguration();
        return this.managementService.setServiceConfiguration(this.domainName, jscape.Service.Protocol.WEBDAV, config)
                .done($.proxy(function () {
                          this.config = config.clone();
                          this.languages = this.config.languages;
                          this._fireApplySuccess();
                      }, this));
    },

    onDiscard: function() {
        var config = this.config;
        this.config = config.clone();
        this.languages = this.config.languages;
        this._setupView(this.config);
    },

    onSetupResources: function() {
        var copy = $.map(this.languages, function(entry) { return entry.clone(); });
        this.resourcesController.start(this.managementService, this.domainName, jscape.Service.Protocol.WEBDAV, copy)
                .done($.proxy(function(values) {
                    this.languages = values;
                }, this));
    },

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

    _createConfiguration: function() {
        return jscape.ServiceConfiguration.webdav(this.view.getTheme(),
                                                  this.view.getLogoData(),
                                                  this.view.getLogoutUrl(),
                                                  this.view.isShowLoginInfo(),
                                                  this.view.isShowAccountLink(),
                                                  this.languages);
    },

    _setupView: function(config) {
        if (config) {
            this.view.setTheme(config.theme);
            this.view.setLogoData(config.logoData);
            this.view.setLogoutUrl(config.logoutUrl);
            this.view.setShowLoginInfo(config.showLoginInfo);
            this.view.setShowAccountLink(config.showAccountLink);
        }
    },

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

/** @class */
jscape.domain.WebDavConfigurationView = Class.extend(
    /** @lends {jscape.domain.WebDavConfigurationView.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=webdavconfigfields]");

        this.theme = $("select[name=theme]", this.fieldset).combobox({required: false, editable: false, panelHeight: "auto", width: "20%"});

        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.logoutUrl = $("input[name=logouturl]", this.fieldset).textbox({required: false, width: "50%"});

        this.showLogin = $("input[name=showlogin]:checkbox", this.fieldset);
        this.showAccount = $("input[name=showaccount]:checkbox", this.fieldset);

        this.resourcesButton = $("a[role=button][name=resources]", this.fieldset).linkbutton({onClick: $.proxy(this._onClick$ResourcesButton, 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)});
    },

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

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

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

    getLogoutUrl: function() {
        return this.logoutUrl.textbox("getValue");
    },

    setLogoutUrl: function(value) {
        this.logoutUrl.textbox("setValue", value);
    },

    isShowLoginInfo: function() {
        return this.showLogin.is(":checked");
    },

    setShowLoginInfo: function(value) {
        this.showLogin.prop("checked", !!value);
    },

    isShowAccountLink: function() {
        return this.showAccount.is(":checked");
    },

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

    show: function(listener) {
        this.listener = listener || jscape.domain.WebDavConfigurationView.LISTENER;
    },

    _onClick$ResourcesButton: function() {
        this.listener.onSetupResources();
    },

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

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

    _onClick$DiscardButton: function() {
        this.listener.onDiscard();
    }
});
jscape.domain.WebDavConfigurationView.LISTENER = {
    onSetupResources: $.noop,
    onChangeLogo: $.noop,
    onApply: $.noop,
    onDiscard: $.noop
};

/** @class */
jscape.domain.SslCiphersController = Class.extend(
    /** @lends {jscape.domain.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, domainName, ciphers) {
        this.managementService = managementService;
        this.domainName = domainName;
        this.deferred = $.Deferred();

        this._setupDialog(ciphers).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 ciphers = dialog.getCiphers();
        dialog.destroy();
        this.deferred.resolve(ciphers);
    },

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

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

/** @class */
jscape.domain.SslCiphersDialog = Class.extend(
    /** @lends {jscape.domain.SslCiphersDialog.prototype} */
{
    /** @constructor */
    initialize: function() {
        this.dialog = $("#d-services-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", disabled: this.dialog.find("fieldset:first").is(":disabled"), 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.domain.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.domain.SslCiphersDialog.LISTENER = {
    onSelectMedium: $.noop,
    onSelectStrong: $.noop,
    onSubmit: $.noop,
    onCancel: $.noop
};

/** @class */
jscape.domain.SftpAlgorithmsController = Class.extend(
    /** @lends {jscape.domain.SftpAlgorithmsController.prototype} */
{
    /** @const */
    DEFAULT_ALGORITHMS: {kexes: [], ciphers: [], macs: [], compressions: []},

    deferred: null,

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

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

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

    _createAlgorithms: function(dialog) {
        return {
            kexes: dialog.getKexes(),
            ciphers: dialog.getCiphers(),
            macs: dialog.getMacs(),
            compressions: dialog.getCompressions()
        };
    },

    _setupDialog: function (algorithms) {
        var dialog = new jscape.domain.SftpAlgorithmsDialog();
        $.when(this.managementService.getServerParameters(),
               this.managementService.getDomainStatistics(this.domainName))
                .done(function (params, stats) {
                          var fipsModeEnabled = stats && stats.fipsModeEnabled;
                          dialog.setSshKexes(params.sshKexes);
                          dialog.setKexes(algorithms.kexes);
                          dialog.setSshCiphers(fipsModeEnabled ? params.sshFipsCiphers : params.sshCiphers);
                          dialog.setCiphers(algorithms.ciphers);
                          dialog.setSshMacs(fipsModeEnabled ? params.sshFipsMacs : params.sshMacs);
                          dialog.setMacs(algorithms.macs);
                          dialog.setSshCompressions(params.sshCompressions);
                          dialog.setCompressions(algorithms.compressions);
                      });
        return dialog;
    }
});

/** @class */
jscape.domain.SftpAlgorithmsDialog = Class.extend(
    /** @lends {jscape.domain.SftpAlgorithmsDialog.prototype} */
{
    /** @constructor */
    initialize: function() {
        this.dialog = $("#d-services-sftpalgorithms").clone().attr("id", "");
        this.dialog.dialog({
            width: 630, height: "auto",
            modal: true, resizable: false, closable: true, closed: true,
            buttons: [
                {text: window.R.string.DIALOG_BUTTON_OK || "Ok", disabled: this.dialog.find("fieldset:first").is(":disabled"), 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=sftpalgorithmsfields]", this.dialog);
        this.tabs = $("[role=tablist]", this.fieldset).tabs({plain: true, width: "100%", height: 270});

        this.kexes = $("table[role=grid][aria-label=kexes]", this.fieldset).datagrid({
            fit: true,
            fitColumns: true,
            showHeader: false,
            border: false,
            remoteSort: false,
            singleSelect: false,
            selectOnCheck: true,
            checkOnSelect: true,
            idField: "value",
            columns: [[{field: "value", checkbox: true}, {field: "text", formatter: function(_, row) { return row.value; }}]]
        });
        this.ciphers = $("table[role=grid][aria-label=ciphers]", this.fieldset).datagrid({
            fit: true,
            fitColumns: true,
            border: false,
            showHeader: false,
            remoteSort: false,
            singleSelect: false,
            selectOnCheck: true,
            checkOnSelect: true,
            idField: "value",
            columns: [[{field: "value", checkbox: true}, {field: "text", formatter: function(_, row) { return row.value; }}]]
        });
        this.macs = $("table[role=grid][aria-label=macs]", this.fieldset).datagrid({
            fit: true,
            fitColumns: true,
            border: false,
            showHeader: false,
            remoteSort: false,
            singleSelect: false,
            selectOnCheck: true,
            checkOnSelect: true,
            idField: "value",
            columns: [[{field: "value", checkbox: true}, {field: "text", formatter: function(_, row) { return row.value; }}]]
        });
        this.compressions = $("table[role=grid][aria-label=compressions]", this.fieldset).datagrid({
            fit: true,
            fitColumns: true,
            border: false,
            remoteSort: false,
            showHeader: false,
            singleSelect: false,
            selectOnCheck: true,
            checkOnSelect: true,
            idField: "value",
            columns: [[{field: "value", checkbox: true}, {field: "text", formatter: function(_, row) { return row.value; }}]]
        });
    },

    getKexes: function() {
        return this._getAlgorithms(this.kexes);
    },

    setKexes: function (values) {
        this._setAlgorithms(this.kexes, values);
    },

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

    getCiphers: function() {
        return this._getAlgorithms(this.ciphers);
    },

    setCiphers: function (values) {
        this._setAlgorithms(this.ciphers, values);
    },

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

    getMacs: function() {
        return this._getAlgorithms(this.macs);
    },

    setMacs: function (values) {
        this._setAlgorithms(this.macs, values);
    },

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

    getCompressions: function() {
        return this._getAlgorithms(this.compressions);
    },

    setCompressions: function (values) {
        this._setAlgorithms(this.compressions, values);
    },

    setSshCompressions: function(values) {
        this.compressions.datagrid("loadData", $.map(values, function(value) { return {text: value, value: 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.fieldset.form("disableValidation");
            this.closing = false;
        }
    },

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

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

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

    _closed: function () {
        return !!this.dialog.dialog("options").closed;
    },

    _getAlgorithms: function(grid) {
        return $.map(grid.datagrid("getChecked"), function(row) { return row.value; });
    },

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

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

    start: function(managementService, domainName, protocol, languages) {
        this.deferred = $.Deferred();
        this.managementService = managementService;
        this.domainName = domainName;
        this.protocol = protocol;
        this.languages = languages || [];

        this._setupDialog(this.languages).show(this);

        return this.deferred.promise();
    },

    onAddLanguage: function(dialog) {
        var addLangDialog = new jscape.domain.AddLanguageDialog();
        addLangDialog.disableLanguages($.map(this.languages, function(entry) { return entry.lang; }));
        addLangDialog.show({
            onSubmit: $.proxy(function(d) {
                var lang = d.getLanguage();
                var displayName = d.getDisplayName();
                d.destroy();
                var language = this._createWebResources(lang, displayName);
                this.languages.push(language);
                dialog.setLanguages(this.languages);
                dialog.selectLanguage(language);
            }, this),
            onCancel: function(d) { d.destroy(); }
        });
    },

    onResetToDefault: function(dialog) {
        this.managementService.getServiceWebResources(this.domainName, this.protocol)
                .done($.proxy(function (languages) {
                          this.languages = languages;
                          dialog.setLanguages(this.languages);
                      }, this));
    },

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

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

    _createWebResources: function(language, displayName) {
        var defaultWebResources = $.grep(this.languages, function(item) { return item.isDefault(); });
        var properties = defaultWebResources.length ? $.extend({}, defaultWebResources[0].properties) : {};
        return new jscape.WebResources(language, displayName, properties);
    },

    _setupDialog: function(languages) {
        var dialog = new jscape.domain.WebResourcesDialog();
        setTimeout(function() { dialog.setLanguages(languages); }, 10);
        return dialog;
    }
});

/** @class */
jscape.domain.WebResourcesDialog = Class.extend(
    /** @lends {jscape.domain.WebResourcesDialog.prototype} */
{
    /** @constructor */
    initialize: function() {
        var initializing = true;
        this.dialog = $("#d-services-webresources").clone().attr("id", "");
        this.dialog.dialog({
            width: "75%", height: "auto",
            modal: true, resizable: false, closable: true, closed: true,
            buttons: [
                {text: window.R.string.DIALOG_BUTTON_OK || "Ok", disabled: this.dialog.find("fieldset:first").is(":disabled"), 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=webresourcesfields]", this.dialog);

        this.language = $("select[name=language]", this.fieldset);
        this.language.combobox({
            required: true, editable: false, width: 210, panelHeight: "auto",
            valueField: "lang", textField: "displayName", selectOnNavigation: false,
            onChange: $.proxy(function() { if (!initializing) { this._onChange$Language.apply(this, arguments); }}, this),
            onLoadSuccess: $.proxy(this._onLoad$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",
            loadMsg: $.fn.datagrid.defaults.loadMsg,
            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)});

        initializing = false;
    },

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

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

    selectLanguage: function(value) {
        var lang = value[this.language.combobox("options").valueField];
        if (lang !== this.language.combobox("getValue")) {
            this.language.combobox("select", lang);
        } else {
            this._onChange$Language();
        }
    },

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

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

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

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

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

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

    _onLoad$Language: function(data) {
        if (data && data.length) {
            this.selectLanguage(data[0]);
        }
    },

    _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) {
        this.data.propertygrid("loading");
        var data = $.map(properties, function(value, key) { return {name: key, value: value, editor: "text"}});
        this.data.propertygrid("loadData", data).propertygrid("loaded");
    },

    _propertiesFor: function (language) {
        var data = this.language.combobox("getData");
        for (var i = 0; i < data.length; i++) {
            var webResources = data[i];
            if (webResources.lang == language) {
                return webResources.properties;
            }
        }
        return null;
    },

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

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

    _closed: function () {
        return !!this.dialog.dialog("options").closed;
    }
});
jscape.domain.WebResourcesDialog.LISTENER = {
    onAddLanguage: $.noop,
    onResetToDefault: $.noop,
    onSubmit: $.noop,
    onCancel: $.noop
};

/** @class */
jscape.domain.AddLanguageDialog = Class.extend(
    /** @lends {jscape.domain.AddLanguageDialog.prototype} */
{
    /** @constructor */
    initialize: function() {
        this.dialog = $("#d-services-addwebresource").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: "50%"});
    },

    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.domain.UploadFormsController = Class.extend(
    /** @lends {jscape.domain.UploadFormsController.prototype} */
{
    forms: null,
    dialog: null,
    deferred: null,

    /** @constructor */
    initialize: function() {
        this.addController = new jscape.domain.AddFormController();
        this.editController = new jscape.domain.EditFormController();

        this._initValidators();
    },

    start: function(forms, groupNames) {
        this.forms = forms || [];
        this.groups = groupNames || [];
        this.deferred = $.Deferred();

        this.dialog = this._setupDialog(forms);
        this.dialog.show(this);

        return this.deferred.promise();
    },

    onFormUp: function (form) {
        var index = $.inArray(form, this.forms);
        if (index > 0) {
            this.forms.splice(index - 1, 2, this.forms[index], this.forms[index - 1]);
            this.dialog.setForms(this.forms);
            this.dialog.selectItem(form);
        }
    },

    onFormDown: function(form) {
        var index = $.inArray(form, this.forms);
        if (index != -1 && index < this.forms.length - 1) {
            this.forms.splice(index, 2, this.forms[index + 1], this.forms[index]);
            this.dialog.setForms(this.forms);
            this.dialog.selectItem(form);
        }
    },

    onAddForm: function() {
        this.addController.start(this.groups).done($.proxy(this._formAdded, this));
    },

    onEditForm: function(form) {
        var index = $.inArray(form, this.forms);
        if (index != -1) {
            this.editController.start(this.groups, form).done($.proxy(this._formEdited, this, index));
        }
    },

    onDeleteForm: function(forms) {
        this._confirmDelete(forms).done($.proxy(this._formDeleted, this, forms));
    },

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

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

    _formAdded: function (form) {
        this.forms.push(form);
        this.dialog.setForms(this.forms);
        this.dialog.selectItem(form);
    },

    _formEdited: function (index, form) {
        this.forms[index] = form;
        this.dialog.setForms(this.forms);
        this.dialog.selectItem(form);
    },

    _formDeleted: function (forms) {
        var index = -1;
        while (forms.length) {
            index = $.inArray(forms.pop(), this.forms);
            this.forms.splice(index, 1);
        }
        this.dialog.setForms(this.forms);
        if (this.forms.length) {
            index = Math.max(0, Math.min(index, this.forms.length - 1));
            this.dialog.selectItem(this.forms[index]);
        }
    },

    _confirmDelete: function(forms) {
        var text = $.map(forms || [], function(form) { return form.name; }).join(", ");
        return jscape.ConfirmDialog.confirm(window.R.string.UPLOAD_FORMS_CONFIRM_DELETE_TITLE,
                                            window.R.string.UPLOAD_FORMS_CONFIRM_DELETE_MESSAGE.supplant({0: text}));
    },

    _setupDialog: function(forms) {
        var dialog = new jscape.domain.UploadFormsDialog();
        dialog.setForms(forms);
        return dialog;
    },

    _initValidators: function() {
        var v = new jscape.Validator();
        v.rule("uploadform_name", $.proxy(this._uploadFormNameValid, this), window.R.string.UPLOAD_FORMS_ERROR_BAD_NAME);
        v.rule("uploadform_unique", $.proxy(this._uploadFormUnique, this), window.R.string.UPLOAD_FORMS_ERROR_ALREADY_EXISTS);
    },

    _uploadFormNameValid: function(value) {
        return /^[^\s_.]+$/.test(value);
    },

    _uploadFormUnique: function(value) {
        return $.grep(this.forms, function(form) { return form.name === value; }).length == 0;
    }
});

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

    /** @constructor */
    initialize: function() {
        this.dialog = $("#d-services-uploadforms").clone().attr("id", "");
        this.dialog.dialog({
            width: "60%", height: "auto",
            modal: true, resizable: false, closable: true, closed: true,
            buttons: [
                {text: window.R.string.DIALOG_BUTTON_OK || "Ok", disabled: this.dialog.find("fieldset:first").is(":disabled"), 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=uploadformsfields]", this.dialog);

        this.data = $("table[role=grid][aria-label=uploadforms]", this.fieldset);
        this.data.datagrid({
            fit: true,
            fitColumns: true,
            singleSelect: true,
            onSelect: $.proxy(this._adjustRowSelection, this),
            onUnselect: $.proxy(this._adjustRowSelection, this),
            onDblClickRow: $.proxy(this._onClick$EditButton, this),
            onLoadSuccess: $.proxy(this._adjustRowSelection, this),
            idField: "name",
            columns: [[
                {field: "name", title: $("thead th:nth-child(1)", this.data).text(), width: "70%"},
                {field: "enabled", title: $("thead th:nth-child(2)", this.data).text(), width: "30%"}
            ]]
        });

        this.moveUpButton = $("a[role=button][name=moveup]", this.fieldset).linkbutton({disabled: true, onClick: $.proxy(this._onClick$MoveUpButton, this)});
        this.moveDownButton = $("a[role=button][name=movedown]", this.fieldset).linkbutton({disabled: true, onClick: $.proxy(this._onClick$MoveDownButton, this)});
        this.addButton = $("a[role=button][name=add]", this.fieldset).linkbutton({onClick: $.proxy(this._onClick$AddButton, this)});
        this.editButton = $("a[role=button][name=edit]", this.fieldset).linkbutton({disabled: true, onClick: $.proxy(this._onClick$EditButton, this)});
        this.deleteButton = $("a[role=button][name=delete]", this.fieldset).linkbutton({disabled: true, onClick: $.proxy(this._onClick$DeleteButton, this)});
    },

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

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

    show: function (listener) {
        this.listener = listener || jscape.domain.UploadFormsDialog.LISTENER;
        this.selection = [];
        this.dialog.dialog("center").dialog("open");
        this._adjustButtonsState();
    },

    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$MoveUpButton: function() {
        this.listener.onFormUp(this.selection[0]);
    },

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

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

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

    _onClick$DeleteButton: function() {
        this.listener.onDeleteForm(this.selection);
    },

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

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

    _adjustButtonsState: function () {
        var index = this.selection.length == 1 ? this.data.datagrid("getRowIndex", this.selection[0]) : -1;
        var count = this.data.datagrid("getRows").length;

        this.moveUpButton.linkbutton(index > 0 && index <= count - 1 ? "enable" : "disable");
        this.moveDownButton.linkbutton(index >= 0 && index < count - 1 ? "enable" : "disable");
        this.editButton.linkbutton(this.selection.length == 1 ? "enable" : "disable");
        this.deleteButton.linkbutton(this.selection.length != 0 ? "enable" : "disable");
    }
});
jscape.domain.UploadFormsDialog.LISTENER = {
    onFormUp: $.noop,
    onFormDown: $.noop,
    onAddForm: $.noop,
    onEditForm: $.noop,
    onDeleteForm: $.noop,
    onSubmit: $.noop,
    onCancel: $.noop
};

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

    /** @constructor */
    initialize: function() {
        this.addController = new jscape.domain.AddFormInputController();
        this.editController = new jscape.domain.EditFormInputController();
    },

    start: function(groups, inputs) {
        this.inputs = inputs || [];
        this.deferred = $.Deferred();
        this.dialog = this._setupDialog(groups).show(this);
        return this.deferred.promise();
    },

    onInputUp: function (input) {
        var index = $.inArray(input, this.inputs);
        if (index > 0) {
            this.inputs.splice(index - 1, 2, this.inputs[index], this.inputs[index - 1]);
            this.dialog.setInputs(this.inputs);
            this.dialog.selectItem(input);
        }
    },

    onInputDown: function (input) {
        var index = $.inArray(input, this.inputs);
        if (index != -1 && index < this.inputs.length - 1) {
            this.inputs.splice(index, 2, this.inputs[index + 1], this.inputs[index]);
            this.dialog.setInputs(this.inputs);
            this.dialog.selectItem(input);
        }
    },

    onAddInput: function() {
        this.addController.start().done($.proxy(function(input) {
            this.inputs.push(input);
            this.dialog.setInputs(this.inputs);
            this.dialog.selectItem(input);
        }, this));
    },

    onEditInput: function(input) {
        var index = $.inArray(input, this.inputs);
        if (index != -1) {
            this.editController.start(input).done($.proxy(function(input) {
                this.inputs[index] = input;
                this.dialog.setInputs(this.inputs);
                this.dialog.selectItem(input);
            }, this));
        }
    },

    onDeleteInput: function (inputs) {
        var index = -1;
        while (inputs.length) {
            index = $.inArray(inputs.pop(), this.inputs);
            this.inputs.splice(index, 1);
        }
        this.dialog.setInputs(this.inputs);
    },

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

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

    _createForm: function(dialog) {
        throw "Abstract method";
    },

    _setupDialog: function(groups) {
    },

    _initValidators: function () {
        var v = new jscape.Validator();
        v.rule("uploadform_input_name", $.proxy(this._uploadFormInputNameValid, this), window.R.string.UPLOAD_FORMS_ERROR_BAD_INPUT_NAME);
        v.rule("uploadform_input_unique", $.proxy(this._uploadFormInputNotExists, this), window.R.string.UPLOAD_FORMS_ERROR_INPUT_ALREADY_EXISTS);
    },

    _uploadFormInputNameValid: function(value) {
        return /^[^\s_.]+$/gi.test(value);
    },

    _uploadFormInputNotExists: function (value) {
        return $.grep(this.inputs,function (input) { return input.name == value; }).length == 0;
    }
});

/** @class */
jscape.domain.AddFormController = jscape.domain.BaseFormController.extend(
    /** @lends {jscape.domain.AddFormController.prototype} */
{
    /** @override */
    start: function (groups) {
        this._initValidators();
        return this._super(groups, []);
    },

    /** @override */
    _createForm: function(dialog) {
        return new jscape.UploadForm(dialog.getName(),
                                     dialog.getDescription(),
                                     dialog.isEnabled(),
                                     dialog.isBatch(),
                                     dialog.getGroup(),
                                     dialog.getInputs());
    },

    /** @override */
    _setupDialog: function(groups) {
        var dialog = new jscape.domain.AddFormDialog();
        dialog.setGroups(groups);
        dialog.setBatch(true);
        dialog.setEnabled(true);
        return dialog;
    }
});

/** @class */
jscape.domain.EditFormController = jscape.domain.BaseFormController.extend(
    /** @lends {jscape.domain.EditFormController.prototype} */
{
    /** @override */
    start: function(groups, form) {
        this.form = form;
        this._initValidators();
        return this._super(groups, form.inputs);
    },

    /** @override */
    _createForm: function(dialog) {
        return new jscape.UploadForm(this.form.name,
                                     dialog.getDescription(),
                                     dialog.isEnabled(),
                                     dialog.isBatch(),
                                     dialog.getGroup(),
                                     dialog.getInputs());
    },

    /** @override */
    _setupDialog: function(groups) {
        var dialog = new jscape.domain.EditFormDialog();
        dialog.setFormName(this.form.name);
        dialog.setDescription(this.form.description);
        dialog.setEnabled(this.form.enabled);
        dialog.setBatch(this.form.batch);
        dialog.setGroups(groups);
        dialog.setGroup(this.form.group);
        dialog.setInputs(this.form.inputs);
        return dialog;
    }
});

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

    /** @constructor */
    initialize: function(dialog) {
        this.dialog = dialog.clone().attr("id", "");
        this.dialog.dialog({
            width: "60%", 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=uploadformfields]", this.dialog);

        this.description = $("input[name=description]", this.fieldset).textbox({width: "70%"});
        this.prompt = $("input[name=prompt]:radio", this.fieldset);

        this.groupEnabled = $("input[name=grouprequired]:checkbox", this.fieldset);
        this.groupEnabled.change($.proxy(function() {
            var enabled = this.groupEnabled.is(":checked");
            this.group.combobox(enabled ? "enable" : "disable").combobox(enabled ? "enableValidation" : "disableValidation");
        }, this));
        this.group = $("select[name=group]", this.fieldset);
        this.group.combobox({
            required: true, editable: false, disabled: true, width: 150, panelHeight: "auto",
            onLoadSuccess: $.proxy(function(data) {
                if (data.length) {
                    this.group.combobox("select", data[0].value);
                } else {
                    this.groupEnabled.prop("disabled", true).prop("checked", false).change();
                }
            }, this)
        });

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

        this.inputs = $("table[role=grid][aria-label=inputs]", this.fieldset);
        this.inputs.datagrid({
            fit: true,
            fitColumns: true,
            remoteSort: false,
            ctrlSelect: true,
            onSelect: $.proxy(this._adjustRowSelection, this),
            onUnselect: $.proxy(this._adjustRowSelection, this),
            onDblClickRow: $.proxy(this._onClick$EditButton, this),
            onLoadSuccess: $.proxy(this._adjustRowSelection, this),
            columns: [[
                {field: "name", title: $("thead th:nth-child(1)", this.inputs).text(), width: 100},
                {field: "type", title: $("thead th:nth-child(2)", this.inputs).text(), width: 80},
                {field: "value", title: $("thead th:nth-child(3)", this.inputs).text(), width: 150},
                {field: "required", title: $("thead th:nth-child(4)", this.inputs).text(), width: 60}
            ]]
        });

        this.moveUpButton = $("a[role=button][name=moveup]", this.fieldset).linkbutton({disabled: true, onClick: $.proxy(this._onClick$MoveUpButton, this)});
        this.moveDownButton = $("a[role=button][name=movedown]", this.fieldset).linkbutton({disabled: true, onClick: $.proxy(this._onClick$MoveDownButton, this)});
        this.addButton = $("a[role=button][name=add]", this.fieldset).linkbutton({onClick: $.proxy(this._onClick$AddButton, this)});
        this.editButton = $("a[role=button][name=edit]", this.fieldset).linkbutton({disabled: true, onClick: $.proxy(this._onClick$EditButton, this)});
        this.deleteButton = $("a[role=button][name=delete]", this.fieldset).linkbutton({disabled: true, onClick: $.proxy(this._onClick$DeleteButton, this)});
    },

    getDescription: function() {
        return this.description.textbox("getValue");
    },

    setDescription: function(value) {
        this.description.textbox("setValue", value);
    },

    isBatch: function() {
        return this.prompt.filter("[value=batch]").is(":checked");
    },

    setBatch: function(value) {
        this.prompt.filter(!!value ? "[value=batch]" : "[value=file]").prop("checked", true);
    },

    getGroup: function() {
        return this.groupEnabled.is(":checked") ? this.group.combobox("getValue") : null;
    },

    setGroup: function(value) {
        this.groupEnabled.prop("checked", value != null).change();
        if (value != null) {
            this.group.combobox("setValue", value);
        }
    },

    setGroups: function(values) {
        this.group.combobox("loadData", values);
    },

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

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

    getInputs: function() {
        return this.inputs.datagrid("getRows");
    },

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

    selectItem: function(input) {
        this.inputs.datagrid("selectRow", this.inputs.datagrid("getRowIndex", input));
    },

    show: function (listener) {
        this.listener = listener || jscape.domain.BaseFormDialog.LISTENER;
        this.selection = [];
        this.dialog.dialog("center").dialog("open");
        this.fieldset.form("validate");
        this._adjustButtonsState();
        return this;
    },

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

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

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

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

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

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

    _onClick$DeleteButton: function() {
        this.listener.onDeleteInput(this.selection);
    },

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

    _adjustButtonsState: function() {
        var index = this.selection.length == 1 ? this.inputs.datagrid("getRowIndex", this.selection[0]) : -1;
        var count = this.inputs.datagrid("getRows").length;

        this.moveUpButton.linkbutton(index > 0 && index <= count - 1 ? "enable" : "disable");
        this.moveDownButton.linkbutton(index >= 0 && index < count - 1 ? "enable" : "disable");
        this.editButton.linkbutton(this.selection.length == 1 ? "enable" : "disable");
        this.deleteButton.linkbutton(this.selection.length != 0 ? "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.domain.BaseFormDialog.LISTENER = {
    onInputUp: $.noop,
    onInputDown: $.noop,
    onAddInput: $.noop,
    onEditInput: $.noop,
    onDeleteInput: $.noop
};

/** @class */
jscape.domain.AddFormDialog = jscape.domain.BaseFormDialog.extend(
    /** @lends {jscape.domain.AddFormDialog.prototype} */
{
    /** @constructor */
    initialize: function() {
        this._super($("#d-uploadforms-add"));

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

    getName: function() {
        return this.name.textbox("getValue");
    }
});

/** @class */
jscape.domain.EditFormDialog = jscape.domain.BaseFormDialog.extend(
    /** @lends {jscape.domain.EditFormDialog.prototype} */
{
    /** @constructor */
    initialize: function() {
        this._super($("#d-uploadforms-edit"));

        this.title = this.dialog.dialog("header").text() || "";
    },

    setFormName: function(value) {
        this.dialog.dialog("setTitle", this.title.supplant({0: value}));
    }
});

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

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

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

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

    _createFormInput: function(dialog) {
        throw "Abstract method";
    },

    _setupDialog: function() {
    }
});

/** @class */
jscape.domain.AddFormInputController = jscape.domain.BaseFormInputController.extend(
    /** @lends {jscape.domain.AddFormInputController.prototype} */
{
    _createFormInput: function(dialog) {
        return new jscape.UploadForm.Input(dialog.getType(), dialog.getName(), dialog.getLabel(), dialog.getValue(), dialog.isRequired());
    },

    _setupDialog: function() {
        var dialog = new jscape.domain.AddFormInputDialog();
        dialog.setType(jscape.UploadForm.Input.TYPE.TEXT);
        dialog.setRequired(true);
        return dialog;
    }
});

/** @class */
jscape.domain.EditFormInputController = jscape.domain.BaseFormInputController.extend(
    /** @lends {jscape.domain.EditFormInputController.prototype} */
{
    /** @override */
    start: function(input) {
        this.input = input;
        return this._super();
    },

    _createFormInput: function(dialog) {
        return new jscape.UploadForm.Input(dialog.getType(), this.input.name, dialog.getLabel(), dialog.getValue(), dialog.isRequired());
    },

    _setupDialog: function () {
        var dialog = new jscape.domain.EditFormInputDialog();
        dialog.setName(this.input.name);
        dialog.setLabel(this.input.label);
        dialog.setType(this.input.type);
        dialog.setValue(this.input.value);
        dialog.setRequired(this.input.required);
        return dialog;
    }
});

/** @class */
jscape.domain.BaseFormInputDialog = Class.extend(
    /** @lends {jscape.domain.BaseFormInputDialog.prototype} */
{
    /** @constructor */
    initialize: function(dialog) {
        this.dialog = dialog.clone().attr("id", "");
        this.dialog.dialog({
            width: "50%", 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=uploadforminputfields]", this.dialog);

        this.label = $("input[name=label]", this.fieldset).textbox({width: "60%"});
        this.type = $("select[name=type]", this.fieldset).combobox({required: true, editable: false, width: 210, panelHeight: "auto"});
        this.value = $("input[name=value]", this.fieldset).textbox({width: "60%"});
        this.required = $("input[name=required]:checkbox", this.fieldset);
    },

    getLabel: function() {
        return this.label.textbox("getValue");
    },

    setLabel: function(value) {
        this.label.textbox("setValue", value);
    },

    getType: function() {
        return this.type.combobox("getValue");
    },

    setType: function(value) {
        this.type.combobox("setValue", value);
    },

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

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

    isRequired: function() {
        return this.required.is(":checked");
    },

    setRequired: function(value) {
        this.required.prop("checked", !!value);
    },

    show: function (listener) {
        this.listener = listener;
        this.dialog.dialog("center").dialog("open");
        this.fieldset.form("validate");
        this.fieldset.find("input:not(:disabled):first").focus();
        return this;
    },

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

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

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

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

    _closed: function () {
        return !!this.dialog.dialog("options").closed;
    }
});

/** @class */
jscape.domain.AddFormInputDialog = jscape.domain.BaseFormInputDialog.extend(
    /** @lends {jscape.domain.AddFormInputDialog.prototype} */
{
    /** @constructor */
    initialize: function() {
        this._super($("#d-uploadforms-addfield"));

        this.name = $("input[name=name]", this.fieldset).textbox({
            required: true,
            validType: ["uploadform_input_name", "uploadform_input_unique"],
            missingMessage: window.R.string.UPLOAD_FORMS_ERROR_BAD_INPUT_NAME,
            width: "60%"
        });
    },

    getName: function() {
        return this.name.textbox("getValue");
    }
});

/** @class */
jscape.domain.EditFormInputDialog = jscape.domain.BaseFormInputDialog.extend(
    /** @lends {jscape.domain.EditFormInputDialog.prototype} */
{
    /** @constructor */
    initialize: function() {
        this._super($("#d-uploadforms-editfield"));

        this.title = this.dialog.dialog("header").text() || "";
    },

    setName: function(value) {
        this.dialog.dialog("setTitle", this.title.supplant({0: value}));
    }
});