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

/** @class */
jscape.ResourceDescriptor = Class.extend(
    /** @lends {jscape.ResourceDescriptor.prototype} */
{
    /** @constructor */
    initialize: function(a, b, c, d, e, f, g, h, i, j, k, l) {
        this.name = a || "";
        this.protocol = b || null;
        this.host = c || "";
        this.port = parseInt(d) || null;
        this.timeout = parseInt(e) || null;
        this.username = f !== undefined ? f : null;
        this.password = g !== undefined ? g : null;
        this.usingCredentials = h || false;
        this.remoteDirectory = i || null;
        this.logDirectory = j || null;
        this.timeToLive = parseInt(k) || null;
        this.tags = l || [];
    }
});
jscape.ResourceDescriptor.fromJSON = function(data) {
    var remoteDir = jscape.RemoteDirectory.fromJSON(data.remoteDirectory);
    if (data.protocol == jscape.ResourceDescriptor.Protocol.WEBDAV) {
        return jscape.ResourceDescriptor.webdav(data.name, data.host, data.port, data.domain, data.path, !!data.useSsl, data.username, data.password, data.usingCredentials, remoteDir, data.logDirectory, data.tags);
    } else {
        var keyProvider = jscape.KeyProvider.fromJSON(data.keyProvider);
        var hostKeyProvider = jscape.KeyProvider.fromJSON(data.hostKeyProvider);
        if (data.protocol == jscape.ResourceDescriptor.Protocol.AFTP) {
            return jscape.ResourceDescriptor.aftp(data.name, data.host, data.port, data.timeout, data.tcpNoDelayEnabled, data.securityMode, data.username, data.password, data.usingCredentials, keyProvider, hostKeyProvider, remoteDir, data.logDirectory, data.timeToLive, data.tags);
        } else if (data.protocol == jscape.ResourceDescriptor.Protocol.FTP) {
            return jscape.ResourceDescriptor.ftp(data.name, data.host, data.port, data.timeout, data.tcpNoDelayEnabled, data.connectionType, data.passive, data.username, data.password, data.usingCredentials, keyProvider, hostKeyProvider, remoteDir, data.logDirectory, data.timeToLive, data.tags);
        } else if (data.protocol == jscape.ResourceDescriptor.Protocol.SFTP) {
            return jscape.ResourceDescriptor.sftp(data.name, data.host, data.port, data.timeout, data.tcpNoDelayEnabled, data.useAdaptiveConnection, data.startSubsystemReplyRequired, data.username, data.password, data.usingCredentials, keyProvider, hostKeyProvider, remoteDir, data.logDirectory, data.timeToLive, data.tags);
        } else if (data.protocol == jscape.ResourceDescriptor.Protocol.AMAZON_S3) {
            return jscape.ResourceDescriptor.amazonS3(data.name, data.encryptionType, data.kmsKeyId, data.username, data.password, data.authenticationType, data.region, remoteDir, data.logDirectory, data.tags);
        } else if (data.protocol == jscape.ResourceDescriptor.Protocol.REST) {
            return jscape.ResourceDescriptor.rest(data.name, data.host, data.port, data.timeout, data.sslRequired, data.domain, data.username, data.password, data.usingCredentials, keyProvider, remoteDir, data.logDirectory, data.timeToLive, data.tags);
        } else if (data.protocol == jscape.ResourceDescriptor.Protocol.OFTP) {
            hostKeyProvider = null;
            var encryptionKeyProvider = jscape.ServerKeyProvider.fromJSON(data.encryptionKeyProvider);
            var signingKeyProvider = jscape.ServerKeyProvider.fromJSON(data.signingKeyProvider);
            return jscape.ResourceDescriptor.oftp(data.name, data.host, data.port, data.sslRequired, data.username, data.password, data.usingCredentials, keyProvider, hostKeyProvider, data.destination, encryptionKeyProvider, signingKeyProvider, data.cipherSuite, data.logDirectory, data.timeToLive, data.tags);
        } else if (data.protocol == jscape.ResourceDescriptor.Protocol.TFTP) {
            return jscape.ResourceDescriptor.tftp(data.name, data.host, data.port, data.retransmitTimeout, data.maxRetransmitAttempts, data.logDirectory, data.tags);
        } else if (data.protocol == jscape.ResourceDescriptor.Protocol.SMB) {
            return jscape.ResourceDescriptor.smb(data.name, data.host, data.port, data.timeout, data.domain, data.username, data.password, data.usingCredentials, remoteDir, data.logDirectory, data.tags);
        } else if (data.protocol == jscape.ResourceDescriptor.Protocol.GOOGLE_STORAGE) {
            return jscape.ResourceDescriptor.googleStorage(data.name, data.authenticationType, data.credentialsFile, remoteDir, data.logDirectory, data.tags);
        } else if (data.protocol == jscape.ResourceDescriptor.Protocol.MICROSOFT_AZURE) {
            return jscape.ResourceDescriptor.microsoftAzure(data.name, data.username, data.password, data.usingCredentials, data.sslRequired, remoteDir, data.logDirectory, data.tags);
        }
    }
    throw "Unknown resource type: " + (data && data.protocol);
};
jscape.ResourceDescriptor.aftp = function(name, host, port, timeout, tcpNoDelay, securityMode, username, password, usingCredentials, keyProvider, hostKeyProvider, remoteDir, logDir, timeToLive, tags) {
    return $.extend(new jscape.ResourceDescriptor(name, jscape.ResourceDescriptor.Protocol.AFTP, host, port, timeout, username, password, usingCredentials, remoteDir, logDir, timeToLive, tags),
                    {tcpNoDelayEnabled: !!tcpNoDelay, securityMode: securityMode, keyProvider: keyProvider, hostKeyProvider: hostKeyProvider});
};
jscape.ResourceDescriptor.ftp = function(name, host, port, timeout, tcpNoDelay, connectionType, passive, username, password, usingCredentials, keyProvider, hostKeyProvider, remoteDir, logDir, timeToLive, tags) {
    return $.extend(new jscape.ResourceDescriptor(name, jscape.ResourceDescriptor.Protocol.FTP, host, port, timeout, username, password, usingCredentials, remoteDir, logDir, timeToLive, tags),
                    {tcpNoDelayEnabled: !!tcpNoDelay, connectionType: connectionType, passive: !!passive, keyProvider: keyProvider, hostKeyProvider: hostKeyProvider});
};
jscape.ResourceDescriptor.sftp = function(name, host, port, timeout, tcpNoDelay, useAdaptiveConnection, startSubsystemReplyRequired, username, password, usingCredentials, keyProvider, hostKeyProvider, remoteDir, logDir, timeToLive, tags) {
    return $.extend(new jscape.ResourceDescriptor(name, jscape.ResourceDescriptor.Protocol.SFTP, host, port, timeout, username, password, usingCredentials, remoteDir, logDir, timeToLive, tags),
                    {tcpNoDelayEnabled: !!tcpNoDelay, useAdaptiveConnection: !!useAdaptiveConnection, startSubsystemReplyRequired: !!startSubsystemReplyRequired, keyProvider: keyProvider, hostKeyProvider: hostKeyProvider});
};
jscape.ResourceDescriptor.webdav = function(name, host, port, domain, path, useSsl, username, password, usingCredentials, remoteDir, logDir, tags) {
    return $.extend(new jscape.ResourceDescriptor(name, jscape.ResourceDescriptor.Protocol.WEBDAV, host, port, undefined, username, password, usingCredentials, remoteDir, logDir, null, tags),
                    {domain: domain, path: path, useSsl: !!useSsl});
};
jscape.ResourceDescriptor.amazonS3 = function(name, encryptionType, kmsKey, username, password, authenticationType, region, remoteDir, logDir, tags) {
    return $.extend(new jscape.ResourceDescriptor(name, jscape.ResourceDescriptor.Protocol.AMAZON_S3, undefined, undefined, undefined, username, password, undefined, remoteDir, logDir, null, tags),
                    {encryptionType: encryptionType || "NONE", kmsKeyId: kmsKey, authenticationType: authenticationType, region: region});
};
jscape.ResourceDescriptor.googleStorage = function(name, authenticationType, keyFile, remoteDir, logDir, tags) {
    return $.extend(new jscape.ResourceDescriptor(name, jscape.ResourceDescriptor.Protocol.GOOGLE_STORAGE, undefined, undefined, undefined, undefined, undefined, undefined, remoteDir, logDir, null, tags),
                    {authenticationType: authenticationType, credentialsFile: keyFile});
};
jscape.ResourceDescriptor.microsoftAzure = function(name, username, password, usingCredentials, sslRequired, remoteDir, logDir, tags) {
    return $.extend(new jscape.ResourceDescriptor(name, jscape.ResourceDescriptor.Protocol.MICROSOFT_AZURE, undefined, undefined, undefined, username, password, usingCredentials, remoteDir, logDir, null, tags),
                    {sslRequired: !!sslRequired});
};
jscape.ResourceDescriptor.rest = function(name, host, port, timeout, sslRequired, domain, username, password, usingCredentials, keyProvider, remoteDir, logDir, timeToLive, tags) {
    return $.extend(new jscape.ResourceDescriptor(name, jscape.ResourceDescriptor.Protocol.REST, host, port, timeout, username, password, usingCredentials, remoteDir, logDir, timeToLive, tags),
                    {sslRequired: !!sslRequired, domain: domain, keyProvider: keyProvider});
};
jscape.ResourceDescriptor.oftp = function(name, host, port, sslRequired, username, password, usingCredentials, keyProvider, hostKeyProvider, destination, encryptionKeyProvider, signingKeyProvider, cipherSuite, logDir, timeToLive, tags) {
    return $.extend(new jscape.ResourceDescriptor(name, jscape.ResourceDescriptor.Protocol.OFTP, host, port, undefined, username, password, usingCredentials, undefined, logDir, timeToLive, tags),
                    {sslRequired: !!sslRequired, keyProvider: keyProvider, hostKeyProvider: hostKeyProvider, destination: destination, encryptionKeyProvider: encryptionKeyProvider, signingKeyProvider: signingKeyProvider, cipherSuite: cipherSuite});
};
jscape.ResourceDescriptor.tftp = function(name, host, port, retransmitTimeout, maxRetransmitAttempts, logDir, tags) {
    return $.extend(new jscape.ResourceDescriptor(name, jscape.ResourceDescriptor.Protocol.TFTP, host, port, undefined, undefined, undefined, false, undefined, logDir, null, tags),
                    {retransmitTimeout: retransmitTimeout, maxRetransmitAttempts: maxRetransmitAttempts});
};
jscape.ResourceDescriptor.smb = function(name, host, port, timeout, domain, username, password, usingCredentials, remoteDir, logDir, tags) {
    return $.extend(new jscape.ResourceDescriptor(name, jscape.ResourceDescriptor.Protocol.SMB, host, port, timeout, username, password, usingCredentials, remoteDir, logDir, null, tags),
                    {domain: domain});
};

jscape.ResourceDescriptor.Protocol = {AFTP: "AFTP", AMAZON_S3: "AmazonS3", GOOGLE_STORAGE: "Google Cloud Storage", MICROSOFT_AZURE: "Microsoft Azure File Storage", FTP: "FTP", OFTP: "OFTP", REST: "REST", SFTP: "SFTP", SMB: "SMB", WEBDAV: "WebDAV", TFTP: "TFTP"};
jscape.ResourceDescriptor.Protocol.values = function() { return $.map(this, function(value) { return typeof value === "string" ? value : null; }); };

/** @class */
jscape.RemoteDirectory = Class.extend(
    /** @lends {jscape.RemoteDirectory.prototype} */
{
    /** @constructor */
    initialize: function(type) {
        this.type = type || jscape.RemoteDirectory.Type.REMOTE;
    },

    toJSON: function() {
        var obj = $.extend({"@type": this.type}, this);
        delete obj.type;
        return obj;
    }
});
jscape.RemoteDirectory.Type = {LOCAL: "LOCAL", REMOTE: "REMOTE", REMOTE_PATH: "REMOTE_PATH"};
jscape.RemoteDirectory.fromJSON = function(data) {
    var type = data && data["@type"] in jscape.RemoteDirectory.Type ? data["@type"] : null;
    return data ? $.extend(new jscape.RemoteDirectory(type), data) : new jscape.RemoteDirectory(type);
};
jscape.RemoteDirectory.local = function() {
    return new jscape.RemoteDirectory(jscape.RemoteDirectory.Type.LOCAL);
};
jscape.RemoteDirectory.remote = function(path) {
    return path && path.trim().length
           ? $.extend(new jscape.RemoteDirectory(jscape.RemoteDirectory.Type.REMOTE_PATH), {path: path})
           : new jscape.RemoteDirectory(jscape.RemoteDirectory.Type.REMOTE);
};

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

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

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

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

/** @class */
jscape.domain.ReverseProxiesController = jscape.ui.DatagridController.extend(
    /** @lends {jscape.domain.ReverseProxiesController.prototype} */
{
    view: null,

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

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

        this.addController = new jscape.domain.AddReverseProxyController();
        this.editController = new jscape.domain.EditReverseProxyController();
        this.testController = new jscape.domain.TestReverseProxyController();
        this.deleteController = new jscape.domain.DeleteReverseProxyController();
    },

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

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

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

    onAddProxy: function() {
        this.addController.start(this, this.managementService, this.domainName)
                .done($.proxy(this._proxyAdded, this));
    },

    onEditProxy: function(proxy) {
        var index = $.inArray(proxy, this.view.getReverseProxies());
        if (index != -1) {
            this.editController.start(this, this.managementService, this.domainName, proxy)
                    .done($.proxy(this._proxyEdited, this, index));
        }
    },

    onDeleteProxy: function(proxies) {
        return this.deleteController.start(this.managementService, this.domainName, proxies)
                .done($.proxy(this._proxyDeleted, this, proxies));
    },

    onTestProxy: function(descriptor) {
        return this.testController.start(this.managementService, this.domainName, descriptor);
    },

    onTestServer: function(descriptor) {
        return this.onTestProxy(descriptor);
    },

    _proxyAdded: function(proxy) {
        this._recordAdded(proxy);
    },

    _proxyEdited: function(index, proxy) {
        this._recordEdited(proxy);
    },

    _proxyDeleted: function (proxies) {
        this._recordDeleted(proxies);
    },

    _initValidators: function() {
        var v = new jscape.Validator();
        v.nonEmptyRule("proxy_debugdir_nonempty", window.R.string.PROXIES_ERROR_BAD_DEBUG_DIR);
        v.rule("proxy_unique", $.proxy(this._proxyNotExists, this), window.R.string.PROXIES_ERROR_ALREADY_EXISTS);
    },

    _proxyNotExists: function (value, excludes) {
        return $.grep(this.view.getReverseProxies(), function (proxy) {
            return proxy.name == value && (excludes == undefined || $.inArray(proxy.name, excludes) == -1);
        }).length == 0;
    }
});

/** @class */
jscape.domain.ReverseProxiesView = jscape.ui.DatagridView.extend(
    /** @lends {jscape.domain.ReverseProxiesView.prototype} */
{
    selection: null,

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

        this.fieldset = $("fieldset[name=reverseproxiesfields]", container);

        this.data = $("table[role=grid][aria-label=reverseproxies]", this.fieldset);
        this.data.datagrid({
            fit: true,
            fitColumns: true,
            singleSelect: true,
            pagination: true,
            search: true,
            remoteSearch: true,
            remoteSort: true,
            sortName: "name",
            idField: "name",
            columns: [[
                {field: "name", title: $("thead th:nth-child(1)", this.data).text(), sortable: true, width: 120},
                {field: "protocol", title: $("thead th:nth-child(2)", this.data).text(), sortable: false, width: 60, formatter: $.proxy(this._formatProtocol, this), finder: {type: "combobox", options: {data: $.map(jscape.ResourceDescriptor.Protocol.values(), $.proxy(function(value) { return {text: this._formatProtocol(value), value: value}; }, this)), panelHeight: "auto"}}},
                {field: "host", title: $("thead th:nth-child(3)", this.data).text(), width: 100},
                {field: "port", title: $("thead th:nth-child(4)", this.data).text(), searchable: false, align: "right", width: 30},
                {field: "username", title: $("thead th:nth-child(5)", this.data).text(), width: 80},
                {field: "details", title: $("thead th:nth-child(6)", this.data).text(), searchable: false, formatter: $.proxy(function(_, row) { return this._formatDetails(row); }, this), width: 150},
                {field: "tags", title: $("thead th:nth-child(7)", this.data).text(), width: 80, formatter: function(value) { return String($.isArray(value) ? value.join(", ") : value).escapeXml(); }}
            ]],
            onSelect: $.proxy(this._adjustRowSelection, this),
            onUnselect: $.proxy(this._adjustRowSelection, this),
            onDblClickRow: $.proxy(this._onClick$EditButton, this),
            loader: $.proxy(this._onLoad$Data, this),
            onBeforeLoad: function () { return !initializing; },
            onLoadSuccess: $.proxy(this._adjustRowSelection, 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.testButton = $("a[role=button][name=test]", this.fieldset).linkbutton({disabled: true, onClick: $.proxy(this._onClick$TestButton, this)});
        this.deleteButton = $("a[role=button][name=delete]", this.fieldset).linkbutton({disabled: true, onClick: $.proxy(this._onClick$DeleteButton, this)});

        initializing = false;
    },

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

    getReverseProxies: function() {
        return this.getRecords();
    },

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

    _formatProtocol: function(value) {
        return window.R.string["APPLICATION_PROTOCOL_" + (value + "").toUpperCase().replace(/\s+/g, "_")] || "";
    },

    _formatDetails: function(descriptor) {
        return descriptor.connectionType
               ? String(descriptor.connectionType).escapeXml()
               : descriptor.securityMode ? window.R.string[("PROXIES_SECURITY_MODE_" + descriptor.securityMode).toUpperCase()] || "": "";
    },

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

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

    _onClick$TestButton: function() {
        this.testButton.linkbutton("disable");
        this.listener.onTestProxy(this.selection[0])
                .always($.proxy(this._adjustRowSelection, this));
    },

    _onClick$DeleteButton: function() {
        this.deleteButton.linkbutton("disable");
        this.listener.onDeleteProxy(this.selection)
                .always($.proxy(this._adjustRowSelection, this));
    },

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

    _adjustButtonsState: function() {
        this.editButton.linkbutton(this.selection.length == 1 ? "enable" : "disable");
        this.testButton.linkbutton(this.selection.length == 1 ? "enable" : "disable");
        this.deleteButton.linkbutton(this.selection.length != 0 ? "enable" : "disable");
    }
});
jscape.domain.ReverseProxiesView.LISTENER = {
    onRefresh: $.noop,
    onAddProxy: $.noop,
    onEditProxy: $.noop,
    onTestProxy: $.noop,
    onDeleteProxy: $.noop
};

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

    /** @constructor */
    initialize: function() {
        this.clientKeyController = new jscape.domain.ClientKeyController();
    },

    start: function(listener, managementService, domainName, keyProvider) {
        this.listener = listener || jscape.domain.BaseReverseProxyController.LISTENER;
        this.managementService = managementService;
        this.domainName = domainName;
        this.clientKeyProvider = keyProvider || null;
        this.deferred = $.Deferred();
        this._setupDialog().show(this);
        return this.deferred.promise();
    },

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

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

    onTest: function(dialog) {
        return this.listener.onTestServer(this._createDescriptor(dialog));
    },

    onSelectClientKey: function() {
        this.clientKeyController.start(this.managementService, this.domainName, this.clientKeyProvider)
                .done($.proxy(function(provider) { this.clientKeyProvider = provider; }, this));
    },

    onSelectKeyFile: function(dialog) {
        return new SelectPathController($.proxy(this.managementService.listKeystorePath, this.managementService),
                                        $.proxy(this.managementService.createKeystoreDir, this.managementService))
                .selectFile().then(function(entry) { return entry.path; });
    },

    onSelectDebugDir: function(dialog) {
        new SelectPathController($.proxy(this.managementService.listDebugDir, this.managementService),
                                 $.proxy(this.managementService.createDebugDir, this.managementService))
                .selectDirectory()
                .done(function(entry) { dialog.setDebugDirectory(entry.path); });
    },

    _loadHostKeys: function () {
        return this.managementService.getHostCertificates()
                .then(function(certificates) { return $.map(certificates, function (certificate) { return certificate.name; }); });
    },

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

    _createDescriptor: function (dialog) {
        throw "Abstract method";
    }
});
jscape.domain.BaseReverseProxyController.LISTENER = {
    onTestServer: $.noop
};

/** @class */
jscape.domain.ReverseProxyDialog = Class.extend(
    /** @lends {jscape.domain.ReverseProxyDialog.prototype} */
{
    /** @constructor */
    initialize: function(dialog) {
        this.dialog = dialog.clone().attr("id", "");
        this.dialog.dialog({
            width: "70%", 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)
        }).keydown($.proxy(function(e) {
            if (e.keyCode == 13) {
                e.stopPropagation();
                this._onSubmit();
            }
            if (e.keyCode == 27) {
                e.stopPropagation();
                this._onCancel();
            }
        }, this)).show();

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

        this.debugLog = $("input[name=debuglog]:checkbox", this.fieldset);
        this.debugLog.change($.proxy(function() {
            var enabled = this.debugLog.is(":checked");
            this.debugDir.textbox(enabled ? "enable" : "disable").textbox(enabled ? "enableValidation" : "disableValidation");
            this.debugDirBrowseButton.linkbutton(enabled ? "enable" : "disable");
        }, this));
        this.debugDir = $("input[name=debugdir]", this.fieldset).textbox({required: true, validaType: "proxy_debugdir_nonempty", missingMessage: window.R.string.PROXIES_ERROR_BAD_DEBUG_DIR, width: "50%"});
        this.debugDirBrowseButton = $("a[role=button][name=debugdirbrowse]", this.fieldset).linkbutton({disabled: true, onClick: $.proxy(this._onClick$DebugDirBrowseButton, this)});

        this.tags = $("select[name=tags]", this.fieldset).tagbox({limitToList: true, hasDownArrow: true, width: "60%", panelHeight: "auto", panelMaxHeight: 150, onLoadSuccess: function() { $(this).tagbox("clear"); }});

        this.testButton = $("a[role=button][name=test]", this.dialog).linkbutton({onClick: $.proxy(this._onClick$TestButton, this)});
    },

    getDebugDirectory: function() {
        return this.debugLog.is(":checked") ? this.debugDir.textbox("getValue") : null;
    },

    setDebugDirectory: function(value) {
        this.debugLog.prop("checked", value != null).change();
        this.debugDir.textbox("setValue", value || "");
    },

    setAvailableTags: function(values) {
        this.tags.tagbox("loadData", values);
    },

    getTags: function() {
        return this.tags.tagbox("getValues");
    },

    setTags: function(values) {
        this.tags.tagbox("setValues", values);
    },

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

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

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

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

    _onClick$DebugDirBrowseButton: function() {
        this.listener.onSelectDebugDir(this);
    },

    _onClick$TestButton: function() {
        if (this.fieldset.form("validate")) {
            this.testButton.linkbutton("disable");
            this.listener.onTest(this)
                    .always($.proxy(function() { this.testButton.linkbutton("enable"); }, this));
        }
    }
});
jscape.domain.ReverseProxyDialog.LISTENER = {
    onTest: $.noop,
    onSelectDebugDir: $.noop
};

/** @class */
jscape.domain.AddFtpReverseProxyController = jscape.domain.BaseReverseProxyController.extend(
    /** @lends {jscape.domain.AddFtpReverseProxyController.prototype} */
{
    SECURITY_MODE_KEY_USAGE: {'regular': false, 'explicit SSL': true, 'implicit SSL': true},
    DEFAULT_PORTS: {'regular': 21, 'explicit SSL': 21, 'implicit SSL': 990},
    DEFAULTS: {timeout: 1000, maxAge: 10 * 60 * 1000, tcpNoDelay: true},

    /** @override */
    _setupDialog: function() {
        var dialog = new jscape.domain.AddFtpReverseProxyDialog();
        dialog.setKeyUsage(this.SECURITY_MODE_KEY_USAGE);
        dialog.setDefaultPorts(this.DEFAULT_PORTS);
        dialog.setPort(this.DEFAULT_PORTS[dialog.getConnectionType()]);
        dialog.setTimeout(this.DEFAULTS.timeout);
        dialog.setTcpNoDelay(this.DEFAULTS.tcpNoDelay);
        dialog.setUsername("");
        dialog.setPassword("");
        dialog.setUsePassiveMode(true);
        dialog.setRemoteDirectory(true);
        dialog.setDebugDirectory(null);
        dialog.setMaxAge(this.DEFAULTS.maxAge);
        this.managementService.getDomainTags(this.domainName).done(function (tags) { dialog.setAvailableTags(tags); });
        this._loadHostKeys().done(function(keys) { dialog.setHostKeys(keys); });
        return dialog;
    },

    /** @override */
    _createDescriptor: function (dialog) {
        return jscape.ResourceDescriptor.ftp(dialog.getName(),
                                             dialog.getHost(),
                                             dialog.getPort(),
                                             dialog.getTimeout(),
                                             dialog.getTcpNoDelay(),
                                             dialog.getConnectionType(),
                                             dialog.isUsePassiveMode(),
                                             dialog.getUsername(),
                                             dialog.getPassword(),
                                             dialog.isReplayCredentials(),
                                             this.clientKeyProvider,
                                             dialog.getHostKey() != null ? new jscape.ServerKeyProvider(dialog.getHostKey()) : null,
                                             dialog.isRemoteDirectory() ? jscape.RemoteDirectory.remote(dialog.getRemoteDirectoryPath()) : jscape.RemoteDirectory.local(),
                                             dialog.getDebugDirectory(),
                                             dialog.getMaxAge(),
                                             dialog.getTags());
    }
});

/** @class */
jscape.domain.EditFtpReverseProxyController = jscape.domain.BaseReverseProxyController.extend(
    /** @lends {jscape.domain.EditFtpReverseProxyController.prototype} */
{
    /** @const */
    SECURITY_MODE_KEY_USAGE: {'regular': false, 'explicit SSL': true, 'implicit SSL': true},
    DEFAULT_PORTS: {'REGULAR': 21, 'EXPLICIT_SSL': 21, 'IMPLICIT_SSL': 990},

    descriptor: null,

    /** @override */
    start: function(listener, managementService, domainName, descriptor) {
        this.descriptor = descriptor;
        return this._super(listener, managementService, domainName, descriptor.keyProvider);
    },

    /** @override */
    _setupDialog: function() {
        var dialog = new jscape.domain.EditFtpReverseProxyDialog();
        var descriptor = this.descriptor;
        if (descriptor) {
            dialog.setName(descriptor.name);
            dialog.setHost(descriptor.host);
            dialog.setPort(descriptor.port);
            dialog.setTimeout(descriptor.timeout);
            dialog.setTcpNoDelay(descriptor.tcpNoDelayEnabled);
            dialog.setConnectionType(descriptor.connectionType);
            dialog.setKeyUsage(this.SECURITY_MODE_KEY_USAGE);
            dialog.setUsername(descriptor.username);
            dialog.setPassword(descriptor.password);
            dialog.setUsePassiveMode(descriptor.passive);
            dialog.setRemoteDirectoryPath(descriptor.remoteDirectory.path);
            dialog.setRemoteDirectory(jscape.RemoteDirectory.Type.LOCAL != descriptor.remoteDirectory.type);
            dialog.setDebugDirectory(descriptor.logDirectory);
            dialog.setMaxAge(descriptor.timeToLive);
        }
        this.managementService.getDomainTags(this.domainName)
                .done(function (tags) {
                          dialog.setAvailableTags(tags);
                          descriptor && dialog.setTags(descriptor.tags);
                      });
        this._loadHostKeys()
                .done(function (keys) {
                          dialog.setHostKeys(keys);
                          descriptor && dialog.setHostKey(descriptor.hostKeyProvider ? descriptor.hostKeyProvider.keyAlias : null);
                      });
        return dialog;
    },

    /** @override */
    _createDescriptor: function (dialog) {
        return jscape.ResourceDescriptor.ftp(this.descriptor.name,
                                             dialog.getHost(),
                                             dialog.getPort(),
                                             dialog.getTimeout(),
                                             dialog.getTcpNoDelay(),
                                             dialog.getConnectionType(),
                                             dialog.isUsePassiveMode(),
                                             dialog.getUsername(),
                                             dialog.getPassword(),
                                             dialog.isReplayCredentials(),
                                             this.clientKeyProvider,
                                             dialog.getHostKey() != null ? new jscape.ServerKeyProvider(dialog.getHostKey()) : null,
                                             dialog.isRemoteDirectory() ? jscape.RemoteDirectory.remote(dialog.getRemoteDirectoryPath()) : jscape.RemoteDirectory.local(),
                                             dialog.getDebugDirectory(),
                                             dialog.getMaxAge(),
                                             dialog.getTags());
    }
});

/** @class */
jscape.domain.FtpReverseProxyDialog = jscape.domain.ReverseProxyDialog.extend(
    /** @lends {jscape.domain.FtpReverseProxyDialog.prototype} */
{
    /** @cons */
    TIMEOUT_FACTOR: 60 * 1000,
    DEFAULT_MAX_AGE: 10,

    keyUsage: null,
    defaultPorts: null,

    /** @constructor */
    initialize: function(dialog) {
        this._super(dialog);

        var initializing = true;
        this.keyUsage = {};
        this.defaultPorts = {};

        this.host = $("input[name=host]", this.fieldset).textbox({required: true, validType: "non_empty", missingMessage: window.R.string.PROXIES_ERROR_BAD_HOST, invalidMessage: window.R.string.PROXIES_ERROR_BAD_HOST, width: "60%"});
        this.port = $("input[name=port]", this.fieldset).numberspinner({required: true, min: 1, max: 65535, width: 100});
        this.timeout = $("input[name=timeout]", this.fieldset).numberspinner({required: true, min: 1, max: 60, width: 60});
        this.tcpNoDelay = $("input[name=tcpnodelay]:checkbox", this.fieldset);
        this.connectionType = $("select[name=connectiontype]", this.fieldset).combobox({required: true, editable: false, width: 120, panelHeight: "auto", onChange: $.proxy(function(val) { if (!initializing) this._adjustSecurityMode(val); }, this)});

        this.useHostKey = $("input[name=usehostkey]:checkbox", this.fieldset).prop("disabled", true);
        this.useHostKey.change($.proxy(function() { this.hostKey.combobox(this.useHostKey.is(":checked:not(:disabled)") ? "enable" : "disable"); }, this));
        this.hostKey = $("select[name=hostkey]", this.fieldset);
        this.hostKey.combobox({editable: false, disabled: true, width: 170, panelHeight: "auto", panelMaxHeight: 150, onLoadSuccess: $.proxy(function(data) {
            this.useHostKey.prop("disabled", data.length == 0);
            if (data.length != 0) {
                this.hostKey.combobox("select", data[0].value);
            }
        }, this)});
        this.clientKeyButton = $("a[role=button][name=selectclientkey]", this.fieldset).linkbutton({onClick: $.proxy(this._onClick$ClientKeyButton, this)});

        this.credentials = $("input[name=credentials]:radio", this.fieldset);
        this.enterCredentials = this.credentials.filter("[value=enter]");
        this.replayCredentials = this.credentials.filter("[value=replay]");
        this.credentials.change($.proxy(function() {
            var enabled = this.enterCredentials.is(":checked");
            this.username.textbox(enabled ? "enable" : "disable").textbox("isValid");
            this.password.textbox(enabled ? "enable" : "disable");
        }, this));

        this.username = $("input[name=username]", this.fieldset).textbox({required: true, validType: "proxy_username_nonempty", missingMessage: window.R.string.PROXIES_ERROR_BAD_USER, width: "50%"});
        this.password = $("input[name=userpwd]", this.fieldset).textbox({type: "password", width: "50%"});

        this.passive = $("input[name=passivemode]:checkbox", this.fieldset);
        this.remoteDirectory = $("input[name=remotedirectory]:radio", this.fieldset).change($.proxy(function() {
            this.remoteDirectoryPath.textbox(this.isRemoteDirectory() ? "enable" : "disable");
        }, this));
        this.remoteDirectoryPath = $("input[name=remotepath]", this.fieldset).textbox({width: "60%"});

        this.maxAge = $("input[name=maxage]:checkbox", this.fieldset);
        this.maxAge.change($.proxy(function() {
            var enabled = this.maxAge.is(":checked");
            this.ttl.numberspinner(enabled ? "enable" : "disable").numberspinner(enabled ? "enableValidation" : "disableValidation")
        }, this));
        this.ttl = $("input[name=ttl]", this.fieldset).numberspinner({required: true, disabled: true, min: 1, max: 1000, width: 70});

        initializing = false;
    },

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

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

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

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

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

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

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

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

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

    setKeyUsage: function(values) {
        this.keyUsage = $.extend({}, values);
    },

    setDefaultPorts: function(values) {
        this.defaultPorts = $.extend({}, values);
    },

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

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

    isReplayCredentials: function() {
        return this.replayCredentials.is(":checked");
    },

    getUsername: function() {
        return this.enterCredentials.is(":checked") ? this.username.textbox("getValue") : null;
    },

    setUsername: function(value) {
        if (value != null) {
            this.username.textbox("setValue", value);
            this.enterCredentials.prop("checked", true).change();
        } else {
            this.replayCredentials.prop("checked", true).change();
        }
    },

    getPassword: function() {
        return this.enterCredentials.is(":checked") ? this.password.textbox("getValue") : null;
    },

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

    getHostKey: function () {
        return this.useHostKey.is(":checked:not(:disabled)") ? this.hostKey.combobox("getValue") : null;
    },

    setHostKey: function (value) {
        this.useHostKey.prop("checked", value != null).change();
        if (value != null) {
            this.hostKey.combobox("setValue", value);
        }
    },

    setHostKeys: function (values) {
        this.hostKey.combobox("loadData", values);
    },

    isUsePassiveMode: function() {
        return this.passive.is(":checked");
    },

    setUsePassiveMode: function(value) {
        this.passive.prop("checked", !!value);
    },

    isRemoteDirectory: function() {
        return this.remoteDirectory.filter("[value=remote]").is(":checked");
    },

    setRemoteDirectory: function(value) {
        this.remoteDirectory.filter(!!value ? "[value=remote]" : ":not([value=remote])").first().prop("checked", true).change();
    },

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

    setRemoteDirectoryPath: function(value) {
        this.remoteDirectoryPath.textbox("setValue", value);
        this.setRemoteDirectory(value && value.length != 0);
    },

    getMaxAge: function() {
        return this.maxAge.is(":checked") ? this.ttl.numberspinner("getValue") * this.TIMEOUT_FACTOR : null;
    },

    setMaxAge: function(value) {
        value = parseInt(value);
        this.maxAge.prop("checked", !isNaN(value)).change();
        this.ttl.numberspinner("setValue", !isNaN(value) ? value / this.TIMEOUT_FACTOR : this.DEFAULT_MAX_AGE);
    },

    show: function (listener) {
        this._super(listener || jscape.domain.FtpReverseProxyDialog.LISTENER);
        this.remoteDirectory.change();
        this._adjustSecurityMode(this.getConnectionType());
    },

    _onClick$ClientKeyButton: function () {
        this.listener.onSelectClientKey();
    },

    _adjustSecurityMode: function (mode) {
        var enabled = !!this.keyUsage[mode];
        this.useHostKey.prop("disabled", !enabled).change();
        this.clientKeyButton.linkbutton(enabled ? "enable" : "disable");

        var port = parseInt(this.defaultPorts[mode]);
        if (!isNaN(port)) {
            this.port.numberspinner("setValue", port);
        }
    }
});
jscape.domain.FtpReverseProxyDialog.LISTENER = $.extend({}, jscape.domain.ReverseProxyDialog.LISTENER, {
    onSelectClientKey: $.noop
});

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

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

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

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

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

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


/** @class */
jscape.domain.AddSftpReverseProxyController = jscape.domain.BaseReverseProxyController.extend(
    /** @lends {jscape.domain.AddSftpReverseProxyController.prototype} */
{
    DEFAULTS: {port: 22, timeout: 1000, maxAge: 10 * 60 * 1000, tcpNoDelay: true},

    /** @override */
    _setupDialog: function() {
        var dialog = new jscape.domain.AddSftpReverseProxyDialog();
        dialog.setPort(this.DEFAULTS.port);
        dialog.setTimeout(this.DEFAULTS.timeout);
        dialog.setTcpNoDelay(this.DEFAULTS.tcpNoDelay);
        dialog.setUsername("");
        dialog.setPassword("");
        dialog.setRemoteDirectory(true);
        dialog.setDebugDirectory(null);
        dialog.setMaxAge(this.DEFAULTS.maxAge);
        this.managementService.getDomainTags(this.domainName).done(function (tags) { dialog.setAvailableTags(tags); });
        this._loadHostKeys().done(function(keys) { dialog.setHostKeys(keys); });
        return dialog;
    },

    /** @override */
    _createDescriptor: function (dialog) {
        return jscape.ResourceDescriptor.sftp(dialog.getName(),
                                              dialog.getHost(),
                                              dialog.getPort(),
                                              dialog.getTimeout(),
                                              dialog.getTcpNoDelay(),
                                              dialog.isUseAdaptiveMode(),
                                              dialog.isStartSubsystemReplyRequired(),
                                              dialog.getUsername(),
                                              dialog.getPassword(),
                                              dialog.isReplayCredentials(),
                                              this.clientKeyProvider,
                                              dialog.getHostKey() != null ? new jscape.ServerKeyProvider(dialog.getHostKey()) : null,
                                              dialog.isRemoteDirectory() ? jscape.RemoteDirectory.remote(dialog.getRemoteDirectoryPath()) : jscape.RemoteDirectory.local(),
                                              dialog.getDebugDirectory(),
                                              dialog.getMaxAge(),
                                              dialog.getTags());
    }
});

/** @class */
jscape.domain.EditSftpReverseProxyController = jscape.domain.BaseReverseProxyController.extend(
    /** @lends {jscape.domain.EditSftpReverseProxyController.prototype} */
{
    descriptor: null,

    /** @override */
    start: function(listener, managementService, domainName, descriptor) {
        this.descriptor = descriptor;
        return this._super(listener, managementService, domainName, descriptor.keyProvider);
    },

    /** @override */
    _setupDialog: function() {
        var dialog = new jscape.domain.EditSftpReverseProxyDialog();
        var descriptor = this.descriptor;
        if (descriptor) {
            dialog.setName(descriptor.name);
            dialog.setHost(descriptor.host);
            dialog.setPort(descriptor.port);
            dialog.setTimeout(descriptor.timeout);
            dialog.setTcpNoDelay(descriptor.tcpNoDelayEnabled);
            dialog.setUsername(descriptor.username);
            dialog.setPassword(descriptor.password);
            dialog.setUseAdaptiveMode(descriptor.useAdaptiveConnection);
            dialog.setStartSubsystemReplyRequired(descriptor.startSubsystemReplyRequired);
            dialog.setRemoteDirectoryPath(descriptor.remoteDirectory.path);
            dialog.setRemoteDirectory(jscape.RemoteDirectory.Type.LOCAL != descriptor.remoteDirectory.type);
            dialog.setDebugDirectory(descriptor.logDirectory);
            dialog.setMaxAge(descriptor.timeToLive);
        }
        this.managementService.getDomainTags(this.domainName)
                .done(function (tags) {
                          dialog.setAvailableTags(tags);
                          descriptor && dialog.setTags(descriptor.tags);
                      });
        this._loadHostKeys()
                .done(function (keys) {
                          dialog.setHostKeys(keys);
                          descriptor && dialog.setHostKey(descriptor.hostKeyProvider ? descriptor.hostKeyProvider.keyAlias : null);
                      });
        return dialog;
    },

    /** @override */
    _createDescriptor: function (dialog) {
        return jscape.ResourceDescriptor.sftp(this.descriptor.name,
                                              dialog.getHost(),
                                              dialog.getPort(),
                                              dialog.getTimeout(),
                                              dialog.getTcpNoDelay(),
                                              dialog.isUseAdaptiveMode(),
                                              dialog.isStartSubsystemReplyRequired(),
                                              dialog.getUsername(),
                                              dialog.getPassword(),
                                              dialog.isReplayCredentials(),
                                              this.clientKeyProvider,
                                              dialog.getHostKey() != null ? new jscape.ServerKeyProvider(dialog.getHostKey()) : null,
                                              dialog.isRemoteDirectory() ? jscape.RemoteDirectory.remote(dialog.getRemoteDirectoryPath()) : jscape.RemoteDirectory.local(),
                                              dialog.getDebugDirectory(),
                                              dialog.getMaxAge(),
                                              dialog.getTags());
    }
});

/** @class */
jscape.domain.SftpReverseProxyDialog = jscape.domain.ReverseProxyDialog.extend(
    /** @lends {jscape.domain.SftpReverseProxyDialog.prototype} */
{
    /** @cons */
    TIMEOUT_FACTOR: 60 * 1000,
    DEFAULT_MAX_AGE: 10,

    /** @constructor */
    initialize: function(dialog) {
        this._super(dialog);

        this.host = $("input[name=host]", this.fieldset).textbox({required: true, validType: "non_empty", missingMessage: window.R.string.PROXIES_ERROR_BAD_HOST, invalidMessage: window.R.string.PROXIES_ERROR_BAD_HOST, width: "60%"});
        this.port = $("input[name=port]", this.fieldset).numberspinner({required: true, min: 1, max: 65535, width: 100});
        this.timeout = $("input[name=timeout]", this.fieldset).numberspinner({required: true, min: 1, max: 60, width: 60});
        this.tcpNoDelay = $("input[name=tcpnodelay]:checkbox", this.fieldset);

        this.useHostKey = $("input[name=usehostkey]:checkbox", this.fieldset).prop("disabled", true);
        this.useHostKey.change($.proxy(function() { this.hostKey.combobox(this.useHostKey.is(":checked:not(:disabled)") ? "enable" : "disable"); }, this));
        this.hostKey = $("select[name=hostkey]", this.fieldset);
        this.hostKey.combobox({editable: false, disabled: true, width: 170, panelHeight: "auto", panelMaxHeight: 150, onLoadSuccess: $.proxy(function(data) {
            this.useHostKey.prop("disabled", data.length == 0);
            if (data.length != 0) {
                this.hostKey.combobox("select", data[0].value);
            }
        }, this)});
        this.clientKeyButton = $("a[role=button][name=selectclientkey]", this.fieldset).linkbutton({onClick: $.proxy(this._onClick$ClientKeyButton, this)});

        this.credentials = $("input[name=credentials]:radio", this.fieldset);
        this.enterCredentials = this.credentials.filter("[value=enter]");
        this.replayCredentials = this.credentials.filter("[value=replay]");
        this.credentials.change($.proxy(function() {
            var enabled = this.enterCredentials.is(":checked");
            this.username.textbox(enabled ? "enable" : "disable").textbox(enabled ? "enableValidation" : "disableValidation");
            this.password.textbox(enabled ? "enable" : "disable");
        }, this));

        this.username = $("input[name=username]", this.fieldset).textbox({required: true, validType: "proxy_username_nonempty", missingMessage: window.R.string.PROXIES_ERROR_BAD_USER, width: "50%"});
        this.password = $("input[name=userpwd]", this.fieldset).textbox({type: "password", width: "50%"});

        this.useAdaptiveMode = $("input[name=adaptivemode]:checkbox");
        this.startSubsystemReply = $("input[name=startsubsystemreply]:checkbox");
        this.remoteDirectory = $("input[name=remotedirectory]:radio", this.fieldset).change($.proxy(function() {
            this.remoteDirectoryPath.textbox(this.isRemoteDirectory() ? "enable" : "disable");
        }, this));
        this.remoteDirectoryPath = $("input[name=remotepath]", this.fieldset).textbox({width: "60%"});

        this.maxAge = $("input[name=maxage]:checkbox", this.fieldset);
        this.maxAge.change($.proxy(function() {
            var enabled = this.maxAge.is(":checked");
            this.ttl.numberspinner(enabled ? "enable" : "disable").numberspinner(enabled ? "enableValidation" : "disableValidation")
        }, this));
        this.ttl = $("input[name=ttl]", this.fieldset).numberspinner({required: true, disabled: true, min: 1, max: 1000, width: 70});
    },

    getName: function() {
        throw "Abstract method.";
    },

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

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

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

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

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

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

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

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

    isReplayCredentials: function() {
        return this.replayCredentials.is(":checked");
    },

    getUsername: function() {
        return this.enterCredentials.is(":checked") ? this.username.textbox("getValue") : null;
    },

    setUsername: function(value) {
        if (value != null) {
            this.username.textbox("setValue", value);
            this.enterCredentials.prop("checked", true).change();
        } else {
            this.replayCredentials.prop("checked", true).change();
        }
    },

    getPassword: function() {
        return this.enterCredentials.is(":checked") ? this.password.textbox("getValue") : null;
    },

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

    getHostKey: function () {
        return this.useHostKey.is(":checked:not(:disabled)") ? this.hostKey.combobox("getValue") : null;
    },

    setHostKey: function (value) {
        this.useHostKey.prop("checked", value != null).change();
        if (value != null) {
            this.hostKey.combobox("setValue", value);
        }
    },

    setHostKeys: function (values) {
        this.hostKey.combobox("loadData", values);
    },

    isUseAdaptiveMode: function() {
        return this.useAdaptiveMode.is(":checked");
    },

    setUseAdaptiveMode: function(value) {
        this.useAdaptiveMode.prop("checked", !!value);
    },

    isStartSubsystemReplyRequired: function() {
        return this.startSubsystemReply.is(":checked");
    },

    setStartSubsystemReplyRequired: function(value) {
        this.startSubsystemReply.prop("checked", !!value);
    },

    isRemoteDirectory: function() {
        return this.remoteDirectory.filter("[value=remote]").is(":checked");
    },

    setRemoteDirectory: function(value) {
        this.remoteDirectory.filter(!!value ? "[value=remote]" : ":not([value=remote])").first().prop("checked", true).change();
    },

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

    setRemoteDirectoryPath: function(value) {
        this.remoteDirectoryPath.textbox("setValue", value);
        this.setRemoteDirectory(value && value.length != 0);
    },

    getMaxAge: function() {
        return this.maxAge.is(":checked") ? this.ttl.numberspinner("getValue") * this.TIMEOUT_FACTOR : null;
    },

    setMaxAge: function(value) {
        value = parseInt(value);
        this.maxAge.prop("checked", !isNaN(value)).change();
        this.ttl.numberspinner("setValue", !isNaN(value) ? value / this.TIMEOUT_FACTOR : this.DEFAULT_MAX_AGE);
    },

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

    _onClick$ClientKeyButton: function () {
        this.listener.onSelectClientKey();
    }
});
jscape.domain.SftpReverseProxyDialog.LISTENER = $.extend({}, jscape.domain.ReverseProxyDialog.LISTENER, {
    onSelectClientKey: $.noop
});

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

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

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

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

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

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


/** @class */
jscape.domain.AddAftpReverseProxyController = jscape.domain.BaseReverseProxyController.extend(
    /** @lends {jscape.domain.AddAftpReverseProxyController.prototype} */
{
    SECURITY_MODE_KEY_USAGE: {'NO_PROTECTION': false, 'FULL_TIME_PROTECTED': true, 'AUTHENTICATION_PROTECTED': true},
    DEFAULTS: {port: 3000, timeout: 1000, maxAge: 10 * 60 * 1000, tcpNoDelay: true},

    /** @override */
    _setupDialog: function () {
        var dialog = new jscape.domain.AddAftpReverseProxyDialog();
        dialog.setPort(this.DEFAULTS.port);
        dialog.setTimeout(this.DEFAULTS.timeout);
        dialog.setTcpNoDelay(this.DEFAULTS.tcpNoDelay);
        dialog.setKeyUsage(this.SECURITY_MODE_KEY_USAGE);
        dialog.setUsername("");
        dialog.setPassword("");
        dialog.setRemoteDirectory(true);
        dialog.setDebugDirectory(null);
        dialog.setMaxAge(this.DEFAULTS.maxAge);
        this.managementService.getDomainTags(this.domainName).done(function (tags) { dialog.setAvailableTags(tags); });
        this._loadHostKeys().done(function(keys) { dialog.setHostKeys(keys); });
        return dialog;
    },

    _createDescriptor: function (dialog) {
        return jscape.ResourceDescriptor.aftp(dialog.getName(),
                                              dialog.getHost(),
                                              dialog.getPort(),
                                              dialog.getTimeout(),
                                              dialog.getTcpNoDelay(),
                                              dialog.getSecurityMode(),
                                              dialog.getUsername(),
                                              dialog.getPassword(),
                                              dialog.isReplayCredentials(),
                                              this.clientKeyProvider,
                                              dialog.getHostKey() != null ? new jscape.ServerKeyProvider(dialog.getHostKey()) : null,
                                              dialog.isRemoteDirectory() ? jscape.RemoteDirectory.remote(dialog.getRemoteDirectoryPath()) : jscape.RemoteDirectory.local(),
                                              dialog.getDebugDirectory(),
                                              dialog.getMaxAge(),
                                              dialog.getTags());
    }
});

/** @class */
jscape.domain.EditAftpReverseProxyController = jscape.domain.BaseReverseProxyController.extend(
    /** @lends {jscape.domain.EditAftpReverseProxyController.prototype} */
{
    /** @const */
    SECURITY_MODE_KEY_USAGE: {'NO_PROTECTION': false, 'FULL_TIME_PROTECTED': true, 'AUTHENTICATION_PROTECTED': true},

    /** @override */
    start: function(listener, managementService, domainName, descriptor) {
        this.descriptor = descriptor;
        return this._super(listener, managementService, domainName, descriptor.keyProvider);
    },

    /** @override */
    _setupDialog: function () {
        var dialog = new jscape.domain.EditAftpReverseProxyDialog();
        var descriptor = this.descriptor;
        if (descriptor) {
            dialog.setName(descriptor.name);
            dialog.setHost(descriptor.host);
            dialog.setPort(descriptor.port);
            dialog.setTimeout(descriptor.timeout);
            dialog.setTcpNoDelay(descriptor.tcpNoDelayEnabled);
            dialog.setSecurityMode(descriptor.securityMode);
            dialog.setKeyUsage(this.SECURITY_MODE_KEY_USAGE);
            dialog.setUsername(descriptor.username);
            dialog.setPassword(descriptor.password);
            dialog.setRemoteDirectoryPath(descriptor.remoteDirectory.path);
            dialog.setRemoteDirectory(jscape.RemoteDirectory.Type.LOCAL != descriptor.remoteDirectory.type);
            dialog.setDebugDirectory(descriptor.logDirectory);
            dialog.setMaxAge(descriptor.timeToLive);
        }
        this.managementService.getDomainTags(this.domainName)
                .done(function (tags) {
                          dialog.setAvailableTags(tags);
                          descriptor && dialog.setTags(descriptor.tags);
                      });
        this._loadHostKeys()
                .done(function (keys) {
                          dialog.setHostKeys(keys);
                          descriptor && dialog.setHostKey(descriptor.hostKeyProvider ? descriptor.hostKeyProvider.keyAlias : null);
                      });
        return dialog;
    },

    _createDescriptor: function (dialog) {
        return jscape.ResourceDescriptor.aftp(this.descriptor.name,
                                              dialog.getHost(),
                                              dialog.getPort(),
                                              dialog.getTimeout(),
                                              dialog.getTcpNoDelay(),
                                              dialog.getSecurityMode(),
                                              dialog.getUsername(),
                                              dialog.getPassword(),
                                              dialog.isReplayCredentials(),
                                              this.clientKeyProvider,
                                              dialog.getHostKey() != null ? new jscape.ServerKeyProvider(dialog.getHostKey()) : null,
                                              dialog.isRemoteDirectory() ? jscape.RemoteDirectory.remote(dialog.getRemoteDirectoryPath()) : jscape.RemoteDirectory.local(),
                                              dialog.getDebugDirectory(),
                                              dialog.getMaxAge(),
                                              dialog.getTags());
    }
});

/** @class */
jscape.domain.AftpReverseProxyDialog = jscape.domain.ReverseProxyDialog.extend(
    /** @lends {jscape.domain.AftpReverseProxyDialog.prototype} */
{
    /** @cons */
    TIMEOUT_FACTOR: 60 * 1000,
    DEFAULT_MAX_AGE: 10,

    keyUsage: {},

    /** @constructor */
    initialize: function(dialog) {
        this._super(dialog);

        var initializing = true;

        this.host = $("input[name=host]", this.fieldset).textbox({required: true, validType: "non_empty", missingMessage: window.R.string.PROXIES_ERROR_BAD_HOST, invalidMessage: window.R.string.PROXIES_ERROR_BAD_HOST, width: "60%"});
        this.port = $("input[name=port]", this.fieldset).numberspinner({required: true, min: 1, max: 65535, width: 100});
        this.timeout = $("input[name=timeout]", this.fieldset).numberspinner({required: true, min: 1, max: 60, width: 60});
        this.tcpNoDelay = $("input[name=tcpnodelay]:checkbox", this.fieldset);
        this.security = $("select[name=security]", this.fieldset).combobox({required: true, editable: false, onChange: $.proxy(function(val) { if (!initializing) { this._adjustSecurityMode(val); }}, this), width: 210, panelHeight: "auto"});

        this.useHostKey = $("input[name=usehostkey]:checkbox", this.fieldset).prop("disabled", true);
        this.useHostKey.change($.proxy(function() { this.hostKey.combobox(this.useHostKey.is(":checked:not(:disabled)") ? "enable" : "disable"); }, this));
        this.hostKey = $("select[name=hostkey]", this.fieldset);
        this.hostKey.combobox({editable: false, disabled: true, width: 170, panelHeight: "auto", panelMaxHeight: 150, onLoadSuccess: $.proxy(function(data) {
            this.useHostKey.prop("disabled", data.length == 0);
            if (data.length != 0) {
                this.hostKey.combobox("select", data[0].value);
            }
        }, this)});
        this.clientKeyButton = $("a[role=button][name=selectclientkey]", this.fieldset).linkbutton({onClick: $.proxy(this._onClick$ClientKeyButton, this)});

        this.credentials = $("input[name=credentials]:radio", this.fieldset);
        this.enterCredentials = this.credentials.filter("[value=enter]");
        this.replayCredentials = this.credentials.filter("[value=replay]");
        this.credentials.change($.proxy(function() {
            var enabled = this.enterCredentials.is(":checked");
            this.username.textbox(enabled ? "enable" : "disable").textbox(enabled ? "enableValidation" : "disableValidation");
            this.password.textbox(enabled ? "enable" : "disable");
        }, this));

        this.username = $("input[name=username]", this.fieldset).textbox({required: true, validType: "proxy_username_nonempty", missingMessage: window.R.string.PROXIES_ERROR_BAD_USER, width: "40%"});
        this.password = $("input[name=userpwd]", this.fieldset).textbox({type: "password", width: "40%"});

        this.remoteDirectory = $("input[name=remotedirectory]:radio", this.fieldset).change($.proxy(function() {
            this.remoteDirectoryPath.textbox(this.isRemoteDirectory()? "enable" : "disable");
        }, this));
        this.remoteDirectoryPath = $("input[name=remotepath]", this.fieldset).textbox({width: "60%"});

        this.maxAge = $("input[name=maxage]:checkbox", this.fieldset);
        this.maxAge.change($.proxy(function() {
            var enabled = this.maxAge.is(":checked");
            this.ttl.numberspinner(enabled ? "enable" : "disable").numberspinner(enabled ? "enableValidation" : "disableValidation")
        }, this));
        this.ttl = $("input[name=ttl]", this.fieldset).numberspinner({required: true, disabled: true, min: 1, max: 1000, width: 70});

        initializing = false;
    },

    getName: function() {
        throw "Abstract method.";
    },

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

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

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

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

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

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

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

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

    setKeyUsage: function(keyUsage) {
        this.keyUsage = $.extend({}, keyUsage);
    },

    getSecurityMode: function() {
        return this.security.combobox("getValue");
    },

    setSecurityMode: function(value) {
        this.security.combobox("setValue", value);
    },

    isReplayCredentials: function() {
        return this.replayCredentials.is(":checked");
    },

    getUsername: function() {
        return this.enterCredentials.is(":checked") ? this.username.textbox("getValue") : null;
    },

    setUsername: function(value) {
        if (value != null) {
            this.username.textbox("setValue", value);
            this.enterCredentials.prop("checked", true).change();
        } else {
            this.replayCredentials.prop("checked", true).change();
        }
    },

    getPassword: function() {
        return this.enterCredentials.is(":checked") ? this.password.textbox("getValue") : null;
    },

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

    getHostKey: function () {
        return this.useHostKey.is(":checked:not(:disabled)") ? this.hostKey.combobox("getValue") : null;
    },

    setHostKey: function (value) {
        this.useHostKey.prop("checked", value != null).change();
        if (value != null) {
            this.hostKey.combobox("setValue", value);
        }
    },

    setHostKeys: function (values) {
        this.hostKey.combobox("loadData", values);
    },

    isRemoteDirectory: function() {
        return this.remoteDirectory.filter("[value=remote]").is(":checked");
    },

    setRemoteDirectory: function(value) {
        this.remoteDirectory.filter(!!value ? "[value=remote]" : ":not([value=remote])").first().prop("checked", true).change();
    },

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

    setRemoteDirectoryPath: function(value) {
        this.remoteDirectoryPath.textbox("setValue", value);
        this.setRemoteDirectory(value && value.length != 0);
    },

    getMaxAge: function() {
        return this.maxAge.is(":checked") ? this.ttl.numberspinner("getValue") * this.TIMEOUT_FACTOR : null;
    },

    setMaxAge: function(value) {
        value = parseInt(value);
        this.maxAge.prop("checked", !isNaN(value)).change();
        this.ttl.numberspinner("setValue", !isNaN(value) ? value / this.TIMEOUT_FACTOR : this.DEFAULT_MAX_AGE);
    },

    show: function (listener) {
        this._super(listener || jscape.domain.AftpReverseProxyDialog.LISTENER);
        this._adjustSecurityMode(this.getSecurityMode());
    },

    _onClick$ClientKeyButton: function () {
        this.listener.onSelectClientKey();
    },

    _adjustSecurityMode: function (mode) {
        var enabled = !!this.keyUsage[mode];
        this.useHostKey.prop("disabled", !enabled).change();
        this.clientKeyButton.linkbutton(enabled ? "enable" : "disable");
    }
});
jscape.domain.AftpReverseProxyDialog.LISTENER = $.extend({}, jscape.domain.ReverseProxyDialog.LISTENER, {
    onSelectClientKey: $.noop
});

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

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

    /** @override */
    getName: function() {
        return this.name.textbox("getValue");
    }
});

/** @class */
jscape.domain.EditAftpReverseProxyDialog = jscape.domain.AftpReverseProxyDialog.extend(
    /** @lends {jscape.domain.EditAftpReverseProxyDialog.prototype} */
{
    proxyName: "",

    /** @constructor */
    initialize: function() {
        this._super($("#d-proxy-edit-aftp"));

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

    /** @override */
    getName: function() {
        return this.proxyName;
    },

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

/** @class */
jscape.domain.AddWebDavReverseProxyController = jscape.domain.BaseReverseProxyController.extend(
    /** @lends {jscape.domain.AddWebDavReverseProxyController.prototype} */
{
    /** @const */
    DEFAULT_PORT: 80,

    /** @override */
    _setupDialog: function () {
        var dialog = new jscape.domain.AddWebDavReverseProxyDialog();
        dialog.setPort(this.DEFAULT_PORT);
        dialog.setUsername("");
        dialog.setPassword("");
        dialog.setPath("/");
        dialog.setRemoteDirectory(true);
        dialog.setDebugDirectory(null);
        this.managementService.getDomainTags(this.domainName).done(function (tags) { dialog.setAvailableTags(tags); });
        return dialog;
    },

    _createDescriptor: function (dialog) {
        return jscape.ResourceDescriptor.webdav(dialog.getName(),
                                                dialog.getHost(),
                                                dialog.getPort(),
                                                dialog.getDomain(),
                                                dialog.getPath(),
                                                dialog.isUseSsl(),
                                                dialog.getUsername(),
                                                dialog.getPassword(),
                                                dialog.isReplayCredentials(),
                                                dialog.isRemoteDirectory() ? jscape.RemoteDirectory.remote(dialog.getRemoteDirectoryPath()) : jscape.RemoteDirectory.local(),
                                                dialog.getDebugDirectory(),
                                                dialog.getTags());
    }
});

/** @class */
jscape.domain.EditWebDavReverseProxyController = jscape.domain.BaseReverseProxyController.extend(
    /** @lends {jscape.domain.EditWebDavReverseProxyController.prototype} */
{
    /** @override */
    start: function(listener, managementService, domainName, descriptor) {
        this.descriptor = descriptor;
        return this._super(listener, managementService, domainName);
    },

    /** @override */
    _setupDialog: function () {
        var dialog = new jscape.domain.EditWebDavReverseProxyDialog();
        var descriptor = this.descriptor;
        if (descriptor) {
            dialog.setName(descriptor.name);
            dialog.setHost(descriptor.host);
            dialog.setPort(descriptor.port);
            dialog.setUsername(descriptor.username);
            dialog.setPassword(descriptor.password);
            dialog.setPath(descriptor.path);
            dialog.setDomain(descriptor.domain);
            dialog.setUseSsl(descriptor.useSsl);
            dialog.setRemoteDirectoryPath(descriptor.remoteDirectory.path);
            dialog.setRemoteDirectory(jscape.RemoteDirectory.Type.LOCAL != descriptor.remoteDirectory.type);
            dialog.setDebugDirectory(descriptor.logDirectory);
        }
        this.managementService.getDomainTags(this.domainName)
                .done(function (tags) {
                          dialog.setAvailableTags(tags);
                          descriptor && dialog.setTags(descriptor.tags);
                      });
        return dialog;
    },

    _createDescriptor: function (dialog) {
        return jscape.ResourceDescriptor.webdav(this.descriptor.name,
                                                dialog.getHost(),
                                                dialog.getPort(),
                                                dialog.getDomain(),
                                                dialog.getPath(),
                                                dialog.isUseSsl(),
                                                dialog.getUsername(),
                                                dialog.getPassword(),
                                                dialog.isReplayCredentials(),
                                                dialog.isRemoteDirectory() ? jscape.RemoteDirectory.remote(dialog.getRemoteDirectoryPath()) : jscape.RemoteDirectory.local(),
                                                dialog.getDebugDirectory(),
                                                dialog.getTags());
    }
});

/** @class */
jscape.domain.WebDavReverseProxyDialog = jscape.domain.ReverseProxyDialog.extend(
    /** @lends {jscape.domain.WebDavReverseProxyDialog.prototype} */
{
    /** @constructor */
    initialize: function(dialog) {
        this._super(dialog);

        this.host = $("input[name=host]", this.fieldset).textbox({required: true, validType: "non_empty", missingMessage: window.R.string.PROXIES_ERROR_BAD_HOST, invalidMessage: window.R.string.PROXIES_ERROR_BAD_HOST, width: "60%"});
        this.port = $("input[name=port]", this.fieldset).numberspinner({required: true, min: 1, max: 65535, width: 100});
        this.path = $("input[name=path]", this.fieldset).textbox({width: "50%"});
        this.domain = $("input[name=domain]", this.fieldset).textbox({width: "50%"});

        this.credentials = $("input[name=credentials]:radio", this.fieldset);
        this.enterCredentials = this.credentials.filter("[value=enter]");
        this.replayCredentials = this.credentials.filter("[value=replay]");
        this.credentials.change($.proxy(function() {
            var enabled = this.enterCredentials.is(":checked");
            this.username.textbox(enabled ? "enable" : "disable").textbox(enabled ? "enableValidation" : "disableValidation");
            this.password.textbox(enabled ? "enable" : "disable");
        }, this));

        this.username = $("input[name=username]", this.fieldset).textbox({required: true, validType: "proxy_username_nonempty", missingMessage: window.R.string.PROXIES_ERROR_BAD_USER, width: "50%"});
        this.password = $("input[name=userpwd]", this.fieldset).textbox({type: "password", width: "50%"});

        this.useSsl = $("input[name=ssl]:checkbox", this.fieldset);
        this.remoteDirectory = $("input[name=remotedirectory]:radio", this.fieldset).change($.proxy(function() {
            this.remoteDirectoryPath.textbox(this.isRemoteDirectory() ? "enable" : "disable");
        }, this));
        this.remoteDirectoryPath = $("input[name=remotepath]", this.fieldset).textbox({width: "60%"});
    },

    getName: function() {
        throw "Abstract method.";
    },

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

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

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

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

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

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

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

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

    isReplayCredentials: function() {
        return this.replayCredentials.is(":checked");
    },

    getUsername: function() {
        return this.enterCredentials.is(":checked") ? this.username.textbox("getValue") : null;
    },

    setUsername: function(value) {
        if (value != null) {
            this.username.textbox("setValue", value);
            this.enterCredentials.prop("checked", true).change();
        } else {
            this.replayCredentials.prop("checked", true).change();
        }
    },

    getPassword: function() {
        return this.enterCredentials.is(":checked") ? this.password.textbox("getValue") : null;
    },

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

    isUseSsl: function() {
        return this.useSsl.is(":checked");
    },

    setUseSsl: function(value) {
        this.useSsl.prop("checked", !!value);
    },

    isRemoteDirectory: function() {
        return this.remoteDirectory.filter("[value=remote]").is(":checked");
    },

    setRemoteDirectory: function(value) {
        this.remoteDirectory.filter(!!value ? "[value=remote]" : ":not([value=remote])").first().prop("checked", true).change();
    },

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

    setRemoteDirectoryPath: function(value) {
        this.remoteDirectoryPath.textbox("setValue", value);
        this.setRemoteDirectory(value && value.length != 0);
    }
});

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

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

    /** @override */
    getName: function() {
        return this.name.textbox("getValue");
    }
});

/** @class */
jscape.domain.EditWebDavReverseProxyDialog = jscape.domain.WebDavReverseProxyDialog.extend(
    /** @lends {jscape.domain.EditWebDavReverseProxyDialog.prototype} */
{
    proxyName: "",

    /** @constructor */
    initialize: function() {
        this._super($("#d-proxy-edit-webdav"));

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

    /** @override */
    getName: function() {
        return this.proxyName;
    },

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

/** @class */
jscape.domain.AddRestReverseProxyController = jscape.domain.BaseReverseProxyController.extend(
    /** @lends {jscape.domain.AddRestReverseProxyController.prototype} */
{
    /** @const */
    DEFAULT_PORT: 80,
    DEFAULT_TIMEOUT: 1000,
    DEFAULT_MAX_AGE: 10 * 60 * 1000,

    /** @override */
    _setupDialog: function () {
        var dialog = new jscape.domain.AddRestReverseProxyDialog();
        dialog.setPort(this.DEFAULT_PORT);
        dialog.setTimeout(this.DEFAULT_TIMEOUT);
        dialog.setUsername("");
        dialog.setPassword("");
        dialog.setRemoteDirectory(true);
        dialog.setDebugDirectory(null);
        dialog.setMaxAge(this.DEFAULT_MAX_AGE);
        this.managementService.getDomainTags(this.domainName).done(function (tags) { dialog.setAvailableTags(tags); });
        return dialog;
    },

    _createDescriptor: function (dialog) {
        return jscape.ResourceDescriptor.rest(dialog.getName(),
                                              dialog.getHost(),
                                              dialog.getPort(),
                                              dialog.getTimeout(),
                                              dialog.isSslRequired(),
                                              dialog.getDomain(),
                                              dialog.getUsername(),
                                              dialog.getPassword(),
                                              dialog.isReplayCredentials(),
                                              dialog.getKeyFile().length != 0 ? new jscape.FileKeyProvider(dialog.getKeyFile(), dialog.getKeyFilePassword()) : null,
                                              dialog.isRemoteDirectory() ? jscape.RemoteDirectory.remote(dialog.getRemoteDirectoryPath()) : jscape.RemoteDirectory.local(),
                                              dialog.getDebugDirectory(),
                                              dialog.getMaxAge(),
                                              dialog.getTags());
    }
});

/** @class */
jscape.domain.EditRestReverseProxyController = jscape.domain.BaseReverseProxyController.extend(
    /** @lends {jscape.domain.EditRestReverseProxyController.prototype} */
{
    /** @override */
    start: function(listener, managementService, domainName, descriptor) {
        this.descriptor = descriptor;
        return this._super(listener, managementService, domainName);
    },

    /** @override */
    _setupDialog: function () {
        var dialog = new jscape.domain.EditRestReverseProxyDialog();
        var descriptor = this.descriptor;
        if (descriptor) {
            dialog.setName(descriptor.name);
            dialog.setHost(descriptor.host);
            dialog.setPort(descriptor.port);
            dialog.setTimeout(descriptor.timeout);
            dialog.setSslRequired(descriptor.sslRequired);
            dialog.setDomain(descriptor.domain);
            dialog.setUsername(descriptor.username);
            dialog.setPassword(descriptor.password);
            if (descriptor.keyProvider) {
                dialog.setKeyFile(descriptor.keyProvider.file);
                dialog.setKeyFilePassword(descriptor.keyProvider.filePassword);
            }
            dialog.setRemoteDirectoryPath(descriptor.remoteDirectory.path);
            dialog.setRemoteDirectory(jscape.RemoteDirectory.Type.LOCAL != descriptor.remoteDirectory.type);
            dialog.setDebugDirectory(descriptor.logDirectory);
            dialog.setMaxAge(descriptor.timeToLive);
        }
        this.managementService.getDomainTags(this.domainName)
                .done(function (tags) {
                          dialog.setAvailableTags(tags);
                          descriptor && dialog.setTags(descriptor.tags);
                      });
        return dialog;
    },

    _createDescriptor: function (dialog) {
        return jscape.ResourceDescriptor.rest(this.descriptor.name,
                                              dialog.getHost(),
                                              dialog.getPort(),
                                              dialog.getTimeout(),
                                              dialog.isSslRequired(),
                                              dialog.getDomain(),
                                              dialog.getUsername(),
                                              dialog.getPassword(),
                                              dialog.isReplayCredentials(),
                                              dialog.getKeyFile().length != 0 ? new jscape.FileKeyProvider(dialog.getKeyFile(), dialog.getKeyFilePassword()) : null,
                                              dialog.isRemoteDirectory() ? jscape.RemoteDirectory.remote(dialog.getRemoteDirectoryPath()) : jscape.RemoteDirectory.local(),
                                              dialog.getDebugDirectory(),
                                              dialog.getMaxAge(),
                                              dialog.getTags());
    }
});

/** @class */
jscape.domain.RestReverseProxyDialog = jscape.domain.ReverseProxyDialog.extend(
    /** @lends {jscape.domain.RestReverseProxyDialog.prototype} */
{
    /** @cons */
    TIMEOUT_FACTOR: 60 * 1000,

    /** @constructor */
    initialize: function(dialog) {
        this._super(dialog);

        this.host = $("input[name=host]", this.fieldset).textbox({required: true, validType: "non_empty", missingMessage: window.R.string.PROXIES_ERROR_BAD_HOST, invalidMessage: window.R.string.PROXIES_ERROR_BAD_HOST, width: "60%"});
        this.port = $("input[name=port]", this.fieldset).numberspinner({required: true, min: 1, max: 65535, width: 100});
        this.timeout = $("input[name=timeout]", this.fieldset).numberspinner({required: true, min: 1, max: 60, width: 60});
        this.sslRequired = $("input[name=ssl]:checkbox", this.fieldset);

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

        this.credentials = $("input[name=credentials]:radio", this.fieldset);
        this.enterCredentials = this.credentials.filter("[value=enter]");
        this.replayCredentials = this.credentials.filter("[value=replay]");
        this.credentials.change($.proxy(function() {
            var enabled = this.enterCredentials.is(":checked");
            this.username.textbox(enabled ? "enable" : "disable").textbox(enabled ? "enableValidation" : "disableValidation");
            this.password.textbox(enabled ? "enable" : "disable");
        }, this));

        this.username = $("input[name=username]", this.fieldset).textbox({required: true, validType: "proxy_username_nonempty", missingMessage: window.R.string.PROXIES_ERROR_BAD_USER, width: "50%"});
        this.password = $("input[name=userpwd]", this.fieldset).textbox({type: "password", width: "50%"});

        this.keyFile = $("input[name=keyfile]", this.fieldset).textbox({width : "50%"});
        this.keyFilePassword = $("input[name=keyfilepwd]", this.fieldset).textbox({type: "password", width: "50%"});
        this.keyFileBrowseButton = $("a[role=button][name=keyfilebrowse]", this.fieldset).linkbutton({onClick: $.proxy(this._onClick$KeyFileBrowseButton, this)});

        this.remoteDirectory = $("input[name=remotedirectory]:radio", this.fieldset).change($.proxy(function() {
            this.remoteDirectoryPath.textbox(this.isRemoteDirectory() ? "enable" : "disable");
        }, this));
        this.remoteDirectoryPath = $("input[name=remotepath]", this.fieldset).textbox({width: "60%"});

        this.maxAge = $("input[name=maxage]:checkbox", this.fieldset);
        this.maxAge.change($.proxy(function () {
            var enabled = this.maxAge.is(":checked");
            this.ttl.numberspinner(enabled ? "enable" : "disable").numberspinner(enabled ? "enableValidation" : "disableValidation");
        }, this));
        this.ttl = $("input[name=ttl]", this.fieldset).numberspinner({required: true, disabled: true, min: 1, max: 1000, width: 70});
    },

    getName: function() {
        throw "Abstract method.";
    },

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

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

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

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

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

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

    isSslRequired: function() {
        return this.sslRequired.is(":checked");
    },

    setSslRequired: function(value) {
        this.sslRequired.prop("checked", !!value);
    },

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

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

    isReplayCredentials: function() {
        return this.replayCredentials.is(":checked");
    },

    getUsername: function() {
        return this.enterCredentials.is(":checked") ? this.username.textbox("getValue") : null;
    },

    setUsername: function(value) {
        if (value != null) {
            this.username.textbox("setValue", value);
            this.enterCredentials.prop("checked", true).change();
        } else {
            this.replayCredentials.prop("checked", true).change();
        }
    },

    getPassword: function() {
        return this.enterCredentials.is(":checked") ? this.password.textbox("getValue") : null;
    },

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

    getKeyFile: function() {
        return this.keyFile.textbox("getValue").trim();
    },

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

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

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

    isRemoteDirectory: function() {
        return this.remoteDirectory.filter("[value=remote]").is(":checked");
    },

    setRemoteDirectory: function(value) {
        this.remoteDirectory.filter(!!value ? "[value=remote]" : ":not([value=remote])").first().prop("checked", true).change();
    },

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

    setRemoteDirectoryPath: function(value) {
        this.remoteDirectoryPath.textbox("setValue", value);
        this.setRemoteDirectory(value && value.length != 0);
    },

    getMaxAge: function () {
        return this.maxAge.is(":checked") ? this.ttl.numberspinner("getValue") * this.TIMEOUT_FACTOR : null;
    },

    setMaxAge: function (value) {
        value = parseInt(value);
        this.maxAge.prop("checked", !isNaN(value)).change();
        this.ttl.numberspinner("setValue", !isNaN(value) ? value / this.TIMEOUT_FACTOR : this.DEFAULT_MAX_AGE);
    },

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

    _onClick$KeyFileBrowseButton: function () {
        this.listener.onSelectKeyFile(this)
                .done($.proxy(function (value) {
                          this.keyFile.textbox("setValue", value)
                                  .textbox("textbox").select().focus();
                      }, this));
    }
});
jscape.domain.RestReverseProxyDialog.LISTENER = $.extend({}, jscape.domain.ReverseProxyDialog.LISTENER, {
    onSelectKeyFile: $.noop
});

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

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

    /** @override */
    getName: function() {
        return this.name.textbox("getValue");
    }
});

/** @class */
jscape.domain.EditRestReverseProxyDialog = jscape.domain.RestReverseProxyDialog.extend(
    /** @lends {jscape.domain.EditRestReverseProxyDialog.prototype} */
{
    proxyName: "",

    /** @constructor */
    initialize: function() {
        this._super($("#d-proxy-edit-rest"));

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

    /** @override */
    getName: function() {
        return this.proxyName;
    },

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

/** @class */
jscape.domain.AddAmazonS3ReverseProxyController = jscape.domain.BaseReverseProxyController.extend(
    /** @lends {jscape.domain.AddAmazonS3ReverseProxyController.prototype} */
{
    DEFAULT_REGION: "us-west-2",

    kmsKeys: {params: null, cache: null},

    onRefreshKmsKeys: function (dialog) {
        var descriptor = this._createDescriptor(dialog);
        var params = {u: descriptor.username, p: descriptor.password, r: descriptor.region};
        if (this.kmsKeys && this.kmsKeys.cache && Object._equals(params, this.kmsKeys.params)) {
            return $.Deferred().resolve(this.kmsKeys.cache);
        }
        return jscape.API.getReverseProxyAmazonKmsKeys(this.domainName, "amazons3", descriptor)
                .done($.proxy(function (keys) { this.kmsKeys = {params: params, cache: keys}; }, this));
    },

    /** @override */
    _setupDialog: function () {
        var dialog = new jscape.domain.AddAmazonS3ReverseProxyDialog();
        dialog.setUsername("");
        dialog.setPassword("");
        dialog.setRegion(this.DEFAULT_REGION);
        dialog.setRemoteDirectory(true);
        dialog.setDebugDirectory(null);
        this.managementService.getDomainTags(this.domainName).done(function (tags) { dialog.setAvailableTags(tags); });
        return dialog;
    },

    _createDescriptor: function (dialog) {
        return jscape.ResourceDescriptor.amazonS3(dialog.getName(),
                                                  dialog.getEncryptionType(),
                                                  dialog.getKmsKey(),
                                                  dialog.getUsername(),
                                                  dialog.getPassword(),
                                                  dialog.getAuthenticationType(),
                                                  dialog.getRegion(),
                                                  dialog.isRemoteDirectory() ? jscape.RemoteDirectory.remote(dialog.getRemoteDirectoryPath()) : jscape.RemoteDirectory.local(),
                                                  dialog.getDebugDirectory(),
                                                  dialog.getTags());
    }
});

/** @class */
jscape.domain.EditAmazonS3ReverseProxyController = jscape.domain.BaseReverseProxyController.extend(
    /** @lends {jscape.domain.EditAmazonS3ReverseProxyController.prototype} */
{
    kmsKeys: {params: null, cache: null},

    /** @override */
    start: function(listener, managementService, domainName, descriptor) {
        this.descriptor = descriptor;
        return this._super(listener, managementService, domainName);
    },

    onRefreshKmsKeys: function (dialog) {
        var descriptor = this._createDescriptor(dialog);
        var params = {u: descriptor.username, p: descriptor.password, r: descriptor.region};
        if (this.kmsKeys && this.kmsKeys.cache && Object._equals(params, this.kmsKeys.params)) {
            return $.Deferred().resolve(this.kmsKeys.cache);
        }
        return jscape.API.getReverseProxyAmazonKmsKeys(this.domainName, this.descriptor.name, descriptor)
                .done($.proxy(function (keys) { this.kmsKeys = {params: params, cache: keys}; }, this));
    },

    /** @override */
    _setupDialog: function () {
        var dialog = new jscape.domain.EditAmazonS3ReverseProxyDialog();
        var descriptor = this.descriptor;
        if (descriptor) {
            dialog.setName(descriptor.name);
            dialog.setEncryptionType("NONE" !== descriptor.encryptionType ? descriptor.encryptionType : null);
            dialog.setKmsKey(descriptor.kmsKeyId);
            dialog.setUsername(descriptor.username);
            dialog.setPassword(descriptor.password);
            dialog.setAuthenticationType(descriptor.authenticationType);
            dialog.setRegion(descriptor.region);
            dialog.setRemoteDirectoryPath(descriptor.remoteDirectory.path);
            dialog.setRemoteDirectory(jscape.RemoteDirectory.Type.LOCAL != descriptor.remoteDirectory.type);
            dialog.setDebugDirectory(descriptor.logDirectory);
        }
        this.managementService.getDomainTags(this.domainName)
                .done(function (tags) {
                          dialog.setAvailableTags(tags);
                          descriptor && dialog.setTags(descriptor.tags);
                      });
        return dialog;
    },

    _createDescriptor: function (dialog) {
        return jscape.ResourceDescriptor.amazonS3(this.descriptor.name,
                                                  dialog.getEncryptionType(),
                                                  dialog.getKmsKey(),
                                                  dialog.getUsername(),
                                                  dialog.getPassword(),
                                                  dialog.getAuthenticationType(),
                                                  dialog.getRegion(),
                                                  dialog.isRemoteDirectory()
                                                          ? jscape.RemoteDirectory.remote(dialog.getRemoteDirectoryPath())
                                                          : jscape.RemoteDirectory.local(),
                                                  dialog.getDebugDirectory(),
                                                  dialog.getTags());
    }
});

/** @class */
jscape.domain.AmazonS3ReverseProxyDialog = jscape.domain.ReverseProxyDialog.extend(
    /** @lends {jscape.domain.AmazonS3ReverseProxyDialog.prototype} */
{
    /** @constructor */
    initialize: function(dialog) {
        this._super(dialog);

        var initializing = true;

        this.useEncryption = $("input[name=encrypt]:checkbox", this.fieldset)
                .change($.proxy(function () { this.encryption.change(); }, this));
        this.encryption = $("input[name=encryption]:radio", this.fieldset);
        this.ecnryptionAwsKms = this.encryption.filter("[value=AWS_KMS_MANAGED_KEYS]");
        this.encryptionAwsKmsKey = $("select[name=kmskey]", this.fieldset).combobox({
                    required: true,
                    editable: false,
                    width: 220,
                    inputEvents: $.extend({}, $.fn.combobox.defaults.inputEvents, {focus: function (e) { $(e.data.target).combobox("reload"); }}),
                    onBeforeLoad: function() { return !initializing; },
                    loader: $.proxy(this._onLoad$KmsKeys, this)
                });
        this.encryption.change($.proxy(function () {
            if (this.useEncryption.is(":checked")) {
                this.encryption.each(function (_, input) { $(input).prop("disabled", false); });
                this.encryptionAwsKmsKey.combobox(this.ecnryptionAwsKms.is(":checked") ? "enable" : "disable");
            } else {
                this.encryption.each(function (_, input) { $(input).prop("disabled", true); });
                this.encryptionAwsKmsKey.combobox("disable");
            }
        }, this)).first().prop("checked", true).end().change();

        this.authentication = $("input[name=authentication]:radio", this.fieldset);
        this.enterCredentials = this.authentication.filter("[value=CREDENTIALS]");
        this.replayCredentials = this.authentication.filter("[value=USER_CREDENTIALS]");
        this.authentication.change($.proxy(function() {
            var enabled = this.enterCredentials.is(":checked");
            this.username.textbox(enabled ? "enable" : "disable").textbox(enabled ? "enableValidation" : "disableValidation");
            this.password.textbox(enabled ? "enable" : "disable");
        }, this));

        this.username = $("input[name=username]", this.fieldset).textbox({required: true, validType: "proxy_username_nonempty", missingMessage: window.R.string.PROXIES_ERROR_BAD_USER, width: "50%"});
        this.password = $("input[name=password]", this.fieldset).textbox({type: "password", width: "50%"});

        this.region = $("select[name=region]", this.fieldset).combobox({required: true, editable: false, width: "60%"});

        this.remoteDirectory = $("input[name=remotedirectory]:radio", this.fieldset).change($.proxy(function() {
            this.remoteDirectoryPath.textbox(this.isRemoteDirectory() ? "enable" : "disable");
        }, this));
        this.remoteDirectoryPath = $("input[name=remotepath]", this.fieldset).textbox({width: "60%"});

        initializing = false;
    },

    getName: function() {
        throw "Abstract method.";
    },

    getEncryptionType: function() {
        return this.useEncryption.is(":checked") ? this.encryption.filter(":checked").val() : null;
    },

    setEncryptionType: function(value) {
        if (value) {
            this.encryption.filter("[value=" + value +"]").prop("checked", true);
            this.useEncryption.prop("checked", true).change();
        } else {
            this.useEncryption.prop("checked", false).change();
        }
    },

    getKmsKey: function() {
        return this.ecnryptionAwsKms.is(":checked:not(:disabled)") ? this.encryptionAwsKmsKey.combobox("getValue") : null;
    },

    setKmsKey: function(value) {
        this.encryptionAwsKmsKey.combobox("setValue", value);
    },

    getUsername: function() {
        return this.enterCredentials.is(":checked") ? this.username.textbox("getValue") : null;
    },

    setUsername: function(value) {
        if (value != null) {
            this.username.textbox("setValue", value);
            this.enterCredentials.prop("checked", true).change();
        } else {
            this.replayCredentials.prop("checked", true).change();
        }
    },

    getPassword: function() {
        return this.enterCredentials.is(":checked") ? this.password.textbox("getValue") : null;
    },

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

    getAuthenticationType: function() {
        return this.authentication.filter(":checked").val();
    },

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

    isRemoteDirectory: function() {
        return this.remoteDirectory.filter("[value=remote]").is(":checked");
    },

    setRemoteDirectory: function(value) {
        this.remoteDirectory.filter(!!value ? "[value=remote]" : ":not([value=remote])").first().prop("checked", true).change();
    },

    getRegion: function() {
        return this.region.combobox("getValue");
    },

    setRegion: function(value) {
        this.region.combobox("select", value);
    },

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

    setRemoteDirectoryPath: function(value) {
        this.remoteDirectoryPath.textbox("setValue", value);
        this.setRemoteDirectory(value && value.length != 0);
    },

    _onLoad$KmsKeys: function (params, success, error) {
        this.listener.onRefreshKmsKeys(this).done(success).fail(error);
    }
});

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

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

    /** @override */
    getName: function() {
        return this.name.textbox("getValue");
    }
});

/** @class */
jscape.domain.EditAmazonS3ReverseProxyDialog = jscape.domain.AmazonS3ReverseProxyDialog.extend(
    /** @lends {jscape.domain.EditAmazonS3ReverseProxyDialog.prototype} */
{
    proxyName: "",

    /** @constructor */
    initialize: function() {
        this._super($("#d-proxy-edit-amazons3"));

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

    /** @override */
    getName: function() {
        return this.proxyName;
    },

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

/** @class */
jscape.domain.AddOftpReverseProxyController = jscape.domain.BaseReverseProxyController.extend(
    /** @lends {jscape.domain.AddOftpReverseProxyController.prototype} */
{
    DEFAULT_PORT: 3305,
    DEFAULT_MAX_AGE: 10 * 60 * 1000,

    /** @override */
    _setupDialog: function () {
        var dialog = new jscape.domain.AddOftpReverseProxyDialog();
        dialog.setPort(this.DEFAULT_PORT);
        dialog.setUseSsl(false);
        dialog.setUsername("");
        dialog.setDebugDirectory(null);
        dialog.setMaxAge(this.DEFAULT_MAX_AGE);
        this.managementService.getDomainTags(this.domainName).done(function (tags) { dialog.setAvailableTags(tags); });
        this._loadEncryptionKeys().done(function (keys) { dialog.setEncryptionKeys(keys); });
        this._loadSigningKeys().done(function (keys) { dialog.setSigningKeys(keys); });
        return dialog;
    },

    _createDescriptor: function (dialog) {
        var signingKeyProvider = dialog.getSigningKey() != null ? new jscape.ServerKeyProvider(dialog.getSigningKey()) : null;
        var encryptionKeyProvider = dialog.getEncryptionKey() != null ? new jscape.ServerKeyProvider(dialog.getEncryptionKey()) : null;
        var cipherSuite = dialog.getEncryptionKey() != null || dialog.getSigningKey() != null ? dialog.getCipher() : null;
        return jscape.ResourceDescriptor.oftp(dialog.getName(),
                                              dialog.getHost(),
                                              dialog.getPort(),
                                              dialog.isUseSsl(),
                                              dialog.getUsername(),
                                              dialog.getPassword(),
                                              dialog.isReplayCredentials(),
                                              null,
                                              null,
                                              dialog.getRecipient(),
                                              encryptionKeyProvider,
                                              signingKeyProvider,
                                              cipherSuite,
                                              dialog.getDebugDirectory(),
                                              dialog.getMaxAge(),
                                              dialog.getTags());
    },

    _loadEncryptionKeys: function() {
        return this.managementService.getHostCertificates("RSA")
                .then(function(keys) { return $.map(keys, function (key) { return key.name; }); });
    },

    _loadSigningKeys: function() {
        return this.managementService.getServerKeys("RSA")
                .then(function(keys) { return $.map(keys, function (key) { return key.name; }); });
    }
});

/** @class */
jscape.domain.EditOftpReverseProxyController = jscape.domain.BaseReverseProxyController.extend(
    /** @lends {jscape.domain.EditOftpReverseProxyController.prototype} */
{
    /** @override */
    start: function(listener, managementService, domainName, descriptor) {
        this.descriptor = descriptor;
        return this._super(listener, managementService, domainName);
    },

    /** @override */
    _setupDialog: function () {
        var dialog = new jscape.domain.EditOftpReverseProxyDialog();
        var descriptor = this.descriptor;
        if (descriptor) {
            dialog.setName(descriptor.name);
            dialog.setHost(descriptor.host);
            dialog.setPort(descriptor.port);
            dialog.setUseSsl(descriptor.sslRequired);
            dialog.setUsername(descriptor.username);
            dialog.setPassword(descriptor.password);
            dialog.setRecipient(descriptor.destination);
            dialog.setCipher(descriptor.cipherSuite);
            dialog.setDebugDirectory(descriptor.logDirectory);
            dialog.setMaxAge(descriptor.timeToLive);
        }
        this.managementService.getDomainTags(this.domainName)
                .done(function (tags) {
                          dialog.setAvailableTags(tags);
                          descriptor && dialog.setTags(descriptor.tags);
                      });
        this._loadEncryptionKeys(dialog)
                .done(function (keyAliases) {
                          dialog.setEncryptionKeys(keyAliases);
                          dialog.setEncryptionKey(descriptor.encryptionKeyProvider ? descriptor.encryptionKeyProvider.keyAlias : null);
                      });
        this._loadSigningKeys(dialog)
                .done(function (keys) {
                          dialog.setSigningKeys(keys);
                          dialog.setSigningKey(descriptor.signingKeyProvider ? descriptor.signingKeyProvider.keyAlias : null);
                      });
        return dialog;
    },

    _createDescriptor: function (dialog) {
        var signingKeyProvider = dialog.getSigningKey() != null ? new jscape.ServerKeyProvider(dialog.getSigningKey()) : null;
        var encryptionKeyProvider = dialog.getEncryptionKey() != null ? new jscape.ServerKeyProvider(dialog.getEncryptionKey()) : null;
        var cipherSuite = dialog.getEncryptionKey() != null || dialog.getSigningKey() != null ? dialog.getCipher() : null;
        return jscape.ResourceDescriptor.oftp(this.descriptor.name,
                                              dialog.getHost(),
                                              dialog.getPort(),
                                              dialog.isUseSsl(),
                                              dialog.getUsername(),
                                              dialog.getPassword(),
                                              dialog.isReplayCredentials(),
                                              null,
                                              null,
                                              dialog.getRecipient(),
                                              encryptionKeyProvider,
                                              signingKeyProvider,
                                              cipherSuite,
                                              dialog.getDebugDirectory(),
                                              dialog.getMaxAge(),
                                              dialog.getTags());
    },

    _loadEncryptionKeys: function() {
        return this.managementService.getHostCertificates("RSA")
                .then(function (keys) { return $.map(keys, function (key) { return key.name; });});
    },

    _loadSigningKeys: function() {
        return this.managementService.getServerKeys("RSA")
                .then(function (keys) { return $.map(keys, function (key) { return key.name; }); });
    }
});

/** @class */
jscape.domain.OftpReverseProxyDialog = jscape.domain.ReverseProxyDialog.extend(
    /** @lends {jscape.domain.OftpReverseProxyDialog.prototype} */
{
    TIMEOUT_FACTOR: 60 * 1000,
    DEFAULT_MAX_AGE: 10,

    /** @constructor */
    initialize: function(dialog) {
        this._super(dialog);

        this.host = $("input[name=host]", this.fieldset).validatebox({required: true, validType: "non_empty", missingMessage: window.R.string.PROXIES_ERROR_BAD_HOST, invalidMessage: window.R.string.PROXIES_ERROR_BAD_HOST});
        this.port = $("input[name=port]", this.fieldset).numberspinner({required: true, min: 1, max: 65535, width: 100});
        this.ssl = $("input[name=ssl]:checkbox", this.fieldset);

        this.credentials = $("input[name=credentials]:radio", this.fieldset);
        this.enterCredentials = this.credentials.filter("[value=enter]");
        this.replayCredentials = this.credentials.filter("[value=replay]");
        this.credentials.change($.proxy(function() {
            var enabled = this.enterCredentials.is(":checked");
            this.username.prop("disabled", !enabled).validatebox(enabled ? "enableValidation" : "disableValidation").validatebox("validate");
            this.password.prop("disabled", !enabled);
        }, this));

        this.username = $("input[name=username]", this.fieldset).validatebox({required: true, validType: "proxy_username_nonempty", missingMessage: window.R.string.PROXIES_ERROR_BAD_USER});
        this.password = $("input[name=userpwd]", this.fieldset);
        this.recipient = $("input[name=recipient]", this.fieldset).validatebox({required: true, missingMessage: window.R.string.PROXIES_ERROR_BAD_RECIPIENT});

        this.useEncryptionKey = $("input[name=useencryptionkey]:checkbox", this.fieldset).prop("disabled", true);
        this.useEncryptionKey.change($.proxy(function() {
            this.encryptionKey.combobox(this.useEncryptionKey.is(":checked") ? "enable" : "disable");
            this._adjustCipherFieldState();
        }, this));
        this.encryptionKey = $("select[name=encryptionkey]", this.fieldset);
        this.encryptionKey.combobox({
            editable: false,
            disabled: true,
            width: 170,
            panelHeight: "auto",
            onLoadSuccess: $.proxy(function(data) {
                this.useEncryptionKey.prop("disabled", data.length == 0);
                if (data.length != 0) {
                    this.encryptionKey.combobox("select", data[0].value);
                }
            }, this)
        });

        this.useSigningKey = $("input[name=usesigningkey]:checkbox", this.fieldset).prop("disabled", true);
        this.useSigningKey.change($.proxy(function() {
            this.signingKey.combobox(this.useSigningKey.is(":checked") ? "enable" : "disable");
            this._adjustCipherFieldState();
        }, this));
        this.signingKey = $("select[name=signingkey]", this.fieldset);
        this.signingKey.combobox({
            editable: false,
            disabled: true,
            width: 170,
            panelHeight: "auto",
            onLoadSuccess: $.proxy(function(data) {
                this.useSigningKey.prop("disabled", data.length == 0);
                if (data.length != 0) {
                    this.signingKey .combobox("select", data[0].value);
                }
            }, this)
        });

        this.cipher = $("select[name=cipher]", this.fieldset).combobox({required: true, editable: false, panelHeight: "auto"});

        this.maxAge = $("input[name=maxage]:checkbox", this.fieldset);
        this.maxAge.change($.proxy(function() {
            var enabled = this.maxAge.is(":checked");
            this.ttl.numberspinner(enabled ? "enable" : "disable").numberspinner(enabled ? "enableValidation" : "disableValidation")
        }, this));
        this.ttl = $("input[name=ttl]", this.fieldset).numberspinner({required: true, disabled: true, min: 1, max: 1000, width: 70});
    },

    getName: function() {
        throw "Abstract method.";
    },

    getHost: function() {
        return this.host.val();
    },

    setHost: function(value) {
        this.host.val(value);
    },

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

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

    isUseSsl: function() {
        return this.ssl.is(":checked");
    },

    setUseSsl: function(value) {
        this.ssl.prop("checked", !!value);
    },

    isReplayCredentials: function() {
        return this.replayCredentials.is(":checked");
    },

    getUsername: function() {
        return this.enterCredentials.is(":checked") ? this.username.textbox("getValue") : null;
    },

    setUsername: function(value) {
        if (value != null) {
            this.username.val(value);
            this.enterCredentials.prop("checked", true).change();
        } else {
            this.replayCredentials.prop("checked", true).change();
        }
    },

    getPassword: function() {
        return this.enterCredentials.is(":checked") ? this.password.val() : null;
    },

    setPassword: function(value) {
        this.password.val(value);
    },

    getRecipient: function() {
        return this.recipient.val();
    },

    setRecipient: function(value) {
        this.recipient.val(value);
    },

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

    setEncryptionKey: function(value) {
        this.useEncryptionKey.prop("checked", value != null).change();
        if (value != null) {
            this.encryptionKey.combobox("setValue", value);
        }
    },

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

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

    setSigningKey: function(value) {
        this.useSigningKey.prop("checked", value != null).change();
        if (value != null) {
            this.signingKey.combobox("setValue", value);
        }
    },

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

    getCipher: function() {
        return this.cipher.is(":disabled") ? null : this.cipher.combobox("getValue");
    },

    setCipher: function(value) {
        this.cipher.combobox("select", value);
    },

    getMaxAge: function() {
        return this.maxAge.is(":checked") ? this.ttl.numberspinner("getValue") * this.TIMEOUT_FACTOR : null;
    },

    setMaxAge: function(value) {
        value = parseInt(value);
        this.maxAge.prop("checked", !isNaN(value)).change();
        this.ttl.numberspinner("setValue", !isNaN(value) ? value / this.TIMEOUT_FACTOR : this.DEFAULT_MAX_AGE);
    },

    show: function (listener) {
        this._super(listener);
        this._adjustCipherFieldState();
    },

    _adjustCipherFieldState: function(){
        this.cipher.combobox(this.getEncryptionKey() != null || this.getSigningKey() != null ? "enable" : "disable");
    }
});

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

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

    /** @override */
    getName: function() {
        return this.name.textbox("getValue");
    }
});

/** @class */
jscape.domain.EditOftpReverseProxyDialog = jscape.domain.OftpReverseProxyDialog.extend(
    /** @lends {jscape.domain.EditOftpReverseProxyDialog.prototype} */
{
    proxyName: "",

    /** @constructor */
    initialize: function() {
        this._super($("#d-proxy-edit-oftp"));

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

    /** @override */
    getName: function() {
        return this.proxyName;
    },

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

/** @class */
jscape.domain.AddTftpReverseProxyController = jscape.domain.BaseReverseProxyController.extend(
    /** @lends {jscape.domain.AddTftpReverseProxyController.prototype} */
{
    DEFAULT_PORT: 69,
    DEFAULT_INTERVAL: 3000,
    DEFAULT_ATTEMPTS: 6,

    /** @override */
    _setupDialog: function () {
        var dialog = new jscape.domain.AddTftpReverseProxyDialog();
        dialog.setPort(this.DEFAULT_PORT);
        dialog.setRetransmitInterval(this.DEFAULT_INTERVAL);
        dialog.setMaxRetransmitAttempts(this.DEFAULT_ATTEMPTS);
        dialog.setDebugDirectory(null);
        this.managementService.getDomainTags(this.domainName).done(function (tags) { dialog.setAvailableTags(tags); });
        return dialog;
    },

    _createDescriptor: function (dialog) {
        return jscape.ResourceDescriptor.tftp(dialog.getName(),
                                              dialog.getHost(),
                                              dialog.getPort(),
                                              dialog.getRetransmitInterval(),
                                              dialog.getMaxRetransmitAttempts(),
                                              dialog.getDebugDirectory(),
                                              dialog.getTags());
    }
});

/** @class */
jscape.domain.EditTftpReverseProxyController = jscape.domain.BaseReverseProxyController.extend(
    /** @lends {jscape.domain.EditTftpReverseProxyController.prototype} */
{
    /** @override */
    start: function(listener, managementService, domainName, descriptor) {
        this.descriptor = descriptor;
        return this._super(listener, managementService, domainName);
    },

    /** @override */
    _setupDialog: function () {
        var dialog = new jscape.domain.EditTftpReverseProxyDialog();
        var descriptor = this.descriptor;
        if (descriptor) {
            dialog.setName(descriptor.name);
            dialog.setHost(descriptor.host);
            dialog.setPort(descriptor.port);
            dialog.setRetransmitInterval(descriptor.retransmitTimeout);
            dialog.setMaxRetransmitAttempts(descriptor.maxRetransmitAttempts);
            dialog.setDebugDirectory(descriptor.logDirectory);
        }
        this.managementService.getDomainTags(this.domainName)
                .done(function (tags) {
                          dialog.setAvailableTags(tags);
                          descriptor && dialog.setTags(descriptor.tags);
                      });
        return dialog;
    },

    _createDescriptor: function (dialog) {
        return jscape.ResourceDescriptor.tftp(this.descriptor.name,
                                              dialog.getHost(),
                                              dialog.getPort(),
                                              dialog.getRetransmitInterval(),
                                              dialog.getMaxRetransmitAttempts(),
                                              dialog.getDebugDirectory(),
                                              dialog.getTags());
    }
});

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

    /** @constructor */
    initialize: function(dialog) {
        this._super(dialog);

        this.host = $("input[name=host]", this.fieldset).textbox({required: true, validType: "non_empty", missingMessage: window.R.string.PROXIES_ERROR_BAD_HOST, invalidMessage: window.R.string.PROXIES_ERROR_BAD_HOST, width: "60%"});
        this.port = $("input[name=port]", this.fieldset).numberspinner({required: true, min: 1, max: 65535, width: 100});
        this.retransmitInterval = $("input[name=retransmitinterval]", this.fieldset).numberspinner({required: true, min: 1, max: 255, width: 60});
        this.retransmitAttempts = $("input[name=retransmitattempts]", this.fieldset).numberspinner({required: true, min: 1, max: 100, width: 60});
    },

    getName: function() {
        throw "Abstract method.";
    },

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

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

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

    setPort: function(value) {
        this.port.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);
    },

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

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

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

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

    /** @override */
    getName: function() {
        return this.name.textbox("getValue");
    }
});

/** @class */
jscape.domain.EditTftpReverseProxyDialog = jscape.domain.TftpReverseProxyDialog.extend(
    /** @lends {jscape.domain.EditTftpReverseProxyDialog.prototype} */
{
    proxyName: "",

    /** @constructor */
    initialize: function() {
        this._super($("#d-proxy-edit-tftp"));

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

    /** @override */
    getName: function() {
        return this.proxyName;
    },

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

/** @class */
jscape.domain.AddSmbReverseProxyController = jscape.domain.BaseReverseProxyController.extend(
    /** @lends {jscape.domain.AddSmbReverseProxyController.prototype} */
{
    DEFAULT_PORT: 445,
    DEFAULT_TIMEOUT: 60 * 1000,

    /** @override */
    _setupDialog: function () {
        var dialog = new jscape.domain.AddSmbReverseProxyDialog();
        dialog.setPort(this.DEFAULT_PORT);
        dialog.setTimeout(this.DEFAULT_TIMEOUT);
        dialog.setUsername("");
        dialog.setPassword("");
        dialog.setRemoteDirectory(true);
        dialog.setDebugDirectory(null);
        this.managementService.getDomainTags(this.domainName).done(function (tags) { dialog.setAvailableTags(tags); });
        return dialog;
    },

    _createDescriptor: function (dialog) {
        return jscape.ResourceDescriptor.smb(dialog.getName(),
                                             dialog.getHost(),
                                             dialog.getPort(),
                                             dialog.getTimeout(),
                                             dialog.getDomain(),
                                             dialog.getUsername(),
                                             dialog.getPassword(),
                                             dialog.isReplayCredentials(),
                                             dialog.isRemoteDirectory() ? jscape.RemoteDirectory.remote(dialog.getRemoteDirectoryPath()) : jscape.RemoteDirectory.local(),
                                             dialog.getDebugDirectory(),
                                             dialog.getTags());
    }
});

/** @class */
jscape.domain.EditSmbReverseProxyController = jscape.domain.BaseReverseProxyController.extend(
    /** @lends {jscape.domain.EditSmbReverseProxyController.prototype} */
{
    /** @override */
    start: function(listener, managementService, domainName, descriptor) {
        this.descriptor = descriptor;
        return this._super(listener, managementService, domainName);
    },

    /** @override */
    _setupDialog: function () {
        var dialog = new jscape.domain.EditSmbReverseProxyDialog();
        var descriptor = this.descriptor;
        if (descriptor) {
            dialog.setName(descriptor.name);
            dialog.setHost(descriptor.host);
            dialog.setPort(descriptor.port);
            dialog.setTimeout(descriptor.timeout);
            dialog.setUsername(descriptor.username);
            dialog.setPassword(descriptor.password);
            dialog.setDomain(descriptor.domain);
            dialog.setRemoteDirectoryPath(descriptor.remoteDirectory.path);
            dialog.setRemoteDirectory(jscape.RemoteDirectory.Type.LOCAL != descriptor.remoteDirectory.type);
            dialog.setDebugDirectory(descriptor.logDirectory);
        }
        this.managementService.getDomainTags(this.domainName)
                .done(function (tags) {
                          dialog.setAvailableTags(tags);
                          descriptor && dialog.setTags(descriptor.tags);
                      });
        return dialog;
    },

    _createDescriptor: function (dialog) {
        return jscape.ResourceDescriptor.smb(this.descriptor.name,
                                             dialog.getHost(),
                                             dialog.getPort(),
                                             dialog.getTimeout(),
                                             dialog.getDomain(),
                                             dialog.getUsername(),
                                             dialog.getPassword(),
                                             dialog.isReplayCredentials(),
                                             dialog.isRemoteDirectory() ? jscape.RemoteDirectory.remote(dialog.getRemoteDirectoryPath()) : jscape.RemoteDirectory.local(),
                                             dialog.getDebugDirectory(),
                                             dialog.getTags());
    }
});

/** @class */
jscape.domain.SmbReverseProxyDialog = jscape.domain.ReverseProxyDialog.extend(
    /** @lends {jscape.domain.SmbReverseProxyDialog.prototype} */
{
    /** @cons */
    TIMEOUT_FACTOR: 60 * 1000,

    /** @constructor */
    initialize: function(dialog) {
        this._super(dialog);

        this.host = $("input[name=host]", this.fieldset).textbox({required: true, validType: "non_empty", missingMessage: window.R.string.PROXIES_ERROR_BAD_HOST, invalidMessage: window.R.string.PROXIES_ERROR_BAD_HOST, width: "60%"});
        this.port = $("input[name=port]", this.fieldset).numberspinner({required: true, min: 1, max: 65535, width: 100});
        this.timeout = $("input[name=timeout]", this.fieldset).numberspinner({required: true, min: 1, max: 60, width: 60});

        this.credentials = $("input[name=credentials]:radio", this.fieldset);
        this.enterCredentials = this.credentials.filter("[value=enter]");
        this.replayCredentials = this.credentials.filter("[value=replay]");
        this.credentials.change($.proxy(function() {
            var enabled = this.enterCredentials.is(":checked");
            this.username.textbox(enabled ? "enable" : "disable").textbox(enabled ? "enableValidation" : "disableValidation");
            this.password.textbox(enabled ? "enable" : "disable");
        }, this));

        this.username = $("input[name=username]", this.fieldset).textbox({required: true, validType: "proxy_username_nonempty", missingMessage: window.R.string.PROXIES_ERROR_BAD_USER, width: "50%"});
        this.password = $("input[name=userpwd]", this.fieldset).textbox({type: "password", width: "50%"});
        this.domain = $("input[name=domain]", this.fieldset).textbox({width: "50%"});

        this.remoteDirectory = $("input[name=remotedirectory]:radio", this.fieldset).change($.proxy(function() {
            this.remoteDirectoryPath.textbox(this.isRemoteDirectory() ? "enable" : "disable");
        }, this));
        this.remoteDirectoryPath = $("input[name=remotepath]", this.fieldset).textbox({width: "60%"});
    },

    getName: function() {
        throw "Abstract method.";
    },

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

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

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

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

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

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

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

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

    isReplayCredentials: function() {
        return this.replayCredentials.is(":checked");
    },

    getUsername: function() {
        return this.enterCredentials.is(":checked") ? this.username.textbox("getValue") : null;
    },

    setUsername: function(value) {
        if (value != null) {
            this.username.textbox("setValue", value);
            this.enterCredentials.prop("checked", true).change();
        } else {
            this.replayCredentials.prop("checked", true).change();
        }
    },

    getPassword: function() {
        return this.enterCredentials.is(":checked") ? this.password.textbox("getValue") : null;
    },

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

    isRemoteDirectory: function() {
        return this.remoteDirectory.filter("[value=remote]").is(":checked");
    },

    setRemoteDirectory: function(value) {
        this.remoteDirectory.filter(!!value ? "[value=remote]" : ":not([value=remote])").first().prop("checked", true).change();
    },

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

    setRemoteDirectoryPath: function(value) {
        this.remoteDirectoryPath.textbox("setValue", value);
        this.setRemoteDirectory(value && value.length != 0);
    }
});

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

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

    /** @override */
    getName: function() {
        return this.name.textbox("getValue");
    }
});

/** @class */
jscape.domain.EditSmbReverseProxyDialog = jscape.domain.SmbReverseProxyDialog.extend(
    /** @lends {jscape.domain.EditSmbReverseProxyDialog.prototype} */
{
    proxyName: "",

    /** @constructor */
    initialize: function() {
        this._super($("#d-proxy-edit-smb"));

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

    /** @override */
    getName: function() {
        return this.proxyName;
    },

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

/** @class */
jscape.domain.AddGoogleStorageReverseProxyController = jscape.domain.BaseReverseProxyController.extend(
    /** @lends {jscape.domain.AddGoogleStorageReverseProxyController.prototype} */
{
    /** @override */
    _setupDialog: function () {
        var dialog = new jscape.domain.AddGoogleStorageReverseProxyDialog();
        dialog.setRemoteDirectory(true);
        dialog.setDebugDirectory(null);
        jscape.API.getDomainTags(this.domainName).done(function (tags) { dialog.setAvailableTags(tags); });
        return dialog;
    },

    _createDescriptor: function (dialog) {
        return jscape.ResourceDescriptor.googleStorage(dialog.getName(),
                                                       dialog.getAuthenticationType(),
                                                       dialog.getKeyFile(),
                                                       dialog.isRemoteDirectory() ? jscape.RemoteDirectory.remote(dialog.getRemoteDirectoryPath()) : jscape.RemoteDirectory.local(),
                                                       dialog.getDebugDirectory(),
                                                       dialog.getTags());
    },

    onSelectKeyFile: function () {
        return new SelectPathController($.proxy(jscape.API.listFileSystem, jscape.API),
                                        $.proxy(jscape.API.createFileSystemDir, jscape.API))
                .selectFile().then(function (entry) { return entry.path; });
    }
});

/** @class */
jscape.domain.EditGoogleStorageReverseProxyController = jscape.domain.BaseReverseProxyController.extend(
    /** @lends {jscape.domain.EditGoogleStorageReverseProxyController.prototype} */
{
    /** @override */
    start: function(listener, managementService, domainName, descriptor) {
        this.descriptor = descriptor;
        return this._super(listener, managementService, domainName);
    },

    /** @override */
    _setupDialog: function () {
        var dialog = new jscape.domain.EditGoogleStorageReverseProxyDialog();
        var descriptor = this.descriptor;
        if (descriptor) {
            dialog.setName(descriptor.name);
            dialog.setAuthenticationType(descriptor.authenticationType);
            dialog.setKeyFile(descriptor.credentialsFile);
            dialog.setRemoteDirectoryPath(descriptor.remoteDirectory.path);
            dialog.setRemoteDirectory(jscape.RemoteDirectory.Type.LOCAL != descriptor.remoteDirectory.type);
            dialog.setDebugDirectory(descriptor.logDirectory);
        }
        jscape.API.getDomainTags(this.domainName)
                .done(function (tags) {
                          dialog.setAvailableTags(tags);
                          descriptor && dialog.setTags(descriptor.tags);
                      });
        return dialog;
    },

    _createDescriptor: function (dialog) {
        return jscape.ResourceDescriptor.googleStorage(this.descriptor.name,
                                                       dialog.getAuthenticationType(),
                                                       dialog.getKeyFile(),
                                                       dialog.isRemoteDirectory() ? jscape.RemoteDirectory.remote(dialog.getRemoteDirectoryPath()) : jscape.RemoteDirectory.local(),
                                                       dialog.getDebugDirectory(),
                                                       dialog.getTags());
    },

    onSelectKeyFile: function () {
        return new SelectPathController($.proxy(jscape.API.listFileSystem, jscape.API),
                                        $.proxy(jscape.API.createFileSystemDir, jscape.API))
                .selectFile().then(function (entry) { return entry.path; });
    }
});

/** @class */
jscape.domain.GoogleStorageReverseProxyDialog = jscape.domain.ReverseProxyDialog.extend(
    /** @lends {jscape.domain.GoogleStorageReverseProxyDialog.prototype} */
{
    /** @constructor */
    initialize: function(dialog) {
        this._super(dialog);

        this.authentication = $("input[name=authentication]:radio", this.fieldset);
        this.useKeyFile = this.authentication.filter("[value=CREDENTIALS_FILE]");
        this.keyFile = $("input[name=keyfile]", this.fieldset).textbox({required: true, validType: "non_empty", width: "45%"});
        this.browseButton = $("a[role=button][name=keyfilebrowse]", this.fieldset).linkbutton({onClick: $.proxy(this._onClick$BrowseButton, this)});
        this.authentication.change($.proxy(function () {
            var enabled = this.useKeyFile.is(":checked");
            this.keyFile.textbox(enabled ? "enable" : "disable").textbox("isValid");
            this.browseButton.linkbutton(enabled ? "enable" : "disable");
        }, this)).first().prop("checked", true).end().change();

        this.remoteDirectory = $("input[name=remotedirectory]:radio", this.fieldset).change($.proxy(function() {
            this.remoteDirectoryPath.textbox(this.isRemoteDirectory() ? "enable" : "disable");
        }, this));
        this.remoteDirectoryPath = $("input[name=remotepath]", this.fieldset).textbox({width: "60%"});
    },

    getAuthenticationType: function () {
        return this.authentication.filter(":checked").val();
    },

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

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

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

    isRemoteDirectory: function() {
        return this.remoteDirectory.filter("[value=remote]").is(":checked");
    },

    setRemoteDirectory: function(value) {
        this.remoteDirectory.filter(!!value ? "[value=remote]" : ":not([value=remote])").first().prop("checked", true).change();
    },

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

    setRemoteDirectoryPath: function(value) {
        this.remoteDirectoryPath.textbox("setValue", value);
        this.setRemoteDirectory(value && value.length != 0);
    },

    _onClick$BrowseButton: function() {
        this.browseButton.linkbutton("disable");
        this.listener.onSelectKeyFile()
                .done($.proxy(function(value) { this.keyFile.textbox("setValue", value).textbox("textbox").focus(); }, this))
                .always($.proxy(function() { this.browseButton.linkbutton("enable"); }, this));
    }
});

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

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

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

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

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

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

/** @class */
jscape.domain.AddMicrosoftAzureReverseProxyController = jscape.domain.BaseReverseProxyController.extend(
    /** @lends {jscape.domain.AddMicrosoftAzureReverseProxyController.prototype} */
{
    /** @override */
    _setupDialog: function () {
        var dialog = new jscape.domain.AddMicrosoftAzureReverseProxyDialog();
        dialog.setUsername("");
        dialog.setPassword("");
        dialog.setRemoteDirectory(true);
        dialog.setDebugDirectory(null);
        jscape.API.getDomainTags(this.domainName).done(function (tags) { dialog.setAvailableTags(tags); });
        return dialog;
    },

    _createDescriptor: function (dialog) {
        return jscape.ResourceDescriptor.microsoftAzure(dialog.getName(),
                                                        dialog.getUsername(),
                                                        dialog.getPassword(),
                                                        dialog.isReplayCredentials(),
                                                        dialog.isUseSsl(),
                                                        dialog.isRemoteDirectory() ? jscape.RemoteDirectory.remote(dialog.getRemoteDirectoryPath()) : jscape.RemoteDirectory.local(),
                                                        dialog.getDebugDirectory(),
                                                        dialog.getTags());
    }
});

/** @class */
jscape.domain.EditMicrosoftAzureReverseProxyController = jscape.domain.BaseReverseProxyController.extend(
    /** @lends {jscape.domain.EditMicrosoftAzureReverseProxyController.prototype} */
{
    /** @override */
    start: function(listener, managementService, domainName, descriptor) {
        this.descriptor = descriptor;
        return this._super(listener, managementService, domainName);
    },

    /** @override */
    _setupDialog: function () {
        var dialog = new jscape.domain.EditMicrosoftAzureReverseProxyDialog();
        var descriptor = this.descriptor;
        if (descriptor) {
            dialog.setName(descriptor.name);
            dialog.setUsername(descriptor.username);
            dialog.setPassword(descriptor.password);
            dialog.setUseSsl(descriptor.sslRequired);
            dialog.setRemoteDirectoryPath(descriptor.remoteDirectory.path);
            dialog.setRemoteDirectory(jscape.RemoteDirectory.Type.LOCAL != descriptor.remoteDirectory.type);
            dialog.setDebugDirectory(descriptor.logDirectory);
        }
        jscape.API.getDomainTags(this.domainName)
                .done(function (tags) {
                          dialog.setAvailableTags(tags);
                          descriptor && dialog.setTags(descriptor.tags);
                      });
        return dialog;
    },

    _createDescriptor: function (dialog) {
        return jscape.ResourceDescriptor.microsoftAzure(this.descriptor.name,
                                                        dialog.getUsername(),
                                                        dialog.getPassword(),
                                                        dialog.isReplayCredentials(),
                                                        dialog.isUseSsl(),
                                                        dialog.isRemoteDirectory() ? jscape.RemoteDirectory.remote(dialog.getRemoteDirectoryPath()) : jscape.RemoteDirectory.local(),
                                                        dialog.getDebugDirectory(),
                                                        dialog.getTags());
    }
});

/** @class */
jscape.domain.MicrosoftAzureReverseProxyDialog = jscape.domain.ReverseProxyDialog.extend(
    /** @lends {jscape.domain.MicrosoftAzureReverseProxyDialog.prototype} */
{
    /** @constructor */
    initialize: function(dialog) {
        this._super(dialog);

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

        this.credentials = $("input[name=credentials]:radio", this.fieldset);
        this.enterCredentials = this.credentials.filter("[value=enter]");
        this.replayCredentials = this.credentials.filter("[value=replay]");
        this.credentials.change($.proxy(function() {
            var enabled = this.enterCredentials.is(":checked");
            this.username.textbox(enabled ? "enable" : "disable").textbox(enabled ? "enableValidation" : "disableValidation");
            this.password.passwordbox(enabled ? "enable" : "disable");
        }, this));

        this.username = $("input[name=username]", this.fieldset).textbox({required: true, validType: "non_empty", missingMessage: window.R.string.PROXIES_ERROR_BAD_USER, invalidMessage: window.R.string.PROXIES_ERROR_BAD_USER, width: "60%"});
        this.password = $("input[name=userpwd]", this.fieldset).passwordbox({required: true, lastDelay: 0, validateOnBlur: true, width: "60%"});

        this.remoteDirectory = $("input[name=remotedirectory]:radio", this.fieldset).change($.proxy(function() {
            this.remoteDirectoryPath.textbox(this.isRemoteDirectory() ? "enable" : "disable");
        }, this));
        this.remoteDirectoryPath = $("input[name=remotepath]", this.fieldset).textbox({width: "60%"});
    },

    isUseSsl: function() {
        return this.useSsl.is(":checked");
    },

    setUseSsl: function(value) {
        this.useSsl.prop("checked", !!value);
    },

    isReplayCredentials: function() {
        return this.replayCredentials.is(":checked");
    },

    getUsername: function() {
        return this.enterCredentials.is(":checked") ? this.username.textbox("getValue") : null;
    },

    setUsername: function(value) {
        if (value != null) {
            this.username.textbox("setValue", value);
            this.enterCredentials.prop("checked", true).change();
        } else {
            this.replayCredentials.prop("checked", true).change();
        }
    },

    getPassword: function() {
        return this.enterCredentials.is(":checked") ? this.password.passwordbox("getValue") : null;
    },

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

    isRemoteDirectory: function() {
        return this.remoteDirectory.filter("[value=remote]").is(":checked");
    },

    setRemoteDirectory: function(value) {
        this.remoteDirectory.filter(!!value ? "[value=remote]" : ":not([value=remote])").first().prop("checked", true).change();
    },

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

    setRemoteDirectoryPath: function(value) {
        this.remoteDirectoryPath.textbox("setValue", value);
        this.setRemoteDirectory(value && value.length != 0);
    }
});

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

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

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

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

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

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

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

    /** @constructor */
    initialize: function() {
        this.controllerMap = {};
        this.controllerMap[jscape.ResourceDescriptor.Protocol.AFTP] = jscape.domain.AddAftpReverseProxyController;
        this.controllerMap[jscape.ResourceDescriptor.Protocol.AMAZON_S3] = jscape.domain.AddAmazonS3ReverseProxyController;
        this.controllerMap[jscape.ResourceDescriptor.Protocol.GOOGLE_STORAGE] = jscape.domain.AddGoogleStorageReverseProxyController;
        this.controllerMap[jscape.ResourceDescriptor.Protocol.MICROSOFT_AZURE] = jscape.domain.AddMicrosoftAzureReverseProxyController;
        this.controllerMap[jscape.ResourceDescriptor.Protocol.FTP] = jscape.domain.AddFtpReverseProxyController;
        this.controllerMap[jscape.ResourceDescriptor.Protocol.OFTP] = jscape.domain.AddOftpReverseProxyController;
        this.controllerMap[jscape.ResourceDescriptor.Protocol.REST] = jscape.domain.AddRestReverseProxyController;
        this.controllerMap[jscape.ResourceDescriptor.Protocol.SFTP] = jscape.domain.AddSftpReverseProxyController;
        this.controllerMap[jscape.ResourceDescriptor.Protocol.SMB] = jscape.domain.AddSmbReverseProxyController;
        this.controllerMap[jscape.ResourceDescriptor.Protocol.WEBDAV] = jscape.domain.AddWebDavReverseProxyController;
        this.controllerMap[jscape.ResourceDescriptor.Protocol.TFTP] = jscape.domain.AddTftpReverseProxyController;
    },

    start: function(listener, managementService, domainName) {
        this.listener = listener || jscape.domain.AddReverseProxyController.LISTENER;
        this.managementService = managementService;
        this.domainName = domainName;
        this.deferred = $.Deferred();
        this._setupDialog().show(this);
        return this.deferred.promise();
    },

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

    onSubmit: function(dialog) {
        var protocol = dialog.getProtocol();
        dialog.destroy();

        var theClass = this.controllerMap[protocol];
        if (typeof theClass == "function") {
            var controller = new theClass();
            controller.start(this, this.managementService, this.domainName)
                    .done($.proxy(this._storeDescriptor, this))
                    .fail($.proxy(function() { this.deferred.reject(); this.deferred = null; }, this));
        } else {
            this.deferred.reject();
            this.deferred = null;
        }
    },

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

    _storeDescriptor: function (descriptor) {
        this.managementService.addReverseProxy(this.domainName, descriptor)
                .done($.proxy(function (descriptor) { this.deferred.resolve(descriptor); this.deferred = null; }, this))
                .fail($.proxy(function () { this.deferred.reject(); this.deferred = null; }, this));
    },

    _setupDialog: function() {
        return new jscape.domain.AddReverseProxyProtocolDialog();
    }
});
jscape.domain.AddReverseProxyController.LISTENER = {
    onTestServer: $.noop
};

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

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

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

    getProtocol: function() {
        return this.protocol.combobox("getValue");
    },

    show: function (listener) {
        this.listener = listener;
        this.dialog.dialog("center").dialog("open");
        this.fieldset.form("validate");
        this.protocol.combobox("textbox").focus();
    },

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

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

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

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

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

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

    /** @constructor */
    initialize: function() {
        this.controllerMap = {};
        this.controllerMap[jscape.ResourceDescriptor.Protocol.AFTP] = jscape.domain.EditAftpReverseProxyController;
        this.controllerMap[jscape.ResourceDescriptor.Protocol.AMAZON_S3] = jscape.domain.EditAmazonS3ReverseProxyController;
        this.controllerMap[jscape.ResourceDescriptor.Protocol.GOOGLE_STORAGE] = jscape.domain.EditGoogleStorageReverseProxyController;
        this.controllerMap[jscape.ResourceDescriptor.Protocol.MICROSOFT_AZURE] = jscape.domain.EditMicrosoftAzureReverseProxyController;
        this.controllerMap[jscape.ResourceDescriptor.Protocol.FTP] = jscape.domain.EditFtpReverseProxyController;
        this.controllerMap[jscape.ResourceDescriptor.Protocol.OFTP] = jscape.domain.EditOftpReverseProxyController;
        this.controllerMap[jscape.ResourceDescriptor.Protocol.REST] = jscape.domain.EditRestReverseProxyController;
        this.controllerMap[jscape.ResourceDescriptor.Protocol.SFTP] = jscape.domain.EditSftpReverseProxyController;
        this.controllerMap[jscape.ResourceDescriptor.Protocol.SMB] = jscape.domain.EditSmbReverseProxyController;
        this.controllerMap[jscape.ResourceDescriptor.Protocol.WEBDAV] = jscape.domain.EditWebDavReverseProxyController;
        this.controllerMap[jscape.ResourceDescriptor.Protocol.TFTP] = jscape.domain.EditTftpReverseProxyController;
    },

    start: function(listener, managementService, domainName, descriptor) {
        this.listener = listener || jscape.domain.EditReverseProxyController.LISTENER;
        this.managementService = managementService;
        this.domainName = domainName;
        this.deferred = $.Deferred();
        this.managementService.getReverseProxy(this.domainName, descriptor.name)
                .then($.proxy(this._editDescriptor, this))
                .fail($.proxy(function() { this.deferred.reject(); this.deferred = null; }, this));
        return this.deferred.promise();
    },

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

    _editDescriptor: function (descriptor) {
        var theClass = this.controllerMap[descriptor.protocol];
        if (typeof theClass === "function") {
            var controller = new theClass();
            return controller.start(this, this.managementService, this.domainName, descriptor)
                    .done($.proxy(this._storeDescriptor, this));
        } else {
            return $.Deferred().reject().promise();
        }
    },

    _storeDescriptor: function (descriptor) {
        this.managementService.setReverseProxy(this.domainName, descriptor.name, descriptor)
                .done($.proxy(function () { this.deferred.resolve(descriptor); this.deferred = null; }, this))
                .fail($.proxy(function() { this.deferred.reject(); this.deferred = null; }, this));
    }
});
jscape.domain.EditReverseProxyController.LISTENER = {
    onTestServer: $.noop
};

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

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

        if (this._requestCredentialsFor(descriptor)) {
            new jscape.domain.ProxyCredentialsDialog().show(this);
        } else {
            this._test(this.descriptor);
        }

        return this.deferred.promise();
    },

    onSubmit: function(dialog) {
        var descriptor = $.extend({}, this.descriptor, {username: dialog.getUsername(), password: dialog.getPassword()});
        dialog.destroy();

        this._test(descriptor);
    },

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

    _requestCredentialsFor: function(descriptor) {
        return !!descriptor.usingCredentials
               || (jscape.ResourceDescriptor.Protocol.AMAZON_S3 == descriptor.protocol && "USER_CREDENTIALS" == descriptor.authenticationType);
    },

    _test: function (descriptor) {
        return this.managementService.testReverseProxy(this.domainName, descriptor.name, descriptor)
                .done(function () {
                          $.messager.alert(window.R.string.PROXIES_SUCCESS_TEST_TITLE,
                                           window.R.string.PROXIES_SUCCESS_TEST_MESSAGE,
                                           "info");
                      })
                .done($.proxy(function () {
                          this.deferred.resolve();
                          this.deferred = null;
                      }, this))
                .fail($.proxy(function () {
                          this.deferred.reject();
                          this.deferred = null;
                      }, this));
    }
});

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

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

        this.username = $("[name=username]", this.fieldset).textbox({validType: "non_empty", width: "60%"});
        this.password = $("[name=password]", this.fieldset).passwordbox({lastDelay: 0, width: "60%"});
    },

    show: function (listener) {
        this.listener = listener;
        this.dialog.dialog("center").dialog("open");
        this.fieldset.form("validate");
        this.username.textbox("textbox").focus();
    },

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

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

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

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

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

    start: function (managementService, domainName, proxies) {
        this.managementService = managementService;
        this.domainName = domainName;
        this.deferred = $.Deferred();
        this._confirmDelete(proxies)
                .done($.proxy(this._deleteConfirmed, this, proxies))
                .fail($.proxy(function() { this.deferred.reject(); this.deferred = null; }, this));
        return this.deferred.promise();
    },

    _confirmDelete: function(proxies) {
        var text = $.map(proxies, function(proxy) { return proxy.name; }).join(", ");
        return jscape.ConfirmDialog.confirm(
                window.R.string.PROXIES_CONFIRM_DELETE_TITLE,
                window.R.string.PROXIES_CONFIRM_DELETE_MESSAGE.supplant({0: text}));
    },

    _deleteConfirmed: function(proxies) {
        $.when.apply(jQuery, $.map(proxies, $.proxy(function(proxy) { return this.managementService.deleteReverseProxy(this.domainName, proxy.name); }, this)))
                .done($.proxy(function() { this.deferred.resolve(proxies); this.deferred = null; }, this))
                .fail($.proxy(function() { this.deferred.reject(); this.deferred = null; }, this));
    }
});
