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

/** @class */
jscape.AuthService = Class.extend(
    /** @lends {jscape.AuthService.prototype} */
{
    /** @constructor */
    initialize: function(type) {
        this.type = type || null;
    }
});
jscape.AuthService.fromJSON = function(data) {
    data = data ? $.extend(new jscape.AuthService(), data) : jscape.AuthService.none();
    if (data.hasOwnProperty("usernameConversion")) {
        data.usernameConversion = jscape.UsernameConversion.valueOf(data.usernameConversion);
    }
    if (data.hasOwnProperty("primary")) {
        delete data.primary.version;
    }
    if (data.hasOwnProperty("secondary")) {
        delete data.secondary.version;
    }
    return data;
};
jscape.AuthService.TYPE = {NONE: 'NONE', DOMAIN: 'DOMAIN', DB: 'DB', DB_QUERY: 'DB_QUERY', LDAP: 'LDAP', LDAP_QUERY: 'LDAP_QUERY', NTLM: 'NTLM', PAM: 'PAM', CUSTOM: 'CUSTOM', MULTIPLE: 'MULTIPLE', PHONE: 'PHONE', RADIUS: 'RADIUS'};
jscape.UsernameConversion = {
    NONE: 'NONE', UPPERCASE: 'UPPERCASE', LOWERCASE: 'LOWERCASE',
    values: function() { return [this.NONE, this.UPPERCASE, this.LOWERCASE]; },
    valueOf: function(value) { return $.inArray(value, this.values()) != -1 ? value : this.NONE; }
};
jscape.AuthService.NONE = $.extend(new jscape.AuthService(jscape.AuthService.TYPE.NONE), {toJSON: function() { return null; }});
jscape.AuthService.none = function() { return jscape.AuthService.NONE; };
jscape.AuthService.domain = function() {
    return new jscape.AuthService(jscape.AuthService.TYPE.DOMAIN);
};
jscape.AuthService.db = function(url, template, usernameConversion) {
    return $.extend(new jscape.AuthService(jscape.AuthService.TYPE.DB), {url: url, accountTemplate: template, usernameConversion: usernameConversion});
};
jscape.AuthService.dbQuery = function(url, username, password, query, hasher, template, usernameConversion) {
    return $.extend(new jscape.AuthService(jscape.AuthService.TYPE.DB_QUERY), {url: url, username: username, password: password, sql: query, hasher: hasher, accountTemplate: template, usernameConversion: usernameConversion});
};
jscape.AuthService.ldap = function(host, port, timeout, userDN, useSsl, anonymousAllowed, template, usernameConversion, failover) {
    return $.extend(new jscape.AuthService(jscape.AuthService.TYPE.LDAP), {host: host, port: port, timeout: timeout, userDN: userDN, useSsl: !!useSsl, anonymousAllowed: !!anonymousAllowed, accountTemplate: template, usernameConversion: usernameConversion, failoverServers: failover ? [failover] : []});
};
jscape.AuthService.ldapQuery = function(host, port, timeout, userDN, searchUserDN, baseDN, password, hasher, filter, useSsl, anonymousAllowed, template, usernameConversion, failover) {
    return $.extend(new jscape.AuthService(jscape.AuthService.TYPE.LDAP_QUERY), {host: host, port: port, timeout: timeout, userDN: userDN, searchUserDN: searchUserDN, baseDN: baseDN, password: password, hasher: hasher, filter: filter, useSsl: !!useSsl, anonymousAllowed: !!anonymousAllowed, accountTemplate: template, usernameConversion: usernameConversion, failoverServers: failover ? [failover] : []});
};
jscape.AuthService.ntlm = function(host, domain, template, usernameConversion) {
    return $.extend(new jscape.AuthService(jscape.AuthService.TYPE.NTLM), {host: host, windowsDomain: domain, accountTemplate: template, usernameConversion: usernameConversion});
};
jscape.AuthService.pam = function(debug, template, usernameConversion) {
    return $.extend(new jscape.AuthService(jscape.AuthService.TYPE.PAM), {debugEnabled: !!debug, accountTemplate: template, usernameConversion: usernameConversion});
};
jscape.AuthService.radius = function(localHost, serverHost, serverPort, timeout, maxRetransmitAttempts, identifier, sharedSecret, template, usernameConversion) {
    return $.extend(new jscape.AuthService(jscape.AuthService.TYPE.RADIUS), {localhost: localHost, localport: 0, serverhost: serverHost, serverport: serverPort, timeout: timeout, maxRetransmitAttempts: maxRetransmitAttempts, identifier: identifier, sharedSecret: sharedSecret, accountTemplate: template, usernameConversion: usernameConversion});
};
jscape.AuthService.custom = function(className, template, usernameConversion) {
    return $.extend(new jscape.AuthService(jscape.AuthService.TYPE.CUSTOM), {className: className, accountTemplate: template, usernameConversion: usernameConversion});
};
jscape.AuthService.multiple = function(primaryService, secondaryService) {
    return $.extend(new jscape.AuthService(jscape.AuthService.TYPE.MULTIPLE), {primary: primaryService, secondary: secondaryService});
};

/** @class */
jscape.UserConfirmationService = Class.extend(
    /** @lends {jscape.UserConfirmationService.prototype} */
{
    /** @constructor */
    initialize: function(type) {
        this.type = type || null;
    }
});
jscape.UserConfirmationService.fromJSON = function(data) {
    return data ? $.extend(new jscape.UserConfirmationService(), data) : jscape.UserConfirmationService.none();
};
jscape.UserConfirmationService.TYPE = {NONE: 'NONE', PHONE: 'PHONE', CUSTOM: 'CUSTOM', TOTP: 'TOTP'};
jscape.UserConfirmationService.NONE = $.extend(new jscape.UserConfirmationService(jscape.UserConfirmationService.TYPE.NONE), {toJSON: function() { return null; }});
jscape.UserConfirmationService.none = function() { return jscape.UserConfirmationService.NONE; };
jscape.UserConfirmationService.phoneFactor = function(licenseDirectory, password, internationalCallsAllowed) {
    return $.extend(new jscape.UserConfirmationService(jscape.UserConfirmationService.TYPE.PHONE), {licenseDirectory: licenseDirectory, password: password, internationalCallsAllowed: internationalCallsAllowed});
};
jscape.UserConfirmationService.totp = function() {
    return new jscape.UserConfirmationService(jscape.UserConfirmationService.TYPE.TOTP);
};
jscape.UserConfirmationService.custom = function(serviceClass) {
    return $.extend(new jscape.UserConfirmationService(jscape.UserConfirmationService.TYPE.CUSTOM), {serviceClassName: serviceClass});
};

/** @class */
jscape.WebSsoService = Class.extend(
    /** @lends {jscape.WebSsoService.prototype} */
{
    /** @constructor */
    initialize: function(type) {
        this.type = type || null;
    }
});
jscape.WebSsoService.fromJSON = function(data) {
    return data ? $.extend(new jscape.WebSsoService(), data) : jscape.AuthService.none();
};
jscape.WebSsoService.TYPE = {OPEN_ID: 'OPEN_ID', OPEN_ID_CONNECT: 'OPEN_ID_CONNECT', SAML: 'SAML'};
jscape.WebSsoService.openId = function(signInUrl, signOutUrl, nonSsoLoginAllowed, template, usernameConversion) {
    return $.extend(new jscape.WebSsoService(jscape.WebSsoService.TYPE.OPEN_ID), {signInUrl: signInUrl, signOutUrl: signOutUrl, nonSsoLoginAllowed: !!nonSsoLoginAllowed, accountTemplate: template, usernameConversion: usernameConversion});
};
jscape.WebSsoService.openIdConnect = function(signInUrl, tokenVerificationUrl, clientId, clientSecret, nonSsoLoginAllowed, template, usernameConversion) {
    return $.extend(new jscape.WebSsoService(jscape.WebSsoService.TYPE.OPEN_ID_CONNECT), {signInUrl: signInUrl, tokenVerificationUrl: tokenVerificationUrl, clientId: clientId, clientSecret: clientSecret, nonSsoLoginAllowed: !!nonSsoLoginAllowed, accountTemplate: template, usernameConversion: usernameConversion});
};
jscape.WebSsoService.saml = function(signInUrl, signOutUrl, changePasswordUrl, decryptionKeyProvider, certificate, nameIdFormat, nonSsoLoginAllowed, template, usernameConversion) {
    return $.extend(new jscape.WebSsoService(jscape.WebSsoService.TYPE.SAML), {signInUrl: signInUrl, signOutUrl: signOutUrl, changePasswordUrl: changePasswordUrl, decryptionKeyProvider: decryptionKeyProvider, verificationHostKey: certificate, nameIdFormat: nameIdFormat, nonSsoLoginAllowed: !!nonSsoLoginAllowed, accountTemplate: template, usernameConversion: usernameConversion});
};

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

        this.authServiceController = new jscape.domain.AuthenticationServiceController();
        this.authServiceController.onCreate(this.managementService, this.domainName);

        this.twoFactorController = new jscape.domain.TwoFactorAuthServiceController();
        this.twoFactorController.onCreate(this.managementService, this.domainName);

        this.webSsoController = new jscape.domain.WebSsoAuthServiceController();
        this.webSsoController.onCreate(this.managementService, this.domainName);
    },

    onStart: function () {
        this.authServiceController.onStart();
        this.twoFactorController.onStart();
        this.webSsoController.onStart();
    },

    onPause: function() {
        this._confirmAndApply($.grep([
                                         this.authServiceController,
                                         this.twoFactorController,
                                         this.webSsoController
                                     ],
                                     function (controller) {
                                         return controller.hasChanged();
                                     }));
    },

    onResume: function() {
        this.authServiceController.onResume();
        this.twoFactorController.onResume();
        this.webSsoController.onResume();
    }
});

/** @class */
jscape.domain.AuthenticationServiceController = Class.extend(
    /** @lends {jscape.domain.AuthenticationServiceController.prototype} */
{
    DEFAULT_DESCRIPTOR: jscape.AuthService.domain(),

    view: null,
    descriptor: null,
    templates: null,

    /** @constructor */
    initialize: function() {
        this.controllers = {
            DOMAIN: jscape.domain.DomainAuthServiceController,
            DB: jscape.domain.DbAuthServiceController,
            DB_QUERY: jscape.domain.DbQueryAuthServiceController,
            LDAP: jscape.domain.LdapAuthServiceController,
            LDAP_QUERY: jscape.domain.LdapQueryAuthServiceController,
            NTLM: jscape.domain.NtlmAuthServiceController,
            PAM: jscape.domain.PamAuthServiceController,
            RADIUS: jscape.domain.RadiusAuthServiceController,
            CUSTOM: jscape.domain.CustomAuthServiceController,
            MULTIPLE: jscape.domain.MultipleAuthServiceController
        };
    },

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

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

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

    onResume: function () {
        $.when(this.managementService.getAuthenticationService(this.domainName),
               this.managementService.getAccountTemplateNames(this.domainName))
                .done($.proxy(function (descriptor, templates) { this.descriptor = descriptor; this.templates = templates.sort(); }, this))
                .fail($.proxy(function () { this.descriptor = this.DEFAULT_DESCRIPTOR; this.templates = []; }, this))
                .always($.proxy(function() { this._setupView(this.descriptor); }, this));
    },

    onApply: function () {
        var descriptor = this._createDescriptor();
        if (descriptor == null) {
            return $.Deferred().resolve().promise();
        }

        return this.managementService.setAuthenticationService(this.domainName, descriptor)
                .done($.proxy(function () { this.descriptor = descriptor; }, this))
                .done($.proxy(this._fireApplySuccess, this));
    },

    onDiscard: function () {
        $.each(this.controllers, function (_, controller) {
            if ($.type(controller) === "object") {
                controller.discardChanges();
            }
        });
        this._setupView(this.descriptor);
    },

    onChangeType: function (view) {
        var serviceType = (view.getType() || "").toUpperCase();
        $.each(this.controllers, $.proxy(function(type, controller) {
            var t = $.type(controller);
            if (serviceType === type) {
                if (t === "function") {
                    this.controllers[type] = new controller(view.container());
                    this.controllers[type].start(this.managementService, this.domainName, this.descriptor, this.templates);
                } else if (t === "object") {
                    controller.resume();
                }
            } else {
                if (t === "object") {
                    controller.pause();
                }
            }
        }, this));
    },

    _createDescriptor: function() {
        var controller = this.controllers[(this.view.getType() || "").toUpperCase()];
        return $.type(controller) === "object" ? controller.applyChanges() : this.DEFAULT_DESCRIPTOR;
    },

    _setupView: function (descriptor) {
        this.view.setType(descriptor && descriptor.type ? descriptor.type : this.DEFAULT_DESCRIPTOR.type);
    },

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

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

        this.type = $("select[name=type]", this.fieldset).combobox({
            required: true,
            editable: false,
            selectOnNavigation: false,
            onChange: $.proxy(this._onChange$Type, this),
            width: "20%",
            panelHeight: "auto"
        });

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

    container: function() {
        return this.fieldset;
    },

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

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

    setType: function(value) {
        var selectedType = this.type.combobox("getValue");
        this.type.combobox("clear").combobox("select", value);
        if (selectedType === value) {
            this._onChange$Type();
        }
    },

    _onChange$Type: function() {
        this.listener.onChangeType(this);
    },

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

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

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

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

    start: function(managementService, domainName, descriptor, templates) {
        this.managementService = managementService;
        this.domainName = domainName;
        this.descriptor = descriptor;
        this.templates = templates || [];

        this.view.show(this);
        this._setupView(this.descriptor);
    },

    resume: function () {
        this.view.show(this);
    },

    pause: function () {
        this.view.hide();
    },

    applyChanges: function () {
        return this.view.valid() ? this._createDescriptor() : null;
    },

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

    onTest: function() {
        this.testController.start(this.managementService, this.domainName, this._createDescriptor());
    },

    _createDescriptor: function () {
        return null;
    },

    _setupView: function (descriptor) {
    }
});

/** @class */
jscape.domain.BaseAuthServiceView = Class.extend(
    /** @lends {jscape.domain.BaseAuthServiceView.prototype} */
{
    show: function(listener) {
        this.listener = listener || jscape.domain.BaseAuthServiceController.LISTENER;
        this.fieldset.show()
                .on("focusin", $.proxy(function (e) {
                        var t = $(e.target);
                        if (!t.is(this.addVariable)) {
                            this._onChange$FocusIn(t);
                        }
                    }, this));
        this.fieldset.form("validate");
    },

    hide: function() {
        this.fieldset.hide();
    },

    valid: function() {
        return this.fieldset.form("validate");
    },

    _onClick$TestButton: function() {
        if (this.valid()) {
            this.listener.onTest(this);
        }
    },

    _onClick$AddVariableButton: function() {
        if (this.focusInField && this.focusInField.length) {
            this.addVariable.linkbutton("disable");
            this.listener.onAddVariable(this.focusInField);
        }
    },

    _onChange$FocusIn: function(field) {
        if (field && !field.is("[readonly]") && (field.is("[type=text]") || field.is("textarea"))) {
            this.focusInField = field;
            if (this.addVariable && this.addVariable.length) {
                this.addVariable.linkbutton("enable");
            }
        } else {
            if (this.addVariable && this.addVariable.length) {
                if (!this.addVariable.is(field)) {
                    this.focusInField = null;
                    this.addVariable.linkbutton("disable");
                }
            } else {
                this.focusInField = null;
            }
        }
    }
});
jscape.domain.BaseAuthServiceController.LISTENER = {
    onTest: $.noop,
    onAddVariable: $.noop
};

/** @class */
jscape.domain.DomainAuthServiceController = jscape.domain.BaseAuthServiceController.extend(
    /** @lends {jscape.domain.DomainAuthServiceController.prototype} */
{
    /** @constructor */
    initialize: function(container) {
        this.view = new jscape.domain.DomainAuthServiceView(container);
    },

    /** @override */
    _createDescriptor: function () {
        return jscape.AuthService.domain();
    }
});

/** @class */
jscape.domain.DomainAuthServiceView = jscape.domain.BaseAuthServiceView.extend(
    /** @lends {jscape.domain.DomainAuthServiceView.prototype} */
{
    /** @constructor */
    initialize: function(container) {
        this.fieldset = $("fieldset[name=domainauthfields]", container).first().hide();
    }
});

/** @class */
jscape.domain.DbAuthServiceController = jscape.domain.BaseAuthServiceController.extend(
    /** @lends {jscape.domain.DbAuthServiceController.prototype} */
{
    /** @constructor */
    initialize: function(container) {
        this._super();
        this.view = new jscape.domain.DbAuthServiceView(container);
    },

    /** @override */
    _createDescriptor: function () {
        return jscape.AuthService.db(this.view.getUrl(),
                                     this.view.getTemplate(),
                                     jscape.UsernameConversion.valueOf(this.view.getUsernameConversion()));
    },

    /** @override */
    _setupView: function (descriptor) {
        this.view.setTemplates(this.templates);

        if (descriptor && descriptor.type == jscape.AuthService.TYPE.DB) {
            this.view.setUrl(descriptor.url);
            this.view.setTemplate(descriptor.accountTemplate);
            this.view.setUsernameConversion(descriptor.usernameConversion == jscape.UsernameConversion.NONE ? null : descriptor.usernameConversion);
        }
    }
});

/** @class */
jscape.domain.DbAuthServiceView = jscape.domain.BaseAuthServiceView.extend(
    /** @lends {jscape.domain.DbAuthServiceView.prototype} */
{
    /** @constructor */
    initialize: function(container) {
        this.fieldset = $("fieldset[name=dbauthfields]", container).first().hide();

        this.url = $("input[name=dburl]", this.fieldset).textbox({
            required: true,
            validType: "length[1,2048]",
            missingMessage: window.R.string.AUTH_ERROR_BAD_DB_URL,
            invalidMessage: window.R.string.AUTH_ERROR_BAD_DB_URL,
            width: 350
        });

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

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

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

    getUrl: function() {
        return this.url.textbox("getValue").trim();
    },

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

    getTemplate: function() {
        return this.useTemplate.is(":checked") ? this.template.combobox("getValue") : null;
    },

    setTemplate: function(value) {
        this.template.combobox("select", value);
        this.useTemplate.prop("checked", value != null).change();
    },

    setTemplates: function(values) {
        this.template.combobox("loadData", values);
    },

    getUsernameConversion: function() {
        return this.useUsernameConversion.is(":checked") ? this.usernameConversion.combobox("getValue") : null;
    },

    setUsernameConversion: function(value) {
        this.useUsernameConversion.prop("checked", value != null).change();
        if (value != null) {
            this.usernameConversion.combobox("select", value);
        }
    }
});

/** @class */
jscape.domain.DbQueryAuthServiceController = jscape.domain.BaseAuthServiceController.extend(
    /** @lends {jscape.domain.DbQueryAuthServiceController.prototype} */
{
    VARIABLES: ["username", "password"],

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

        this.view = new jscape.domain.DbQueryAuthServiceView(container);
        this.variableController = new jscape.VariableController();
    },

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

    /** @override */
    _createDescriptor: function () {
        return jscape.AuthService.dbQuery(this.view.getUrl(),
                                          this.view.getUsername(),
                                          this.view.getPassword(),
                                          this.view.getQuery(),
                                          this.view.getHashClass(),
                                          this.view.getTemplate(),
                                          jscape.UsernameConversion.valueOf(this.view.getUsernameConversion()));
    },

    /** @override */
    _setupView: function (descriptor) {
        this.view.setTemplates(this.templates);

        if (descriptor && descriptor.type == jscape.AuthService.TYPE.DB_QUERY) {
            this.view.setUrl(descriptor.url);
            this.view.setUsername(descriptor.username);
            this.view.setPassword(descriptor.password);
            this.view.setQuery(descriptor.sql);
            this.view.setHashClass(descriptor.hasher);
            this.view.setTemplate(descriptor.accountTemplate);
            this.view.setUsernameConversion(descriptor.usernameConversion == jscape.UsernameConversion.NONE ? null : descriptor.usernameConversion);
        }
    }
});

/** @class */
jscape.domain.DbQueryAuthServiceView = jscape.domain.BaseAuthServiceView.extend(
    /** @lends {jscape.domain.DbQueryAuthServiceView.prototype} */
{
    /** @constructor */
    initialize: function(container) {
        this.fieldset = $("fieldset[name=dbqueryauthfields]", container).first().hide();

        this.url = $("input[name=dburl]", this.fieldset).textbox({required: true, validType: "length[1,2048]", missingMessage: window.R.string.AUTH_ERROR_BAD_DB_URL, invalidMessage: window.R.string.AUTH_ERROR_BAD_DB_URL, width: 410});
        this.username = $("input[name=dbuser]", this.fieldset).textbox({required: true, validType: "length[1,50]", missingMessage: window.R.string.AUTH_ERROR_BAD_DB_USER, invalidMessage: window.R.string.AUTH_ERROR_BAD_DB_USER, width: 250});
        this.password = $("input[name=dbpwd]", this.fieldset).textbox({type: "password", width: 250});
        this.query = $("textarea[name=query]", this.fieldset).textbox({required: true, multiline: true, validType: "length[1,2000]", missingMessage: window.R.string.AUTH_ERROR_BAD_DB_QUERY, invalidMessage: window.R.string.AUTH_ERROR_BAD_DB_QUERY, width: 610, height: 90});
        this.hashClass = $("input[name=hashclass]", this.fieldset).textbox({width: 310});

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

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

        this.addVariable = $("a[role=button][name=addvar]", this.fieldset).linkbutton({disabled: true, onClick: $.proxy(this._onClick$AddVariableButton, this)});
        this.testButton = $("a[role=button][name=test]", this.fieldset).linkbutton({onClick: $.proxy(this._onClick$TestButton, this)});
    },

    getUrl: function() {
        return this.url.textbox("getValue").trim();
    },

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

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

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

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

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

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

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

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

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

    getTemplate: function() {
        return this.useTemplate.is(":checked") ? this.template.combobox("getValue") : null;
    },

    setTemplate: function(value) {
        this.template.combobox("select", value);
        this.useTemplate.prop("checked", value != null).change();
    },

    setTemplates: function(values) {
        this.template.combobox("loadData", values);
    },

    getUsernameConversion: function() {
        return this.useUsernameConversion.is(":checked") ? this.usernameConversion.combobox("getValue") : null;
    },

    setUsernameConversion: function(value) {
        this.useUsernameConversion.prop("checked", value != null).change();
        if (value != null) {
            this.usernameConversion.combobox("select", value);
        }
    },

    _onChange$FocusIn: function(field) {
        if (this.query.textbox("textbox").is(field)) {
            this._super(field);
        } else {
            this._super(null);
        }
    }
});


/** @class */
jscape.domain.LdapAuthServiceController = jscape.domain.BaseAuthServiceController.extend(
    /** @lends {jscape.domain.LdapAuthServiceController.prototype} */
{
    VARIABLES: ["username", "password"],

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

        this.view = new jscape.domain.LdapAuthServiceView(container);
        this.variableController = new jscape.VariableController();
    },

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

    /** @override */
    _createDescriptor: function () {
        var failover = this.view.getFailoverHost() != null  ? {host: this.view.getFailoverHost(), port: this.view.getFailoverPort()} : null;
        return jscape.AuthService.ldap(this.view.getHost(),
                                       this.view.getPort(),
                                       this.view.getTimeout(),
                                       this.view.getUserDN(),
                                       this.view.isUseSsl(),
                                       this.view.isAnonymousAllowed(),
                                       this.view.getTemplate(),
                                       jscape.UsernameConversion.valueOf(this.view.getUsernameConversion()),
                                       failover);
    },

    /** @override */
    _setupView: function (descriptor) {
        this.view.setTemplates(this.templates);

        if (descriptor && descriptor.type == jscape.AuthService.TYPE.LDAP) {
            this.view.setHost(descriptor.host);
            this.view.setPort(descriptor.port);
            this.view.setTimeout(descriptor.timeout);
            this.view.setUserDN(descriptor.userDN);
            this.view.setUseSsl(descriptor.useSsl);
            this.view.setAnonymousAllowed(descriptor.anonymousAllowed);
            this.view.setTemplate(descriptor.accountTemplate);
            this.view.setUsernameConversion(descriptor.usernameConversion == jscape.UsernameConversion.NONE ? null : descriptor.usernameConversion);

            if (descriptor.failoverServers.length) {
                this.view.setFailoverHost(descriptor.failoverServers[0].host);
                this.view.setFailoverPort(descriptor.failoverServers[0].port);
            }
        }
    }
});

/** @class */
jscape.domain.LdapAuthServiceView = jscape.domain.BaseAuthServiceView.extend(
    /** @lends {jscape.domain.LdapAuthServiceView.prototype} */
{
    TIMEOUT_FACTOR: 1000,
    DEFAULT_PORT: 389,
    DEFAULT_TIMEOUT: 30,

    /** @constructor */
    initialize: function(container) {
        this.fieldset = $("fieldset[name=ldapauthfields]", container).first().hide();

        this.host = $("input[name=host]", this.fieldset).textbox({required: true, validType: "length[1,255]", missingMessage: window.R.string.AUTH_ERROR_BAD_LDAP_HOST, invalidMessage: window.R.string.AUTH_ERROR_BAD_LDAP_HOST, width: 410});
        this.port = $("input[name=port]", this.fieldset).numberspinner({required: true, min: 1, max: 65535, value: this.DEFAULT_PORT, width: 100});
        this.timeout = $("input[name=timeout]", this.fieldset).numberspinner({required: true, min: 1, max: 999, value: this.DEFAULT_TIMEOUT, width: 80});
        this.userDN = $("input[name=userdn]", this.fieldset).textbox({required: true, validType: "length[1,255]", missingMessage: window.R.string.AUTH_ERROR_BAD_USER_DN, invalidMessage: window.R.string.AUTH_ERROR_BAD_USER_DN, width: 410});

        this.useSsl = $("input[name=usessl]", this.fieldset);
        this.anonymousAllowed = $("input[name=allowanonymous]", this.fieldset);

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

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

        this.useFailover = $("input[name=usefailover]", this.fieldset);
        this.useFailover.change($.proxy(function() {
            var enabled = this.useFailover.is(":checked");
            this.failoverHost.textbox(enabled ? "enable" : "disable").textbox(enabled ? "enableValidation" : "disableValidation").textbox("isValid");
            this.failoverPort.numberspinner(enabled ? "enable" : "disable").numberspinner(enabled ? "enableValidation" : "disableValidation");
        }, this));

        this.failoverHost = $("input[name=failoverhost]", this.fieldset).textbox({required: true, disabled: true, validType: "length[1,255]", missingMessage: window.R.string.AUTH_ERROR_BAD_FAILOVER_HOST, invalidMessage: window.R.string.AUTH_ERROR_BAD_FAILOVER_HOST, width: 410});
        this.failoverPort = $("input[name=failoverport]", this.fieldset).numberspinner({required: true, disabled: true, min: 1, max: 65535, value: this.DEFAULT_PORT, width: 100});

        this.addVariable = $("a[role=button][name=addvar]", this.fieldset).linkbutton({disabled: true, onClick: $.proxy(this._onClick$AddVariableButton, this)});
        this.testButton = $("a[role=button][name=test]", this.fieldset).linkbutton({onClick: $.proxy(this._onClick$TestButton, this)});
    },

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

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

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

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

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

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

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

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

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

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

    isAnonymousAllowed: function() {
        return this.anonymousAllowed.is(":checked");
    },

    setAnonymousAllowed: function(value) {
        this.anonymousAllowed.prop("checked", !!value);
    },

    getTemplate: function() {
        return this.useTemplate.is(":checked") ? this.template.combobox("getValue") : null;
    },

    setTemplate: function(value) {
        this.template.combobox("select", value);
        this.useTemplate.prop("checked", value != null).change();
    },

    setTemplates: function(values) {
        this.template.combobox("loadData", values);
    },

    getUsernameConversion: function() {
        return this.useUsernameConversion.is(":checked") ? this.usernameConversion.combobox("getValue") : null;
    },

    setUsernameConversion: function(value) {
        this.useUsernameConversion.prop("checked", value != null).change();
        if (value != null) {
            this.usernameConversion.combobox("select", value);
        }
    },

    getFailoverHost: function() {
        return this.useFailover.is(":checked") ? this.failoverHost.textbox("getValue") : null;
    },

    setFailoverHost: function(value) {
        this.failoverHost.textbox("setValue", value);
        this.useFailover.prop("checked", !!value).change();
    },

    getFailoverPort: function() {
        return parseInt(this.failoverPort.numberspinner("getValue"));
    },

    setFailoverPort: function(value) {
        this.failoverPort.numberspinner("setValue", parseInt(value) || this.DEFAULT_PORT);
    }
});

/** @class */
jscape.domain.LdapQueryAuthServiceController = jscape.domain.BaseAuthServiceController.extend(
    /** @lends {jscape.domain.LdapQueryAuthServiceController.prototype} */
{
    VARIABLES: ["username", "password"],

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

        this.view = new jscape.domain.LdapQueryAuthServiceView(container);
        this.variableController = new jscape.VariableController();
    },

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

    /** @override */
    _createDescriptor: function () {
        var failover = this.view.getFailoverHost() != null  ? {host: this.view.getFailoverHost(), port: this.view.getFailoverPort()} : null;
        return jscape.AuthService.ldapQuery(this.view.getHost(),
                                            this.view.getPort(),
                                            this.view.getTimeout(),
                                            this.view.getUserDN(),
                                            this.view.getSearchUserDN(),
                                            this.view.getBaseDN(),
                                            this.view.getPassword(),
                                            this.view.getHasher(),
                                            this.view.getFilter(),
                                            this.view.isUseSsl(),
                                            this.view.isAnonymousAllowed(),
                                            this.view.getTemplate(),
                                            jscape.UsernameConversion.valueOf(this.view.getUsernameConversion()),
                                            failover);
    },

    /** @override */
    _setupView: function (descriptor) {
        this.view.setTemplates(this.templates);

        if (descriptor && descriptor.type == jscape.AuthService.TYPE.LDAP_QUERY) {
            this.view.setHost(descriptor.host);
            this.view.setPort(descriptor.port);
            this.view.setTimeout(descriptor.timeout);
            this.view.setUserDN(descriptor.userDN);
            this.view.setSearchUserDN(descriptor.searchUserDN);
            this.view.setBaseDN(descriptor.baseDN);
            this.view.setPassword(descriptor.password);
            this.view.setHasher(descriptor.hasher);
            this.view.setFilter(descriptor.filter);
            this.view.setUseSsl(descriptor.useSsl);
            this.view.setAnonymousAllowed(descriptor.anonymousAllowed);
            this.view.setTemplate(descriptor.accountTemplate);
            this.view.setUsernameConversion(descriptor.usernameConversion == jscape.UsernameConversion.NONE ? null : descriptor.usernameConversion);

            if (descriptor.failoverServers.length) {
                this.view.setFailoverHost(descriptor.failoverServers[0].host);
                this.view.setFailoverPort(descriptor.failoverServers[0].port);
            }
        }
    }
});

/** @class */
jscape.domain.LdapQueryAuthServiceView = jscape.domain.BaseAuthServiceView.extend(
    /** @lends {jscape.domain.LdapQueryAuthServiceView.prototype} */
{
    TIMEOUT_FACTOR: 1000,
    DEFAULT_TIMEOUT: 30,
    DEFAULT_PORT: 389,

    /** @constructor */
    initialize: function(container) {
        this.fieldset = $("fieldset[name=ldapqueryauthfields]", container).first().hide();

        this.host = $("input[name=host]", this.fieldset).textbox({required: true, validType: "length[1,255]", missingMessage: window.R.string.AUTH_ERROR_BAD_LDAP_HOST, invalidMessage: window.R.string.AUTH_ERROR_BAD_LDAP_HOST, width: 410});
        this.port = $("input[name=port]", this.fieldset).numberspinner({required: true, min: 1, max: 65535, value: this.DEFAULT_PORT, width: 100});
        this.timeout = $("input[name=timeout]", this.fieldset).numberspinner({required: true, min: 1, max: 999, value: this.DEFAULT_TIMEOUT, width: 80});
        this.userDN = $("input[name=userdn]", this.fieldset).textbox({required: true, validType: "length[1,255]", missingMessage: window.R.string.AUTH_ERROR_BAD_USER_DN, invalidMessage: window.R.string.AUTH_ERROR_BAD_USER_DN, width: 410});
        this.searchUserDN = $("input[name=searchuserdn]", this.fieldset).textbox({required: true, validType: "length[1,255]", missingMessage: window.R.string.AUTH_ERROR_BAD_SEARCH_USER_DN, invalidMessage: window.R.string.AUTH_ERROR_BAD_SEARCH_USER_DN, width: 410});

        this.password = $("input[name=password]", this.fieldset).textbox({type: "password", width: 410});
        this.baseDN = $("input[name=basedn]", this.fieldset).textbox({width: 410});
        this.filter = $("textarea[name=filter]", this.fieldset).textbox({required: true, multiline: true, validType: "length[1,2000]", missingMessage: window.R.string.AUTH_ERROR_BAD_FILTER, invalidMessage: window.R.string.AUTH_ERROR_BAD_FILTER, width: 610, height: 90});
        this.hasher = $("input[name=hasher]", this.fieldset).textbox({width: 410});

        this.useSsl = $("input[name=usessl]", this.fieldset);
        this.anonymousAllowed = $("input[name=allowanonymous]", this.fieldset);

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

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

        this.useFailover = $("input[name=usefailover]", this.fieldset);
        this.useFailover.change($.proxy(function() {
            var enabled = this.useFailover.is(":checked");
            this.failoverHost.textbox(enabled ? "enable" : "disable").textbox(enabled ? "enableValidation" : "disableValidation").textbox("isValid");
            this.failoverPort.numberspinner(enabled ? "enable" : "disable").numberspinner(enabled ? "enableValidation" : "disableValidation");
        }, this));

        this.failoverHost = $("input[name=failoverhost]", this.fieldset).textbox({required: true, disabled: true, validType: "length[1,255]", missingMessage: window.R.string.AUTH_ERROR_BAD_FAILOVER_HOST, invalidMessage: window.R.string.AUTH_ERROR_BAD_FAILOVER_HOST, width: 410});
        this.failoverPort = $("input[name=failoverport]", this.fieldset).numberspinner({required: true, disabled: true, min: 1, max: 65535, value: this.DEFAULT_PORT, width: 100});

        this.addVariable = $("a[role=button][name=addvar]", this.fieldset).linkbutton({disabled: true, onClick: $.proxy(this._onClick$AddVariableButton, this)});
        this.testButton = $("a[role=button][name=test]", this.fieldset).linkbutton({onClick: $.proxy(this._onClick$TestButton, this)});
    },

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    isAnonymousAllowed: function() {
        return this.anonymousAllowed.is(":checked");
    },

    setAnonymousAllowed: function(value) {
        this.anonymousAllowed.prop("checked", !!value);
    },

    getTemplate: function() {
        return this.useTemplate.is(":checked") ? this.template.combobox("getValue") : null;
    },

    setTemplate: function(value) {
        this.template.combobox("select", value);
        this.useTemplate.prop("checked", value != null).change();
    },

    setTemplates: function(values) {
        this.template.combobox("loadData", values);
    },

    getUsernameConversion: function() {
        return this.useUsernameConversion.is(":checked") ? this.usernameConversion.combobox("getValue") : null;
    },

    setUsernameConversion: function(value) {
        this.useUsernameConversion.prop("checked", value != null).change();
        if (value != null) {
            this.usernameConversion.combobox("select", value);
        }
    },

    getFailoverHost: function() {
        return this.useFailover.is(":checked") ? this.failoverHost.textbox("getValue") : null;
    },

    setFailoverHost: function(value) {
        this.failoverHost.textbox("setValue", value);
        this.useFailover.prop("checked", !!value).change();
    },

    getFailoverPort: function() {
        return parseInt(this.failoverPort.numberspinner("getValue"));
    },

    setFailoverPort: function(value) {
        this.failoverPort.numberspinner("setValue", parseInt(value) || this.DEFAULT_PORT);
    }
});

/** @class */
jscape.domain.NtlmAuthServiceController = jscape.domain.BaseAuthServiceController.extend(
    /** @lends {jscape.domain.NtlmAuthServiceController.prototype} */
{
    /** @constructor */
    initialize: function(container) {
        this._super();
        this.view = new jscape.domain.NtlmAuthServiceView(container);
    },

    /** @override */
    _createDescriptor: function () {
        return jscape.AuthService.ntlm(this.view.getHost(),
                                       this.view.getDomain(),
                                       this.view.getTemplate(),
                                       jscape.UsernameConversion.valueOf(this.view.getUsernameConversion()));
    },

    /** @override */
    _setupView: function (descriptor) {
        this.view.setTemplates(this.templates);

        if (descriptor && descriptor.type == jscape.AuthService.TYPE.NTLM) {
            this.view.setHost(descriptor.host);
            this.view.setDomain(descriptor.windowsDomain);
            this.view.setTemplate(descriptor.accountTemplate);
            this.view.setUsernameConversion(descriptor.usernameConversion == jscape.UsernameConversion.NONE ? null : descriptor.usernameConversion);
        }
    }
});

/** @class */
jscape.domain.NtlmAuthServiceView = jscape.domain.BaseAuthServiceView.extend(
    /** @lends {jscape.domain.NtlmAuthServiceView.prototype} */
{
    /** @constructor */
    initialize: function(container) {
        this.fieldset = $("fieldset[name=ntlmauthfields]", container).first().hide();

        this.host = $("input[name=host]", this.fieldset).textbox({required: true, validType: "length[1,255]", missingMessage: window.R.string.AUTH_ERROR_BAD_NTLM_HOST, invalidMessage: window.R.string.AUTH_ERROR_BAD_NTLM_HOST, width: 410});
        this.domain = $("input[name=domain]", this.fieldset).textbox({required: true, validType: "length[1,255]", missingMessage: window.R.string.AUTH_ERROR_BAD_NTLM_DOMAIN, invalidMessage: window.R.string.AUTH_ERROR_BAD_NTLM_DOMAIN, width: 410});

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

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

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

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

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

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

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

    getTemplate: function() {
        return this.useTemplate.is(":checked") ? this.template.combobox("getValue") : null;
    },

    setTemplate: function(value) {
        this.template.combobox("select", value);
        this.useTemplate.prop("checked", value != null).change();
    },

    setTemplates: function(values) {
        this.template.combobox("loadData", values);
    },

    getUsernameConversion: function() {
        return this.useUsernameConversion.is(":checked") ? this.usernameConversion.combobox("getValue") : null;
    },

    setUsernameConversion: function(value) {
        this.useUsernameConversion.prop("checked", value != null).change();
        if (value != null) {
            this.usernameConversion.combobox("select", value);
        }
    }
});

/** @class */
jscape.domain.PamAuthServiceController = jscape.domain.BaseAuthServiceController.extend(
    /** @lends {jscape.domain.PamAuthServiceController.prototype} */
{
    /** @constructor */
    initialize: function(container) {
        this._super();
        this.view = new jscape.domain.PamAuthServiceView(container);
    },

    /** @override */
    _createDescriptor: function () {
        return jscape.AuthService.pam(this.view.isDebugEnabled(),
                                      this.view.getTemplate(),
                                      jscape.UsernameConversion.valueOf(this.view.getUsernameConversion()));
    },

    /** @override */
    _setupView: function (descriptor) {
        this.view.setTemplates(this.templates);

        if (descriptor && descriptor.type == jscape.AuthService.TYPE.PAM) {
            this.view.setDebugEnabled(descriptor.debugEnabled);
            this.view.setTemplate(descriptor.accountTemplate);
            this.view.setUsernameConversion(descriptor.usernameConversion == jscape.UsernameConversion.NONE ? null : descriptor.usernameConversion);
        }
    }
});

/** @class */
jscape.domain.PamAuthServiceView = jscape.domain.BaseAuthServiceView.extend(
    /** @lends {jscape.domain.PamAuthServiceView.prototype} */
{
    /** @constructor */
    initialize: function(container) {
        this.fieldset = $("fieldset[name=pamauthfields]", container).first().hide();

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

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

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

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

    isDebugEnabled: function() {
        return this.debug.is(":checked");
    },

    setDebugEnabled: function(value) {
        this.debug.prop("checked", !!value);
    },

    getTemplate: function() {
        return this.useTemplate.is(":checked") ? this.template.combobox("getValue") : null;
    },

    setTemplate: function(value) {
        this.template.combobox("select", value);
        this.useTemplate.prop("checked", value != null).change();
    },

    setTemplates: function(values) {
        this.template.combobox("loadData", values);
    },

    getUsernameConversion: function() {
        return this.useUsernameConversion.is(":checked") ? this.usernameConversion.combobox("getValue") : null;
    },

    setUsernameConversion: function(value) {
        this.useUsernameConversion.prop("checked", value != null).change();
        if (value != null) {
            this.usernameConversion.combobox("select", value);
        }
    }
});

/** @class */
jscape.domain.RadiusAuthServiceController = jscape.domain.BaseAuthServiceController.extend(
    /** @lends {jscape.domain.RadiusAuthServiceController.prototype} */
{
    inetAddresses: null,

    /** @constructor */
    initialize: function(container) {
        this._super();
        this.view = new jscape.domain.RadiusAuthServiceView(container);
    },

    /** @override */
    start: function (managementService) {
        ($.proxy(function (_super, _args) {
            managementService.getServerAddresses()
                    .done($.proxy(function (addresses) { this.inetAddresses = addresses; }, this))
                    .fail($.proxy(function () { this.inetAddresses = []; }, this))
                    .always($.proxy(function () { _super.apply(this, _args); }, this));
        }, this))(this._super, arguments);
    },

    /** @override */
    _createDescriptor: function () {
        return jscape.AuthService.radius(this.view.getLocalHost(),
                                         this.view.getServerHost(),
                                         this.view.getServerPort(),
                                         this.view.getTimeout(),
                                         this.view.getMaxRetransmitAttempts(),
                                         this.view.getIdentifier(),
                                         this.view.getSharedSecret(),
                                         this.view.getTemplate(),
                                         jscape.UsernameConversion.valueOf(this.view.getUsernameConversion()));
    },

    /** @override */
    _setupView: function (descriptor) {
        this.view.setTemplates(this.templates);
        this.view.setAvailableHosts(this.inetAddresses);

        if (descriptor && descriptor.type == jscape.AuthService.TYPE.RADIUS) {
            this.view.setLocalHost(descriptor.localhost);
            this.view.setServerHost(descriptor.serverhost);
            this.view.setServerPort(descriptor.serverport);
            this.view.setTimeout(descriptor.timeout);
            this.view.setMaxRetransmitAttempts(descriptor.maxRetransmitAttempts);
            this.view.setIdentifier(descriptor.identifier);
            this.view.setSharedSecret(descriptor.sharedSecret);
            this.view.setTemplate(descriptor.accountTemplate);
            this.view.setUsernameConversion(descriptor.usernameConversion == jscape.UsernameConversion.NONE ? null : descriptor.usernameConversion);
        }
    }
});

/** @class */
jscape.domain.RadiusAuthServiceView = jscape.domain.BaseAuthServiceView.extend(
    /** @lends {jscape.domain.RadiusAuthServiceView.prototype} */
{
    DEFAULTS: {serverPort: 1812, timeout: 30, retransmitAttempts: 3},
    TIMEOUT_FACTOR: 1000,

    /** @constructor */
    initialize: function(container) {
        this.fieldset = $("fieldset[name=radiusauthfields]", container).first().hide();

        this.localHost = $("select[name=localhost]", this.fieldset).combobox({required: true, validType: "length[1,255]", missingMessage: window.R.string.AUTH_ERROR_BAD_RADIUS_HOST, invalidMessage: window.R.string.AUTH_ERROR_BAD_RADIUS_HOST, width: 200,  panelHeight: "auto"});
        this.serverHost = $("input[name=serverhost]", this.fieldset).textbox({required: true, validType: "length[1,255]", missingMessage: window.R.string.AUTH_ERROR_BAD_RADIUS_HOST, invalidMessage: window.R.string.AUTH_ERROR_BAD_RADIUS_HOST, width: 410});
        this.serverPort = $("input[name=serverport]", this.fieldset).numberspinner({required: true, min: 1, max: 65535, value: this.DEFAULTS.serverPort, width: 100});
        this.timeout = $("input[name=timeout]", this.fieldset).numberspinner({required: true, min: 1, max: 999, value: this.DEFAULTS.timeout, width: 80});

        this.retransmitAttempts = $("input[name=retransmitattempts]", this.fieldset).numberspinner({required: true, min: 1, max: 100, value: this.DEFAULTS.retransmitAttempts, width: 60});
        this.identifier = $("input[name=identifier]", this.fieldset).textbox({required: true, missingMessage: window.R.string.AUTH_ERROR_BAD_RADIUS_ID, invalidMessage: window.R.string.AUTH_ERROR_BAD_RADIUS_ID, width: 410});
        this.sharedSecret = $("input[name=secret]", this.fieldset).textbox({required: true, missingMessage: window.R.string.AUTH_ERROR_BAD_RADIUS_SECRET, invalidMessage: window.R.string.AUTH_ERROR_BAD_RADIUS_SECRET, width: 410});

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

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

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

    getLocalHost: function() {
        return this.localHost.combobox("getValue");
    },

    setLocalHost: function(value) {
        this.localHost.combobox("setValue", value);
    },

    setAvailableHosts: function(values) {
        this.localHost.combobox("loadData", values);
    },

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

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

    getServerPort: function() {
        return parseInt(this.serverPort.numberspinner("getValue"));
    },

    setServerPort: function(value) {
        this.serverPort.numberspinner("setValue", parseInt(value) || this.DEFAULTS.serverPort);
    },

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

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

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

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

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

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

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

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

    getTemplate: function() {
        return this.useTemplate.is(":checked") ? this.template.combobox("getValue") : null;
    },

    setTemplate: function(value) {
        this.template.combobox("select", value);
        this.useTemplate.prop("checked", value != null).change();
    },

    setTemplates: function(values) {
        this.template.combobox("loadData", values);
    },

    getUsernameConversion: function() {
        return this.useUsernameConversion.is(":checked") ? this.usernameConversion.combobox("getValue") : null;
    },

    setUsernameConversion: function(value) {
        this.useUsernameConversion.prop("checked", value != null).change();
        if (value != null) {
            this.usernameConversion.combobox("select", value);
        }
    }
});

/** @class */
jscape.domain.CustomAuthServiceController = jscape.domain.BaseAuthServiceController.extend(
    /** @lends {jscape.domain.CustomAuthServiceController.prototype} */
{
    /** @constructor */
    initialize: function(container) {
        this._super();
        this.view = new jscape.domain.CustomAuthServiceView(container);
    },

    /** @override */
    _createDescriptor: function () {
        return jscape.AuthService.custom(this.view.getClassName(),
                                         this.view.getTemplate(),
                                         jscape.UsernameConversion.valueOf(this.view.getUsernameConversion()));
    },

    /** @override */
    _setupView: function (descriptor) {
        this.view.setTemplates(this.templates);

        if (descriptor && descriptor.type == jscape.AuthService.TYPE.CUSTOM) {
            this.view.setClassName(descriptor.className);
            this.view.setTemplate(descriptor.accountTemplate);
            this.view.setUsernameConversion(descriptor.usernameConversion == jscape.UsernameConversion.NONE ? null : descriptor.usernameConversion);
        }
    }
});

/** @class */
jscape.domain.CustomAuthServiceView = jscape.domain.BaseAuthServiceView.extend(
    /** @lends {jscape.domain.CustomAuthServiceView.prototype} */
{
    /** @constructor */
    initialize: function(container) {
        this.fieldset = $("fieldset[name=customauthfields]", container).first().hide();

        this.className = $("input[name=classname]", this.fieldset).textbox({required: true, validType: "length[1,255]", missingMessage: window.R.string.AUTH_ERROR_BAD_CLASS, invalidMessage: window.R.string.AUTH_ERROR_BAD_CLASS, width: 500});

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

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

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

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

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

    getTemplate: function() {
        return this.useTemplate.is(":checked") ? this.template.combobox("getValue") : null;
    },

    setTemplate: function(value) {
        this.template.combobox("select", value);
        this.useTemplate.prop("checked", value != null).change();
    },

    setTemplates: function(values) {
        this.template.combobox("loadData", values);
    },

    getUsernameConversion: function() {
        return this.useUsernameConversion.is(":checked") ? this.usernameConversion.combobox("getValue") : null;
    },

    setUsernameConversion: function(value) {
        this.useUsernameConversion.prop("checked", value != null).change();
        if (value != null) {
            this.usernameConversion.combobox("select", value);
        }
    }
});

/** @class */
jscape.domain.MultipleAuthServiceController = jscape.domain.BaseAuthServiceController.extend(
    /** @lends {jscape.domain.CustomAuthServiceController.prototype} */
{
    /** @constructor */
    initialize: function(container) {
        this.view = new jscape.domain.MultipleAuthServiceView(container);

        this.primaryController = new jscape.domain.UserMultipleAuthServiceController(this.view.primaryServiceView());
        this.secondaryController = new jscape.domain.UserMultipleAuthServiceController(this.view.secondaryServiceView());
    },

    start: function(managementService, domainName, descriptor, templates) {
        this.managementService = managementService;
        this.domainName = domainName;
        this.view.show(this);

        this.primaryController.start(managementService, domainName, descriptor.primary, templates);
        this.secondaryController.start(managementService, domainName, descriptor.secondary, templates);
    },

    resume: function () {
        this.view.show(this);
    },

    pause: function () {
        this.view.hide();
    },

    applyChanges: function () {
        return this._createDescriptor();
    },

    discardChanges: function() {
        this.primaryController.discardChanges();
        this.secondaryController.discardChanges();
    },

    _createDescriptor: function () {
        return jscape.AuthService.multiple(this.primaryController._createDescriptor(), this.secondaryController._createDescriptor());
    }
});

/** @class */
jscape.domain.MultipleAuthServiceView = jscape.domain.BaseAuthServiceView.extend(
    /** @lends {jscape.domain.MultipleAuthServiceView.prototype} */
{
    /** @constructor */
    initialize: function(container) {
        this.fieldset = $("fieldset[name=multipleauthfields]", container).first().hide();

        this.primaryView = new jscape.domain.UserMultipleAuthServiceView(
                $("fieldset[name=primaryauthfields]", this.fieldset),
                $("select[name=primaryauthtype]", this.fieldset)
        );
        this.secondaryView = new jscape.domain.UserMultipleAuthServiceView(
                $("fieldset[name=secondaryauthfields]", this.fieldset),
                $("select[name=secondaryauthtype]", this.fieldset)
        );
    },

    primaryServiceView: function() {
        return this.primaryView;
    },

    secondaryServiceView: function() {
        return this.secondaryView;
    },

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

    hide: function() {
        this.fieldset.hide();
    },

    valid: function() {
        return this.fieldset.form("validate");
    }
});
jscape.domain.MultipleAuthServiceView.LISTENER = {
    onTest: $.noop
};

/** @class */
jscape.domain.UserMultipleAuthServiceController = jscape.domain.BaseAuthServiceController.extend(
    /** @lends {jscape.domain.UserMultipleAuthServiceController.prototype} */
{
    DEFAULT_DESCRIPTOR: jscape.AuthService.domain(),

    descriptor: null,
    templates: null,

    /** @constructor */
    initialize: function(view) {
        this.view = view;

        this.controllers = {
            DOMAIN: jscape.domain.DomainAuthServiceController,
            DB: jscape.domain.DbAuthServiceController,
            DB_QUERY: jscape.domain.DbQueryAuthServiceController,
            LDAP: jscape.domain.LdapAuthServiceController,
            LDAP_QUERY: jscape.domain.LdapQueryAuthServiceController,
            NTLM: jscape.domain.NtlmAuthServiceController,
            PAM: jscape.domain.PamAuthServiceController,
            RADIUS: jscape.domain.RadiusAuthServiceController,
            CUSTOM: jscape.domain.CustomAuthServiceController
        };
    },

    start: function(managementService, domainName, descriptor, templates) {
        this.managementService = managementService;
        this.domainName = domainName;
        this.descriptor = descriptor;
        this.templates = templates || [];

        this.view.show(this);
        this._setupView(this.descriptor);
    },

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

    /** @override */
    discardChanges: function () {
        $.each(this.controllers, function (_, controller) {
            if ($.type(controller) === "object") {
                controller.discardChanges();
            }
        });
        this._setupView(this.descriptor);
    },

    onChangeType: function (view) {
        var serviceType = (view.getType() || "").toUpperCase();
        $.each(this.controllers, $.proxy(function(type, controller) {
            var t = $.type(controller);
            if (serviceType === type) {
                if (t === "function") {
                    this.controllers[type] = new controller(view.container());
                    this.controllers[type].start(this.managementService, this.domainName, this.descriptor, this.templates);
                } else if (t === "object") {
                    controller.resume();
                }
            } else {
                if (t === "object") {
                    controller.pause();
                }
            }
        }, this));
    },

    _createDescriptor: function() {
        var controller = this.controllers[(this.view.getType() || "").toUpperCase()];
        return $.type(controller) === "object" ? controller.applyChanges() : this.DEFAULT_DESCRIPTOR;
    },

    _setupView: function (descriptor) {
        this.view.setType(descriptor && descriptor.type ? descriptor.type : this.DEFAULT_DESCRIPTOR.type);
    }
});

/** @class */
jscape.domain.UserMultipleAuthServiceView = jscape.domain.BaseAuthServiceView.extend(
    /** @lends {jscape.domain.UserMultipleAuthServiceView.prototype} */
{
    /** @constructor */
    initialize: function(fieldset, type) {
        this.fieldset = fieldset;
        this.type = type.combobox({
            required: true,
            editable: false,
            selectOnNavigation: false,
            onChange: $.proxy(this._onChange$Type, this),
            width: 310,
            panelHeight: "auto"
        });
    },

    container: function() {
        return this.fieldset;
    },

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

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

    setType: function(value) {
        var selectedType = this.type.combobox("getValue");
        this.type.combobox("clear").combobox("select", value);
        if (selectedType === value) {
            this._onChange$Type();
        }
    },

    _onChange$Type: function() {
        this.listener.onChangeType(this);
    }
});
jscape.domain.UserMultipleAuthServiceView.LISTENER = {
    onChangeType: $.noop
};

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

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

    onSubmit: function(dialog) {
        var username = dialog.getUsername();
        var password = dialog.getPassword();
        var clientIp = dialog.getClientIp();
        dialog.destroy();

        this.managementService.testAuthenticationService(this.domainName, this.descriptor, username, password, clientIp)
                .done($.proxy(this._testPassed, this))
                .fail($.proxy(this._testFailed, this));
    },

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

    _setupDialog: function() {
        return new jscape.domain.TestAuthCredentialsDialog();
    },

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

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

/** @class */
jscape.domain.TestAuthCredentialsDialog = Class.extend(
    /** @lends {jscape.domain.TestAuthCredentialsDialog.prototype} */
{
    /** @constructor */
    initialize: function() {
        this.dialog = $("#d-auth-credentials").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=testauthcredentialsfields]", this.dialog);

        this.username = $("input[name=username]", this.fieldset).textbox({width: "60%"});
        this.password = $("input[name=password]", this.fieldset).textbox({type: "password", width: "60%"});
        this.clientIp = $("input[name=clientip]", this.fieldset).textbox({width: "50%"});
    },

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

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

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

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

/** @class */
jscape.domain.TwoFactorAuthServiceController = Class.extend(
    /** @lends {jscape.domain.TwoFactorAuthServiceController.prototype} */
{
    DEFAULT_DESCRIPTOR: jscape.UserConfirmationService.none(),

    view: null,
    descriptor: null,

    /** @constructor */
    initialize: function() {
        this.controllers = {
            NONE: null,
            PHONE: jscape.domain.PhoneFactorServiceController,
            TOTP: jscape.domain.TotpUserConfirmationServiceController,
            CUSTOM: jscape.domain.CustomUserConfirmationServiceController
        };
    },

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

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

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

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

    onApply: function () {
        var descriptor = this._createDescriptor();
        if (descriptor == null) {
            return $.Deferred().reject().promise();
        }

        return this.managementService.setTwoFactorService(this.domainName, descriptor)
                .done($.proxy(function (descriptor) { this.descriptor = descriptor; }, this))
                .done($.proxy(this._fireApplySuccess, this));
    },

    onDiscard: function () {
        $.each(this.controllers, function (_, controller) {
            if ($.type(controller) === "object") {
                controller.discardChanges();
            }
        });
        this._setupView();
    },

    onChangeType: function (view) {
        var serviceType = (view.getType() || "").toUpperCase();
        $.each(this.controllers, $.proxy(function(type, controller) {
            var t = $.type(controller);
            if (serviceType === type) {
                if (t === "function") {
                    this.controllers[type] = new controller(view.container());
                    this.controllers[type].start(this.managementService, this.domainName, this.descriptor);
                } else if (t === "object") {
                    controller.resume();
                }
            } else {
                if (t === "object") {
                    controller.pause();
                }
            }
        }, this));
    },

    _createDescriptor: function() {
        var controller = this.controllers[(this.view.getType() || "").toUpperCase()];
        return $.type(controller) === "object" ? controller.applyChanges() : this.DEFAULT_DESCRIPTOR;
    },

    _setupView: function (descriptor) {
        this.view.setType(descriptor && descriptor.type ? descriptor.type : this.DEFAULT_DESCRIPTOR.type);
    },

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

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

        this.type = $("select[name=type]", this.fieldset).combobox({
            required: true,
            editable: false,
            width: "25%",
            panelHeight: "auto",
            onChange: $.proxy(this._onChange$Type, this)
        });

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

    container: function() {
        return this.fieldset;
    },

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

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

    setType: function(value) {
        var selectedType = this.type.combobox("getValue");
        this.type.combobox("clear").combobox("select", value);
        if (selectedType === value) {
            this._onChange$Type();
        }
    },

    _onChange$Type: function() {
        this.listener.onChangeType(this);
    },

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

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

/** @class */
jscape.domain.PhoneFactorServiceController = jscape.domain.BaseAuthServiceController.extend(
    /** @lends {jscape.domain.PhoneFactorServiceController.prototype} */
{
    VARIABLES: ["installdir"],

    /** @constructor */
    initialize: function() {
        this._super();
        this.view = new jscape.domain.PhoneFactorServiceView();
        this.variableController = new jscape.VariableController();
    },

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

    onSelectPath: function() {
        new SelectPathController($.proxy(this.managementService.listFileSystem, this.managementService),
                                 $.proxy(this.managementService.createFileSystemDir, this.managementService))
                .selectPath()
                .done($.proxy(function(entry) { this.view.setDirectory(entry.path); }, this));
    },

    /** @override */
    _createDescriptor: function () {
        return jscape.UserConfirmationService.phoneFactor(this.view.getDirectory(),
                                                          this.view.getPassword(),
                                                          this.view.isInternationalCallsAllowed());
    },

    /** @override */
    _setupView: function (descriptor) {
        if (descriptor && jscape.UserConfirmationService.TYPE.PHONE == descriptor.type) {
            this.view.setDirectory(descriptor.licenseDirectory);
            this.view.setPassword(descriptor.password);
            this.view.setInternationalCallsAllowed(descriptor.internationalCallsAllowed);
        }
    }
});

/** @class */
jscape.domain.PhoneFactorServiceView = jscape.domain.BaseAuthServiceView.extend(
    /** @lends {jscape.domain.PhoneFactorServiceView.prototype} */
{
    /** @constructor */
    initialize: function() {
        this.fieldset = $("fieldset[name=phonefactorauthfields]").hide();

        this.directory = $("input[name=dir]", this.fieldset).textbox({required: true, validType: "length[1,500]", missingMessage: window.R.string.AUTH_ERROR_BAD_PHONE_DIR, invalidMessage: window.R.string.AUTH_ERROR_BAD_PHONE_DIR, tipPosition: "bottom", width: 610});
        this.browseDir = $("a[role=button][name=browsedir]", this.fieldset).linkbutton({onClick: $.proxy(this._onClick$BrowseDirectory, this)});

        this.password = $("input[name=password]", this.fieldset).textbox({type: "password", width: 410});

        this.allowInternationalCall = $("input[name=allowinterncall]:checkbox", this.fieldset);
        this.addVariable = $("a[role=button][name=addvar]", this.fieldset).linkbutton({disabled: true, onClick: $.proxy(this._onClick$AddVariableButton, this)});
    },

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

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

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

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

    isInternationalCallsAllowed: function() {
        return this.allowInternationalCall.is(":checked");
    },

    setInternationalCallsAllowed: function(value) {
        this.allowInternationalCall.prop("checked", !!value);
    },

    _onClick$BrowseDirectory: function() {
        this.listener.onSelectPath(this);
    }
});

/** @class */
jscape.domain.CustomUserConfirmationServiceController = jscape.domain.BaseAuthServiceController.extend(
    /** @lends {jscape.domain.CustomUserConfirmationServiceController.prototype} */
{
    /** @constructor */
    initialize: function() {
        this._super();
        this.view = new jscape.domain.CustonUserConfirmationServiceView();
    },

    /** @override */
    _createDescriptor: function () {
        return jscape.UserConfirmationService.custom(this.view.getClassName());
    },

    /** @override */
    _setupView: function (descriptor) {
        if (descriptor && jscape.UserConfirmationService.TYPE.CUSTOM == descriptor.type) {
            this.view.setClassName(descriptor.serviceClassName);
        }
    }
});

/** @class */
jscape.domain.CustonUserConfirmationServiceView = jscape.domain.BaseAuthServiceView.extend(
    /** @lends {jscape.domain.CustonUserConfirmationServiceView.prototype} */
{
    /** @constructor */
    initialize: function() {
        this.fieldset = $("fieldset[name=customuserconfirmfields]").hide();

        this.className = $("input[name=classname]", this.fieldset).textbox({required: true, validType: "length[1,255]", missingMessage: window.R.string.AUTH_ERROR_BAD_CLASS, invalidMessage: window.R.string.AUTH_ERROR_BAD_CLASS, width: 500});
    },

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

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

/** @class */
jscape.domain.TotpUserConfirmationServiceController = jscape.domain.BaseAuthServiceController.extend(
    /** @lends {jscape.domain.TotpUserConfirmationServiceController.prototype} */
{
    /** @constructor */
    initialize: function() {
        this._super();
        this.view = new jscape.domain.TotpUserConfirmationServiceControllerView();
    },

    /** @override */
    _createDescriptor: function () {
        return jscape.UserConfirmationService.totp();
    },

    /** @override */
    _setupView: function (descriptor) {
        if (descriptor && jscape.UserConfirmationService.TYPE.TOTP == descriptor.type) {
            //empty
        }
    }
});

/** @class */
jscape.domain.TotpUserConfirmationServiceControllerView = jscape.domain.BaseAuthServiceView.extend(
    /** @lends {jscape.domain.TotpUserConfirmationServiceControllerView.prototype} */
{
    /** @constructor */
    initialize: function() {
        this.fieldset = $("fieldset[name=totpuserconfirmfields]").hide();
    }
});

/** @class */
jscape.domain.WebSsoAuthServiceController = Class.extend(
    /** @lends {jscape.WebSsoAuthServiceController.prototype} */
{
    DEFAULT_DESCRIPTOR: jscape.AuthService.none(),

    view: null,
    templates: null,
    descriptor: null,

    /** @constructor */
    initialize: function() {
        this.controllers = {
            NONE: null,
            OPEN_ID: jscape.domain.OpenIdAuthServiceController,
            OPEN_ID_CONNECT: jscape.domain.OpenIdConnectAuthServiceController,
            SAML: jscape.domain.SamlAuthServiceController
        };
    },

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

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

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

    onResume: function () {
        $.when(this.managementService.getWebSsoService(this.domainName),
               this.managementService.getAccountTemplateNames(this.domainName))
                .done($.proxy(function (descriptor, templates) { this.descriptor = descriptor; this.templates = templates.sort(); }, this))
                .fail($.proxy(function() { this.descriptor = this.DEFAULT_DESCRIPTOR; this.templates = []; }, this))
                .always($.proxy(this._setupView, this));
    },

    onApply: function () {
        var descriptor = this._createDescriptor();
        if (descriptor == null) {
            return $.Deferred().reject().promise();
        }

        return this.managementService.setWebSsoService(this.domainName, descriptor)
                .done($.proxy(function () { this.descriptor = descriptor; }, this))
                .done($.proxy(this._fireApplySuccess, this));
    },

    onDiscard: function () {
        $.each(this.controllers, function(_, controller) {
            if ($.type(controller) === "object") {
                controller.discardChanges();
            }
        });
        this._setupView();
    },

    onChangeType: function (view) {
        var serviceType = (view.getType() || "").toUpperCase();
        $.each(this.controllers, $.proxy(function(type, controller) {
            var t = $.type(controller);
            if (serviceType === type) {
                if (t === "function") {
                    this.controllers[type] = new controller(view.container());
                    this.controllers[type].start(this.managementService, this.domainName, this.descriptor, this.templates);
                } else if (t === "object") {
                    controller.resume(this.descriptor, this.templates);
                }
            } else {
                if (t === "object") {
                    controller.pause();
                }
            }
        }, this));
    },

    _createDescriptor: function() {
        var controller = this.controllers[(this.view.getType() || "").toUpperCase()];
        return $.type(controller) === "object" ? controller.applyChanges() : this.DEFAULT_DESCRIPTOR;
    },

    _setupView: function (descriptor) {
        this.view.setType(descriptor && descriptor.type ? descriptor.type : this.DEFAULT_DESCRIPTOR.type);
    },

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

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

        this.type = $("select[name=type]", this.fieldset).combobox({
            required: true,
            editable: false,
            width: "20%",
            panelHeight: "auto",
            onChange: $.proxy(this._onChange$Type, this)
        });

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

    container: function() {
        return this.fieldset;
    },

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

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

    setType: function(value) {
        var selectedType = this.type.combobox("getValue");
        this.type.combobox("clear");
        this.type.combobox("select", value);
        if (selectedType === value) {
            this._onChange$Type();
        }
    },

    _onChange$Type: function() {
        this.listener.onChangeType(this);
    },

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

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

/** @class */
jscape.domain.SamlAuthServiceController = jscape.domain.BaseAuthServiceController.extend(
    /** @lends {jscape.domain.SamlAuthServiceController.prototype} */
{
    serverKeys: null,
    hostKeys: null,

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

        this.serverKeys = [];
        this.hostKeys = [];
        this.view = new jscape.domain.SamlAuthServiceView();
    },

    /** @override */
    start: function (managementService, domainName, descriptor, templates) {
        this.managementService = managementService;
        this.domainName = domainName;
        this.descriptor = descriptor;
        this.templates = templates;

        $.when(this._loadServerKeys(), this._loadHostKeys())
                .always($.proxy(this._setupView, this, descriptor), this);

        this.view.show(this);
    },

    _loadServerKeys: function() {
        return this.managementService.getServerKeys()
                .then(function(keys) { return $.map(keys, function(key) { return key.name; }); })
                .done($.proxy(function(keys) { this.serverKeys = keys; }, this));
    },

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

    /** @override */
    _createDescriptor: function () {
        return jscape.WebSsoService.saml(this.view.getSignInUrl(),
                                         this.view.getSignOutUrl(),
                                         this.view.getChangePasswordUrl(),
                                         this.view.getDecryptionKey() != null ? new jscape.ServerKeyProvider(this.view.getDecryptionKey()) : null,
                                         this.view.getHostKey(),
                                         this.view.getNameIdFormat(),
                                         this.view.isNonSsoLoginAllowed(),
                                         this.view.getTemplate(),
                                         jscape.UsernameConversion.valueOf(this.view.getUsernameConversion()));
    },

    /** @override */
    _setupView: function (descriptor) {
        this.view.setTemplates(this.templates);
        this.view.setDecryptionKeys(this.serverKeys);
        this.view.setHostKeys(this.hostKeys);

        if (descriptor && descriptor.type == jscape.WebSsoService.TYPE.SAML) {
            this.view.setSignInUrl(descriptor.signInUrl);
            this.view.setSignOutUrl(descriptor.signOutUrl);
            this.view.setChangePasswordUrl(descriptor.changePasswordUrl);
            this.view.setDecryptionKey(descriptor.decryptionKeyProvider && descriptor.decryptionKeyProvider.keyAlias);
            this.view.setHostKey(descriptor.verificationHostKey);
            this.view.setNameIdFormat(descriptor.nameIdFormat);
            this.view.setNonSsoLoginAllowed(descriptor.nonSsoLoginAllowed);
            this.view.setTemplate(descriptor.accountTemplate);
            this.view.setUsernameConversion(descriptor.usernameConversion == jscape.UsernameConversion.NONE ? null : descriptor.usernameConversion);
        }
    }
});

/** @class */
jscape.domain.SamlAuthServiceView = jscape.domain.BaseAuthServiceView.extend(
    /** @lends {jscape.domain.SamlAuthServiceView.prototype} */
{
    /** @constructor */
    initialize: function() {
        this.fieldset = $("fieldset[name=webssoauthsamlfields]").hide();

        this.signInUrl = $("input[name=signinurl]", this.fieldset).textbox({required: true, validType: "length[1,500]", missingMessage: window.R.string.AUTH_ERROR_BAD_SIGNIN_URL, invalidMessage: window.R.string.AUTH_ERROR_BAD_SIGNIN_URL, width: 610});
        this.signOutUrl = $("input[name=signouturl]", this.fieldset).textbox({required: true, validType: "length[1,500]", missingMessage: window.R.string.AUTH_ERROR_BAD_SIGNOUT_URL, invalidMessage: window.R.string.AUTH_ERROR_BAD_SIGNOUT_URL, width: 610});

        this.changePasswordUrl = $("input[name=changepwdurl]", this.fieldset).textbox({width: 610});
        this.nonSsoLoginAllowed = $("input[name=allownonsso]:checkbox", this.fieldset);

        this.useDecryptionKey = $("input[name=usedecryptionkey]:checkbox", this.fieldset)
                .change($.proxy(function () {
                            this.decryptionKey.combobox(this.useDecryptionKey.is(":checked") ? "enable" : "disable");
                        }, this));
        this.decryptionKey = $("select[name=decryptionkey]", this.fieldset).combobox({editable: false, disabled: true, width: "30%", panelHeight: "auto"});

        this.hostKey = $("select[name=hostkey]", this.fieldset);
        this.hostKey.combobox({
            required: true,
            editable: false,
            width: "30%",
            panelHeight: "auto",
            onLoadSuccess: $.proxy(function(data) {
                if (data.length == 0) {
                    this.hostKey.combobox("disable").combobox("disableValidation");
                }
            }, this)
        });

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

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

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

    /** @override */
    show: function () {
        this._super.apply(this, arguments);
        $.each([this.decryptionKey, this.hostKey, this.nameIdFormat], function(_, combobox) {
            combobox.combobox("resize");
        });
    },

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

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

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

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

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

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

    getDecryptionKey: function () {
        return this.useDecryptionKey.is(":checked") ? this.decryptionKey.combobox("getValue") : null;
    },

    setDecryptionKey: function (value) {
        this.useDecryptionKey.prop("checked", !!value).change();
        if (value) {
            this.decryptionKey.combobox("clear").combobox("select", value)
        }
    },

    setDecryptionKeys: function (values) {
        this.decryptionKey.combobox("loadData", values);
    },

    getHostKey: function() {
        return this.hostKey.combobox("getValue");
    },

    setHostKey: function(value) {
        this.hostKey.combobox("setValue", value);
    },

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

    getNameIdFormat: function() {
        return this.nameIdFormat.combobox("getValue");
    },

    setNameIdFormat: function (value) {
        value && this.nameIdFormat.combobox("select", value);
    },

    isNonSsoLoginAllowed: function() {
        return this.nonSsoLoginAllowed.is(":checked");
    },

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

    getTemplate: function() {
        return this.useTemplate.is(":checked") ? this.template.combobox("getValue") : null;
    },

    setTemplate: function(value) {
        this.template.combobox("select", value);
        this.useTemplate.prop("checked", value != null).change();
    },

    setTemplates: function(values) {
        this.template.combobox("loadData", values);
    },

    getUsernameConversion: function() {
        return this.useUsernameConversion.is(":checked") ? this.usernameConversion.combobox("getValue") : null;
    },

    setUsernameConversion: function(value) {
        this.useUsernameConversion.prop("checked", value != null).change();
        if (value != null) {
            this.usernameConversion.combobox("select", value);
        }
    }
});

/** @class */
jscape.domain.OpenIdAuthServiceController = jscape.domain.BaseAuthServiceController.extend(
    /** @lends {jscape.domain.OpenIdAuthServiceController.prototype} */
{
    /** @constructor */
    initialize: function() {
        this._super();
        this.view = new jscape.domain.OpenIdAuthServiceView();
    },

    /** @override */
    _createDescriptor: function () {
        return jscape.WebSsoService.openId(this.view.getSignInUrl(),
                                           this.view.getSignOutUrl(),
                                           this.view.isNonSsoLoginAllowed(),
                                           this.view.getTemplate(),
                                           jscape.UsernameConversion.valueOf(this.view.getUsernameConversion()));
    },

    /** @override */
    _setupView: function (descriptor) {
        this.view.setTemplates(this.templates);

        if (descriptor && descriptor.type == jscape.WebSsoService.TYPE.OPEN_ID) {
            this.view.setSignInUrl(descriptor.signInUrl);
            this.view.setSignOutUrl(descriptor.signOutUrl);
            this.view.setNonSsoLoginAllowed(descriptor.nonSsoLoginAllowed);
            this.view.setTemplate(descriptor.accountTemplate);
            this.view.setUsernameConversion(descriptor.usernameConversion == jscape.UsernameConversion.NONE ? null : descriptor.usernameConversion);
        }
    }
});

/** @class */
jscape.domain.OpenIdAuthServiceView = jscape.domain.BaseAuthServiceView.extend(
    /** @lends {jscape.domain.OpenIdAuthServiceView.prototype} */
{
    /** @constructor */
    initialize: function() {
        this.fieldset = $("fieldset[name=webssoauthopenidfields]").hide();

        this.signInUrl = $("input[name=signinurl]", this.fieldset).textbox({required: true, validType: "length[1,500]", missingMessage: window.R.string.AUTH_ERROR_BAD_SIGNIN_URL, invalidMessage: window.R.string.AUTH_ERROR_BAD_SIGNIN_URL, width: 610});
        this.signOutUrl = $("input[name=signouturl]", this.fieldset).textbox({required: true, validType: "length[1,500]", missingMessage: window.R.string.AUTH_ERROR_BAD_SIGNOUT_URL, invalidMessage: window.R.string.AUTH_ERROR_BAD_SIGNOUT_URL, width: 610});

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

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

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

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

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

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

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

    isNonSsoLoginAllowed: function() {
        return this.nonSsoLoginAllowed.is(":checked");
    },

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

    getTemplate: function() {
        return this.useTemplate.is(":checked") ? this.template.combobox("getValue") : null;
    },

    setTemplate: function(value) {
        this.template.combobox("select", value);
        this.useTemplate.prop("checked", value != null).change();
    },

    setTemplates: function(values) {
        this.template.combobox("loadData", values);
    },

    getUsernameConversion: function() {
        return this.useUsernameConversion.is(":checked") ? this.usernameConversion.combobox("getValue") : null;
    },

    setUsernameConversion: function(value) {
        this.useUsernameConversion.prop("checked", value != null).change();
        if (value != null) {
            this.usernameConversion.combobox("select", value);
        }
    }
});

/** @class */
jscape.domain.OpenIdConnectAuthServiceController = jscape.domain.BaseAuthServiceController.extend(
    /** @lends {jscape.domain.OpenIdConnectAuthServiceController.prototype} */
{
    /** @constructor */
    initialize: function() {
        this._super();
        this.view = new jscape.domain.OpenIdConnectAuthServiceView();
    },

    /** @override */
    _createDescriptor: function () {
        return jscape.WebSsoService.openIdConnect(this.view.getSignInUrl(),
                                                  this.view.getTokenUrl(),
                                                  this.view.getClientId(),
                                                  this.view.getClientSecret(),
                                                  this.view.isNonSsoLoginAllowed(),
                                                  this.view.getTemplate(),
                                                  jscape.UsernameConversion.valueOf(this.view.getUsernameConversion()));
    },

    /** @override */
    _setupView: function (descriptor) {
        this.view.setTemplates(this.templates);

        if (descriptor && descriptor.type == jscape.WebSsoService.TYPE.OPEN_ID_CONNECT) {
            this.view.setSignInUrl(descriptor.signInUrl);
            this.view.setTokenUrl(descriptor.tokenVerificationUrl);
            this.view.setClientId(descriptor.clientId);
            this.view.setClientSecret(descriptor.clientSecret);
            this.view.setNonSsoLoginAllowed(descriptor.nonSsoLoginAllowed);
            this.view.setTemplate(descriptor.accountTemplate);
            this.view.setUsernameConversion(descriptor.usernameConversion == jscape.UsernameConversion.NONE ? null : descriptor.usernameConversion);
        }
    }
});

/** @class */
jscape.domain.OpenIdConnectAuthServiceView = jscape.domain.BaseAuthServiceView.extend(
    /** @lends {jscape.domain.OpenIdConnectAuthServiceView.prototype} */
{
    /** @constructor */
    initialize: function() {
        this.fieldset = $("fieldset[name=webssoauthopenidconnectfields]").hide();

        this.signInUrl = $("input[name=signinurl]", this.fieldset).textbox({required: true, validType: "url", missingMessage: window.R.string.AUTH_ERROR_BAD_SIGNIN_URL, invalidMessage: window.R.string.AUTH_ERROR_BAD_SIGNIN_URL, width: 610});
        this.tokenUrl = $("input[name=tokenurl]", this.fieldset).textbox({required: true, validType: "url", missingMessage: window.R.string.AUTH_ERROR_BAD_TOKEN_URL, invalidMessage: window.R.string.AUTH_ERROR_BAD_TOKEN_URL, width: 610});
        this.clientId = $("input[name=clientid]", this.fieldset).textbox({required: true, validType: "length[1,255]", missingMessage: window.R.string.AUTH_ERROR_BAD_CLIENT_ID, invalidMessage: window.R.string.AUTH_ERROR_BAD_CLIENT_ID, width: 510});
        this.clientSecret = $("input[name=clientsecret]", this.fieldset).textbox({required: true, validType: "length[1,255]", missingMessage: window.R.string.AUTH_ERROR_BAD_CLIENT_SECRET, invalidMessage: window.R.string.AUTH_ERROR_BAD_CLIENT_SECRET, width: 510});

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

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

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

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

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

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

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

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

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

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

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

    isNonSsoLoginAllowed: function() {
        return this.nonSsoLoginAllowed.is(":checked");
    },

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

    getTemplate: function() {
        return this.useTemplate.is(":checked") ? this.template.combobox("getValue") : null;
    },

    setTemplate: function(value) {
        this.template.combobox("select", value);
        this.useTemplate.prop("checked", value != null).change();
    },

    setTemplates: function(values) {
        this.template.combobox("loadData", values);
    },

    getUsernameConversion: function() {
        return this.useUsernameConversion.is(":checked") ? this.usernameConversion.combobox("getValue") : null;
    },

    setUsernameConversion: function(value) {
        this.useUsernameConversion.prop("checked", value != null).change();
        if (value != null) {
            this.usernameConversion.combobox("select", value);
        }
    }
});