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

/** @class */
jscape.AccountInfo = Class.extend(
    /** @lends {jscape.AccountInfo.prototype} */
{
    /** @constructor */
    initialize: function (a, b, c, d, e, f, g) {
        this.name = a || "";
        this.login = b || "";
        this.owner = c || "";
        this.company = d || "";
        this.administrator = !!e || false;
        this.lastLoginDate = parseInt(f) || null;
        this.tags = g || [];
    }
});
jscape.AccountInfo.fromJSON = function(data) {
    return data ? new jscape.AccountInfo(data.name, data.login, data.owner, data.company, data.administrator, data.lastLoginDate, data.tags) : null;
};

/** @class */
jscape.Phone = Class.extend(
    /** @lends {jscape.Phone.prototype} */
{
    /** @constructor */
    initialize: function(a, b, c) {
        this.code = a || "";
        this.number = b || "";
        this.extension = c;
    }
});
jscape.Phone.fromJSON = function(data) {
    return data && data.code && String(data.code).trim().length ? new jscape.Phone(data.code, data.number, data.extension) : null;
};

/** @class */
jscape.Account = Class.extend(
    /** @lends {jscape.Account.prototype} */
{
    /** @constructor */
    initialize: function() {
        this.username = "";
        this.login = "";
        this.emailAddress = "";
        this.company = null;
        this.phone = null;
        this.owner = "";
        this.expirationDate = null;
        this.enabled = true;
        this.secured = false;
        this.groups = [];
        this.bindedKeys = [];
        this.resources = [];
        this.passwordChangingAllowed = false;
        this.emailFileTransferAllowed = false;
        this.usePhoneAuthentication = false;
        this.ignorePasswordAgingRules = false;
        this.quotas = new jscape.AccountTransferQuotas();
        this.ipAccessVerifier = new jscape.IpAccessVerifier();
        this.administration = null;
        this.webOptions = new jscape.WebOptions();
        this.tags = [];
    },

    toJSON: function () {
        return $.extend({},
                        this,
                        {quotas: undefined, webOptions: undefined},
                        $.parseJSON(JSON.stringify(this.quotas)),
                        $.parseJSON(JSON.stringify(this.webOptions)),
                        {
                            company: this.company ? {name: this.company} : null,
                            expirationDate: this.expirationDate ? this.expirationDate.getTime() : null
                        });
    }
});
jscape.Account.fromJSON = function(data) {
    return $.extend(new jscape.Account(), data, {
        company: data.company && data.company.name ? data.company.name : null,
        phone: jscape.Phone.fromJSON(data.phone),
        groups: $.isArray(data.groups) ? data.groups : [],
        expirationDate: $.isNumeric(data.expirationDate) ? new Date(data.expirationDate) : null,
        resources: $.map(data.resources || [], jscape.VirtualFile.fromJSON),
        ipAccessVerifier: jscape.IpAccessVerifier.fromJSON(data.ipAccessVerifier),
        administration: jscape.DomainAdministration.fromJSON(data.administration),
        quotas: jscape.AccountTransferQuotas.fromJSON(data),
        webOptions: jscape.WebOptions.fromJSON(data),
        tags: $.isArray(data.tags) ? data.tags : []
    });
};

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

        this.accountsController = new jscape.domain.AccountsController();
        this.accountsController.onCreate(this.managementService, this.domainName);

        this.templatesController = new jscape.domain.AccountTemplatesController();
        this.templatesController.onCreate(this.managementService, this.domainName);
    },

    onStart: function () {
        this.accountsController.onStart();
        this.templatesController.onStart();
    },

    onResume: function() {
        this.accountsController.onResume();
        this.templatesController.onResume();
    }
});

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

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

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

        this.addController = new jscape.domain.AddAccountController();
        this.editController = new jscape.domain.EditAccountController();
        this.deleteController = new jscape.domain.DeleteAccountController();
        this.copyController = new jscape.domain.CopyAccountController();
        this.checkQuotaController = new jscape.domain.CheckQuotaController();
        this.reportController = new jscape.domain.UserReportController();
    },

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

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

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

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

    onCopyAccount: function(account) {
        this.copyController.start(this.managementService, this.domainName, account.login)
                .done($.proxy(this._accountCopied, this))
                .done($.proxy(this._fireApplySuccess, this));
    },

    onEditAccount: function(account, force) {
        var index = $.inArray(account, this.view.getAccounts());
        if (index != -1 || force === true) {
            this.editController.start(this.managementService, this.domainName, account.login)
                    .done($.proxy(this._accountEdited, this, index));
        }
    },

    onDeleteAccount: function(accounts) {
        this.deleteController.start(this.managementService, this.domainName, accounts)
                .done($.proxy(this._accountDeleted, this, accounts));
    },

    onCheckAccountQuotas: function(account) {
        this.checkQuotaController.start(this.managementService, this.domainName, account.login);
    },

    onAccountsReport: function() {
        this.reportController.start(this.managementService, this.domainName);
    },

    _accountAdded: function (account) {
        this._recordAdded(account);
    },

    _accountEdited: function(index, account) {
        this._recordEdited(account);
    },

    _accountCopied: function(account, editAfterDone) {
        if (editAfterDone) {
            this.view.refresh($.proxy(function() {
                this.view.selectRecord(account);
                this.onEditAccount(account, true);
            }, this));
        } else {
            this._accountAdded(account);
        }
    },

    _accountDeleted: function (accounts) {
        this._recordDeleted(accounts);
    },

    _initValidators: function() {
        var v = new jscape.Validator();
        v.nonEmptyRule("user_login_nonempty", window.R.string.USERS_ERROR_BAD_LOGIN);
        v.rule("user_unique", $.proxy(this._accountNotExists, this), window.R.string.USERS_ERROR_ALREADY_EXIST);
        v.rule("user_login_compliance", $.proxy(this._usernameCompliant, this), window.R.string.USERS_ERROR_USERNAME_NON_COMPLIANT);
        v.rule("user_password_compliance", $.proxy(this._passwordCompliant, this), window.R.string.USERS_ERROR_PASSWORD_NON_COMPLIANT);
        v.rule("user_password_confirm", $.proxy(this._passwordConfirmed, this), window.R.string.USERS_ERROR_CONFIRM_PWD);
    },

    _accountNotExists: function (login) {
        var values = $.map(this.view.getAccounts(), function(account) { return account.login.toUpperCase(); });
        return $.inArray((login || "").toUpperCase(), values) == -1;
    },

    _usernameCompliant: function (value) {
        var result = this.managementService.testUsernameCompliance(this.domainName, value);
        if ($.isPlainObject(result)) {
            if (result.valid === false && result.message) {
                new jscape.Validator().ruleMessage("user_login_compliance", result.message);
            }
            return !!result.valid;
        }
        return true;
    },

    _passwordCompliant: function (value, params) {
        var accountName = params && params.length ? params[0] : null;
        var ret = this.managementService.testPasswordCompliance(this.domainName, accountName, value);
        return ret && ret.trim() == "true";
    },

    _passwordConfirmed: function(value, params) {
        return params && params.length && $(params[0]).val() == value;
    }
});

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

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

        this.fieldset = $("fieldset[name=usersfields]");

        this.data = $("table[role=grid][aria-label=users]", this.fieldset);
        this.data.datagrid({
            fit: true,
            fitColumns: true,
            singleSelect: true,
            pagination: true,
            search: true,
            remoteSearch: true,
            sortName: "name",
            idField: "login",
            columns: [[
                {field: "name", title: $("thead th:nth-child(1)", this.data).text(), width: 90, sortable: true},
                {field: "login", title: $("thead th:nth-child(2)", this.data).text(), width: 70, sortable: true},
                {field: "lastLoginDate", title: $("thead th:nth-child(3)", this.data).text(), width: 100, sortable: true, align: "right", formatter: function(value) { return $.isNumeric(value) ? new Date(value).toLocaleString() : ""; }},
                {field: "owner", title: $("thead th:nth-child(4)", this.data).text(), width: 60, sortable: true},
                {field: "company", title: $("thead th:nth-child(5)", this.data).text(), width: 100, sortable: true},
                {field: "administrator", title: $("thead th:nth-child(6)", this.data).text(), width: 50, sortable: true,  formatter: function(value) { return value ? "yes" : ""; }, styler: function(value) { return value ? "color:green;font-weight:bold" : ""; }},
                {field: "tags", title: $("thead th:nth-child(7)", this.data).text(), width: 80, sortable: false, formatter: function(value) { return String($.isArray(value) ? value.join(", ") : value).escapeXml(); }}
            ]],
            onSelect: $.proxy(this._adjustState, this),
            onUnselect: $.proxy(this._adjustState, this),
            onDblClickRow: $.proxy(this._onClick$EditButton, this),
            loader: $.proxy(this._onLoad$Data, this),
            onBeforeLoad: function() { return !initializing; },
            onLoadSuccess: $.proxy(this._adjustState, this)
        });

        this.reportButton = $("a[role=button][name=report]", this.fieldset).linkbutton({onClick: $.proxy(this._onClick$ReportButton, this)});
        this.addButton = $("a[role=button][name=add]", this.fieldset).linkbutton({onClick: $.proxy(this._onClick$AddButton, this)});
        this.editButton = $("a[role=button][name=edit]", this.fieldset).linkbutton({disabled: true, onClick: $.proxy(this._onClick$EditButton, this)});
        this.deleteButton = $("a[role=button][name=delete]", this.fieldset).linkbutton({disabled: true, onClick: $.proxy(this._onClick$DeleteButton, this)});
        this.copyButton = $("a[role=button][name=copy]", this.fieldset).linkbutton({disabled: true, onClick: $.proxy(this._onClick$CopyButton, this)});
        this.quotasButton = $("a[role=button][name=quotas]", this.fieldset).linkbutton({disabled: true, onClick: $.proxy(this._onClick$QuotasButton, this)});

        initializing = false;
    },

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

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

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

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

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

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

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

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

    _onClick$ReportButton: function() {
        this.listener.onAccountsReport();
    },

    _adjustState: function() {
        this.selection = this.data.datagrid("getSelections");
        this.editButton.linkbutton(this.selection.length == 1 ? "enable" : "disable");
        this.copyButton.linkbutton(this.selection.length == 1 ? "enable" : "disable");
        this.quotasButton.linkbutton(this.selection.length == 1 ? "enable" : "disable");
        this.deleteButton.linkbutton(this.selection.length != 0 ? "enable" : "disable");
    }
});
jscape.domain.AccountsView.LISTENER = {
    onRefresh: $.noop,
    onAddAccount: $.noop,
    onCopyAccount: $.noop,
    onEditAccount: $.noop,
    onDeleteAccount: $.noop,
    onCheckAccountQuotas: $.noop,
    onAccountsReport: $.noop
};

/** @class */
jscape.domain.AddAccountController = Class.extend(
    /** @lends {jscape.domain.AddAccountController.prototype} */
{
    DEFAULT_TEMPLATE_NAME: "Default",

    infoController: null,
    vfsController: null,
    quotasController: null,
    ipAccessController: null,
    domainAdminController: null,
    webController: null,
    deferred: null,

    start: function (managementService, domainName) {
        this.managementService = managementService;
        this.domainName = domainName;
        this.deferred = $.Deferred();
        this.managementService.getAccountTemplateNames(this.domainName)
                .then($.proxy(function(templates) {
                                 if (templates && templates.length) {
                                     return this._selectAccountTemplate(templates);
                                 } else {
                                     this._showNoAccountTemplatesError();
                                     return $.Deferred().reject().promise();
                                 }
                              },this),
                      $.proxy(this._showNoAccountTemplatesError, this))
                .then($.proxy(function(templateName) { return this.managementService.getAccountTemplate(this.domainName, templateName); }, this))
                .done($.proxy(function(template) { this._setupDialog(template).show(this); }, this))
                .fail($.proxy(function() { this.deferred.reject(); this.deferred = null; }, this));
        return this.deferred.promise();
    },

    onSubmit: function(dialog) {
        var account = this._createAccount(dialog);
        this._rootPathPresent(account)
                .done($.proxy(function () {
                          dialog.destroy();
                          this.managementService.addAccount(this.domainName, account)
                                  .done($.proxy(function (info) { this.deferred.resolve(info); this.deferred = null; }, this))
                                  .fail($.proxy(function () { this.deferred.reject(); this.deferred = null; }, this))
                                  .always($.proxy(this._cleanup, this));
                      }, this))
                .fail($.proxy(this._showRootNotFoundError, this));
    },

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

    _selectAccountTemplate: function(templateNames) {
        var deferred = $.Deferred();
        var dialog = new jscape.domain.UserTemplateDialog();
        dialog.setTemplates(templateNames.sort());
        dialog.selectItem(this.DEFAULT_TEMPLATE_NAME);
        dialog.show({
            onSubmit: function(dialog) {
                var templateName = dialog.getTemplate();
                dialog.destroy();
                deferred.resolve(templateName);
                deferred = null;
            },
            onCancel: function(dialog) {
                dialog.destroy();
                deferred.reject();
                deferred = null;
            }
        });
        return deferred.promise();
    },

    _setupDialog: function (template) {
        var dialog = new jscape.domain.AddAccountDialog();
        this._createView(dialog.container());
        window.setTimeout($.proxy(function () {
            try {
                this._setupView(template);
            } catch (e) {
                dialog.destroy();
                this._cleanup();
            } finally {
                dialog = null;
            }
        }, this), 0);
        return dialog;
    },

    _createView: function (container) {
        this._cleanup();
        this.infoController = new jscape.domain.AddUserInfoController(container);
        this.vfsController = new jscape.vfs.VirtualFilesController(container);
        this.quotasController = new jscape.domain.QuotasController(container);
        this.ipAccessController = new jscape.domain.UserIpAccessController(container);
        this.domainAdminController = new jscape.domain.DomainAdministrationController(container, this.vfsController);
        this.webController = new jscape.domain.WebOptionsController(container);
    },

    _setupView: function (template) {
        this.infoController.start(this.managementService, this.domainName, template);
        this.vfsController.start(this.managementService, this.domainName, template.resources);
        this.quotasController.start(template.quotas);
        this.ipAccessController.start(template.ipAccessVerifier);
        this.domainAdminController.start(this.managementService, this.domainName, template.administration);
        this.webController.start(template.webOptions);
    },

    _createAccount: function (dialog) {
        var account = this.infoController.createAccount();
        return $.extend(account, {
            resources: this.vfsController.getDescriptors(),
            quotas: this.quotasController.getQuotas(),
            ipAccessVerifier: this.ipAccessController.getIpAccess(),
            administration: this.domainAdminController.getDomainAdministration(),
            webOptions: this.webController.getWebOptions()
        });
    },

    _rootPathPresent: function (account) {
        function rootPathExists(resources) {
            return new jscape.Validator().isSatisfied("vfs_root_found", resources);
        }
        var deferred = $.Deferred();
        if (rootPathExists(account.resources)) {
            deferred.resolve();
        } else if (account.groups.length != 0) {
            $.when.apply(jQuery, $.map(account.groups, $.proxy(function (groupName) { return this.managementService.getGroup(this.domainName, groupName); }, this)))
                    .done(function () {
                              for (var i = 0; i < arguments.length; i++) {
                                  if (rootPathExists(arguments[i].resources)) {
                                      deferred.resolve();
                                      break;
                                  }
                              }
                              deferred.reject();
                          })
                    .fail($.proxy(function () { deferred.reject(); }, this));
        } else {
            deferred.reject();
        }
        return deferred.promise();
    },

    _showRootNotFoundError: function() {
        $.messager.alert(window.R.string.APPLICATION_ERROR_TITLE,
                         window.R.string.VFS_ERROR_ROOT_PATH_NOT_FOUND,
                         "error");
    },

    _showNoAccountTemplatesError: function () {
        $.messager.alert(window.R.string.APPLICATION_ERROR_TITLE,
                         window.R.string.USERS_ERROR_NO_TEMPLATES,
                         "error");
    },

    _cleanup: function () {
        this.infoController = null;
        this.vfsController = null;
        this.quotasController = null;
        this.ipAccessController = null;
        this.domainAdminController = null;
        this.webController = null;
    }
});

/** @class */
jscape.domain.EditAccountController = Class.extend(
    /** @lends {jscape.domain.EditAccountController.prototype} */
{
    infoController: null,
    vfsController: null,
    quotasController: null,
    ipAccessController: null,
    domainAdminController: null,
    webController: null,
    deferred: null,

    start: function(managementService, domainName, accountName) {
        this.managementService = managementService;
        this.domainName = domainName;
        this.accountName = accountName;
        this.deferred = $.Deferred();
        this.managementService.getAccount(this.domainName, this.accountName)
                .done($.proxy(function(account) { this._setupDialog(account).show(this); }, this))
                .fail($.proxy(function() { this.deferred.reject(); this.deferred = null; }, this));
        return this.deferred.promise();
    },

    onSubmit: function (dialog) {
        var account = this._createAccount(dialog);
        this._rootPathPresent(account)
                .done($.proxy(function () {
                          dialog.destroy();
                          this.managementService.setAccount(this.domainName, this.accountName, account)
                                  .done($.proxy(function (info) { this.deferred.resolve(info); this.deferred = null; }, this))
                                  .fail($.proxy(function () { this.deferred.reject(); this.deferred = null; }, this))
                                  .always($.proxy(this._cleanup, this));
                      }, this))
                .fail($.proxy(this._showMessageRootNotFound, this))
    },

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

    onAccountChanged: function () {
        this.managementService.getAccount(this.domainName, this.accountName)
                .done($.proxy(function (account) {
                          account = $.extend(account, this._createAccount());
                          this._setupView(account);
                      }, this));
    },

    _setupDialog: function (account) {
        var dialog = new jscape.domain.EditAccountDialog();
        dialog.setAccountName(this.accountName);
        this._createView(dialog.container());
        window.setTimeout($.proxy(function () {
            try {
                this._setupView(account);
            } catch (e) {
                dialog.destroy();
                this._cleanup();
            } finally {
                dialog = null;
            }
        }, this), 0);
        return dialog;
    },

    _createView: function (parent) {
        this._cleanup();
        this.infoController = new jscape.domain.EditUserInfoController(parent);
        this.vfsController = new jscape.vfs.VirtualFilesController(parent);
        this.quotasController = new jscape.domain.QuotasController(parent);
        this.ipAccessController = new jscape.domain.UserIpAccessController(parent);
        this.domainAdminController = new jscape.domain.DomainAdministrationController(parent, this.vfsController);
        this.webController = new jscape.domain.WebOptionsController(parent);
    },

    _setupView: function (account) {
        this.infoController.start(this, this.managementService, this.domainName, account);
        this.vfsController.start(this.managementService, this.domainName, account.resources);
        this.quotasController.start(account.quotas);
        this.ipAccessController.start(account.ipAccessVerifier);
        this.domainAdminController.start(this.managementService, this.domainName, account.administration);
        this.webController.start(account.webOptions);
    },

    _createAccount: function () {
        var account = this.infoController.createAccount();
        return $.extend(account, {
            resources: this.vfsController.getDescriptors(),
            quotas: this.quotasController.getQuotas(),
            ipAccessVerifier: this.ipAccessController.getIpAccess(),
            administration: this.domainAdminController.getDomainAdministration(),
            webOptions: this.webController.getWebOptions()
        });
    },

    _rootPathPresent: function (account) {
        function rootPathExists(resources) {
            return new jscape.Validator().isSatisfied("vfs_root_found", resources);
        }
        var deferred = $.Deferred();
        if (rootPathExists(account.resources)) {
            deferred.resolve();
        } else if (account.groups.length != 0) {
            $.when.apply(jQuery, $.map(account.groups, $.proxy(function (groupName) { return this.managementService.getGroup(this.domainName, groupName); }, this)))
                    .done(function () {
                              for (var i = 0; i < arguments.length; i++) {
                                  if (rootPathExists(arguments[i].resources)) {
                                      deferred.resolve();
                                      break;
                                  }
                              }
                              deferred.reject();
                          })
                    .fail($.proxy(function () { deferred.reject(); }, this));
        } else {
            deferred.reject();
        }
        return deferred.promise();
    },

    _cleanup: function() {
        this.infoController = null;
        this.vfsController = null;
        this.quotasController = null;
        this.ipAccessController = null;
        this.domainAdminController = null;
        this.webController = null;
    },

    _showMessageRootNotFound: function() {
        $.messager.alert(window.R.string.APPLICATION_ERROR_TITLE,
                         window.R.string.VFS_ERROR_ROOT_PATH_NOT_FOUND,
                         "error");
    }
});

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

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

    _confirmDelete: function(accounts) {
        var text = $.map(accounts, function(user) { return user.login; }).join(", ");
        return jscape.ConfirmDialog.confirm(
                window.R.string.USERS_CONFIRM_DELETE_TITLE,
                window.R.string.USERS_CONFIRM_DELETE_MESSAGE.supplant({0: text}));
    },

    _deleteConfirmed: function (accounts) {
        $.when.apply(jQuery, $.map(accounts, $.proxy(function(account) { return this.managementService.deleteAccount(this.domainName, account.login); }, this)))
                .done($.proxy(function() { this.deferred.resolve(accounts); this.deferred = null; }, this))
                .fail($.proxy(function() { this.deferred.reject(); this.deferred = null; }, this));
    }
});

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

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

    onSubmit: function(dialog) {
        var newLogin = dialog.getLogin();
        var editAfterDone = dialog.isEditAfterDone();
        dialog.destroy();

        this.managementService.copyAccount(this.domainName, this.accountName, newLogin)
                .done($.proxy(function(info) { this.deferred.resolve(info, editAfterDone); this.deferred = null; }, this))
                .fail($.proxy(function() { this.deferred.reject(); this.deferred = null; }, this));
    },

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

    _setupDialog: function () {
        var dialog = new jscape.domain.CopyAccountDialog();
        dialog.setAccountName(this.accountName);
        dialog.setEditAfterDone(true);
        return dialog;
    }
});

/** @class */
jscape.domain.CheckQuotaController = Class.extend(
    /** @lends {jscape.domain.CheckQuotaController.prototype} */
{
    start: function(managementService, domainName, accountName) {
        this.managementService = managementService;
        this.domainName = domainName;
        this.accountName = accountName;

        managementService.getAccountQuotas(domainName, accountName)
                .done($.proxy(this._showQuotas, this, accountName));
    },

    _showQuotas: function(accountName, quotas) {
        var dialog = new jscape.domain.CheckQuotaDialog();
        dialog.setAccountName(accountName);
        dialog.setDownloadsQuota(quotas ? quotas.downloadsQuota : null);
        dialog.setUploadsQuota(quotas ? quotas.uploadsQuota : null);
        dialog.setTransfersQuota(quotas ? quotas.transfersQuota : null);
        dialog.show();
    }
});

/** @class */
jscape.domain.UserTemplateDialog = Class.extend(
    /** @lends {jscape.domain.UserTemplateDialog.prototype} */
{
    /** @constructor */
    initialize: function() {
        this.dialog = $("#d-user-add-usertemplate").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=usertemplatefileds]", this.dialog);
        this.template = $("select[name=template]", this.fieldset).combobox({required: true, editable: true, limitToList: true, width: 170, panelHeight: "auto"});
        this.template.combobox("textbox").on("focus", function() { $(this).select(); });
    },

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

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

    getTemplate: function() {
        return this.template.combobox("getValue");
    },

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

    selectItem: function(value) {
        this.template.combobox("select", value);
    },

    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.AccountDialog = Class.extend(
    /** @lends {jscape.domain.AccountDialog.prototype} */
{
    /** @constructor */
    initialize: function(dialog) {
        this.dialog = dialog.clone().attr("id", $.now().toString(36));
        this.dialog.dialog({
            width: 800, height: "auto",
            modal: true, resizable: false, closable: true, closed: true,
            buttons: [
                {text: window.R.string.DIALOG_BUTTON_OK || "Ok", handler: $.proxy(this._onSubmit, this)},
                {text: window.R.string.DIALOG_BUTTON_CANCEL || "Cancel", handler: $.proxy(this._onCancel, this)}
            ],
            onClose: $.proxy(function () {if (!this.closing) { this._onCancel(); }}, this)
        }).keydown($.proxy(function(e) {
            if (e.keyCode == 13) {
                e.stopPropagation();
                this._onSubmit();
            } else if (e.keyCode == 27) {
                e.stopPropagation();
                this._onCancel();
            }
        }, this)).show();

        this.tabs = $("div[role=tablist]", this.dialog).tabs({tabPosition: "top", plain: true});
    },

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

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

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

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

    _onSubmit: function () {
        if (this._valid()) {
            this.listener.onSubmit(this);
        }
    },

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

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

    _valid: function () {
        return new jscape.Validator().validateTabs(this.tabs);
    }
});
jscape.domain.AccountDialog.LISTENER = {
    onSubmit: $.noop,
    onCancel: $.noop
};

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

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

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

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

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

        this.title = this.dialog.dialog("header").text();
        this.fieldset = $("fieldset[name=copyuserfileds]", this.dialog);

        this.login = $("[name=login]", this.fieldset).textbox({
            required: true,
            validType: ["user_login_nonempty", "user_unique", "user_login_compliance"],
            validateOnBlur: true,
            delay: 1500,
            missingMessage: window.R.string.USERS_ERROR_BAD_LOGIN,
            width: "60%"
        });
        this.editAfterDone = $("input[name=editafterdone]:checkbox", this.fieldset);
    },

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

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

    isEditAfterDone: function() {
        return this.editAfterDone.is(":checked");
    },

    setEditAfterDone: function(value) {
        this.editAfterDone.prop("checked", !!value);
    },

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

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

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

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

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

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

/** @class */
jscape.domain.CheckQuotaDialog = Class.extend(
    /** @lends {jscape.domain.CheckQuotaDialog.prototype} */
{
    /** @constructor */
    initialize: function() {
        this.dialog = $("#d-user-quota").clone().attr("id", new Date().getTime().toString(36));
        this.dialog.dialog({
            width: 450, height: "auto",
            modal: true, resizable: false, closable: true, closed: true,
            buttons: [{text: window.R.string.DIALOG_BUTTON_CLOSE || "Close", handler: $.proxy(this._onClose, this)}],
            onClose: $.proxy(this._onClose, this)
        }).show();

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

        this.downloadQuota = $("[aria-label=dloadquota]", this.fieldset);
        this.uploadQuota = $("[aria-label=uploadquota]", this.fieldset);
        this.transferQuota = $("[aria-label=transferquota]", this.fieldset);

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

    show: function () {
        this.dialog.dialog("center").dialog("open");
    },

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

    setDownloadsQuota: function(quota) {
        this.downloadQuota.prop("readonly", false);
        this.downloadQuota.text(this._formatQuota(quota));
        this.downloadQuota.prop("readonly", true);
    },

    setUploadsQuota: function(quota) {
        this.uploadQuota.prop("readonly", false);
        this.uploadQuota.text(this._formatQuota(quota));
        this.uploadQuota.prop("readonly", true);
    },

    setTransfersQuota: function(quota) {
        this.transferQuota.prop("readonly", false);
        this.transferQuota.text(this._formatQuota(quota));
        this.transferQuota.prop("readonly", true);
    },

    _formatQuota: function(quota) {
        if (quota != null) {
            var f = new jscape.SizeFormat();
            return window.R.string.USERS_QUOTA_TEMPLATE.supplant({0: f.format(quota.transferredBytes), 1: f.format(quota.bytes)});
        }
        return window.R.string.USERS_QUOTA_NONE;
    },

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

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

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

        this._setupView(template);
    },

    createAccount: function() {
        var account = new jscape.Account();
        account.login = this.view.getLogin();
        account.password = this.view.getPassword();
        account.username = this.view.getUsername();
        account.emailAddress = this.view.getEmail();
        account.company = this.view.getCompany() ? this.view.getCompany() : null;
        account.phone = this.view.getPhoneCode() != null || this.view.getPhoneNumber() != null ? new jscape.Phone(this.view.getPhoneCode(), this.view.getPhoneNumber(), this.view.getPhoneExtension()) :  null;
        account.bindedKeys = this.view.getClientKeys();
        account.groups = this.view.getGroups();
        account.owner = this.view.getOwner();
        account.expirationDate = this.view.getExpirationDate();
        account.enabled = this.view.getEnabled();
        account.secured = this.view.getSecured();
        account.usePhoneAuthentication = this.view.getUseMultiFactorAuthentication();
        account.passwordChangingAllowed = this.view.getAllowPasswordChanging();
        account.emailFileTransferAllowed = this.view.getAllowAdHocTransfers();
        account.ignorePasswordAgingRules = this.view.getIgnorePasswordAgingRules();
        account.tags = this.view.getTags();
        return account;
    },

    _setupView: function (template) {
        if (template) {
            this.view.setUsername(template.username);
            this.view.setEmail(template.emailAddress);
            this.view.setCompany(template.company != null ? template.company.name : "");
        }

        if (template && template.phone != null) {
            this.view.setPhoneCode(template.phone.code);
            this.view.setPhoneNumber(template.phone.number);
            this.view.setPhoneExtension(template.phone.extension);
        }

        if (template.expirationDate != null) {
            this.view.setExpirationDate(template.expirationDate);
        } else if (template.expirationPeriodMillis != null) {
            this.view.setExpirationDate(new Date().getTime() + template.expirationPeriodMillis);
        }

        this.view.setEnabled(template.enabled);
        this.view.setSecured(template.secured);
        this.view.setUseMultiFactorAuthentication(template.usePhoneAuthentication);
        this.view.setAllowAdHocTransfers(template.emailFileTransferAllowed);
        this.view.setAllowPasswordChanging(template.passwordChangingAllowed);
        this.view.setIgnorePasswordAgingRules(template.ignorePasswordAgingRules);

        this.managementService.getAccountAdminNames(this.domainName)
                .done($.proxy(function (owners) {
                          this.view.setAvailableOwners(owners);
                          template && this.view.setOwner(template.owner);
                      }, this));
        this.managementService.getGroupNames(this.domainName)
                .done($.proxy(function (groups) {
                          this.view.setAvailableGroups(groups.sort());
                          template && this.view.setGroups(template.groups);
                      }, this));
        $.when(this.managementService.getClientPublicKeys(this.domainName),
               this.managementService.getClientCertificates(this.domainName))
                .done($.proxy(function (publicKeys, certificates) {
                          publicKeys = $.map(publicKeys, function (key) { return key.name; });
                          certificates = $.map(certificates, function (key) { return key.name; });

                          this.view.setAvailableClientKeys(publicKeys.concat(certificates));
                          template && this.view.setClientKeys(template.bindedKeys);
                      }, this));
        this.managementService.getDomainTags(this.domainName)
                .done($.proxy(function (tags) {
                          this.view.setAvailableTags(tags);
                          template && this.view.setTags(template.tags);
                      }, this));
    }
});

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

    start: function(listener, managementService, domainName, account) {
        this.listener = listener;
        this.managementService = managementService;
        this.domainName = domainName;
        this.account = account;
        this.view.show(this);

        this._setupView(account);
    },

    createAccount: function() {
        var account = $.extend(new jscape.Account(), this.account);
        account.username = this.view.getUsername();
        account.emailAddress = this.view.getEmail();
        account.company = this.view.getCompany() ? this.view.getCompany() : null;
        account.phone = $.isNumeric(this.view.getPhoneCode()) ? new jscape.Phone(this.view.getPhoneCode(), this.view.getPhoneNumber(), this.view.getPhoneExtension()) : null;
        account.bindedKeys = this.view.getClientKeys();
        account.groups = this.view.getGroups();
        account.owner = this.view.getOwner();
        account.expirationDate = this.view.getExpirationDate();
        account.enabled = this.view.getEnabled();
        account.secured = this.view.getSecured();
        account.usePhoneAuthentication = this.view.getUseMultiFactorAuthentication();
        account.passwordChangingAllowed = this.view.getAllowPasswordChanging();
        account.emailFileTransferAllowed = this.view.getAllowAdHocTransfers();
        account.ignorePasswordAgingRules = this.view.getIgnorePasswordAgingRules();
        account.tags = this.view.getTags();
        return account;
    },

    onChangePassword: function () {
        var controller = new jscape.domain.ChangePasswordController();
        return controller.start(this.managementService, this.domainName, this.account.login)
                .done($.proxy(function () { this.listener.onAccountChanged(); }, this));
    },

    onResetTotpKey: function () {
        return this.managementService.resetAccountTotp(this.domainName, this.account.login)
                .done($.proxy(function () {
                          this._showMessageTotpKeyReset();
                          this.listener.onAccountChanged();
                      }, this));
    },

    _setupView: function (account) {
        if (account) {
            this.view.setUsername(account.username);
            this.view.setEmail(account.emailAddress);
            this.view.setCompany(account.company != null ? account.company : "");
            if (account.phone != null) {
                this.view.setPhoneCode(account.phone.code);
                this.view.setPhoneNumber(account.phone.number);
                this.view.setPhoneExtension(account.phone.extension);
            }
            this.view.setExpirationDate(account.expirationDate);
            this.view.setEnabled(account.enabled);
            this.view.setSecured(account.secured);
            this.view.setUseMultiFactorAuthentication(account.usePhoneAuthentication);
            this.view.setAllowAdHocTransfers(account.emailFileTransferAllowed);
            this.view.setAllowPasswordChanging(account.passwordChangingAllowed);
            this.view.setIgnorePasswordAgingRules(account.ignorePasswordAgingRules);
        }

        this.managementService.getAccountAdminNames(this.domainName)
                .done($.proxy(function (owners) {
                          this.view.setAvailableOwners(owners);
                          account && this.view.setOwner(account.owner);
                      }, this));
        this.managementService.getGroupNames(this.domainName)
                .done($.proxy(function (groups) {
                          this.view.setAvailableGroups(groups.sort());
                          account && this.view.setGroups(account.groups);
                      }, this));
        $.when(this.managementService.getClientPublicKeys(this.domainName),
               this.managementService.getClientCertificates(this.domainName))
                .done($.proxy(function (publicKeys, certificates) {
                          publicKeys = $.map(publicKeys, function (key) { return key.name; });
                          certificates = $.map(certificates, function (key) { return key.name; });

                          this.view.setAvailableClientKeys(publicKeys.concat(certificates));
                          account && this.view.setClientKeys(account.bindedKeys);
                      }, this));
        this.managementService.getDomainTags(this.domainName)
                .done($.proxy(function (tags) {
                          this.view.setAvailableTags(tags);
                          account && this.view.setTags(account.tags);
                      }, this));
    },

    _showMessageTotpKeyReset: function () {
        $.messager.alert("", window.R.string.USERS_SUCCESS_RESET_TOTP, "info");
    }
});

/** @class */
jscape.domain.BaseUserInfoView = jscape.domain.UserInfoView.extend(
    /** @lends {jscape.domain.BaseUserInfoView.prototype} */
{
    /** @constructor */
    initialize: function(fieldset) {
        this._super(fieldset);

        this.expires = $("input[name=expires]", this.fieldset).change($.proxy(function() {
            var enabled = this.expires.is(":checked");
            this.expirationDate.datetimebox(enabled ? "enable" : "disable").datetimebox(enabled ? "enableValidation" : "disableValidation");
        }, this));
        this.expirationDate = $("input[name=expirationdate]", this.fieldset).datetimebox({
            required: true,
            editable: false,
            disabled: true,
            showSeconds: false,
            width: 150,
            formatter: $.proxy(this._formatDate, this),
            parser: $.proxy(this._parseDate, this)
        });
        this.expirationDate.datetimebox("calendar").calendar({validator: function (date) { return new Date().getTime() < date.getTime(); }});
        this.expirationDate.datetimebox("setValue", this.expirationDate.datetimebox("options").formatter(new Date()));
    },

    getExpirationDate: function() {
        if (this.expires.is(":checked:not(:disabled)")) {
            var opts = this.expirationDate.datetimebox("options");
            return opts.parser.call(this, this.expirationDate.datetimebox("getValue"));
        }
        return null;
    },

    setExpirationDate: function(value) {
        var date = this._formatDate(value != null ? new Date(value) : new Date());
        if (value != null) {
            this.expires.prop("checked", true).change();
            this.expirationDate.datetimebox("setValue", date).datetimebox("enable");
        } else {
            this.expires.prop("checked", false).change();
            this.expirationDate.datetimebox("setValue", date);
        }
    },

    _formatDate: function(date) {
        return jscape.DateFormat.format(date, "{MM}/{dd}/{yy} {hh}:{mm}");
    },

    _parseDate: function (str) {
        var matches = /(\d{1,2})\/(\d{1,2})\/(\d{2,4})\s(\d{2}):(\d{2})/.exec(str);
        if (matches != null && matches.length == 6) {
            var m = parseInt(matches[1], 10),
                    d = parseInt(matches[2], 10),
                    y = parseInt(matches[3], 10),
                    h = parseInt(matches[4], 10),
                    min = parseInt(matches[5], 10);
            if (!isNaN(m) && !isNaN(d) && !isNaN(y) && !isNaN(h) && !isNaN(min)) {
                return new Date(y, m - 1, d, h, min);
            }
        }
        return new Date();
    }
});

/** @class */
jscape.domain.AddUserInfoView = jscape.domain.BaseUserInfoView.extend(
    /** @lends {jscape.domain.AddUserInfoView.prototype} */
{
    /** @constructor */
    initialize: function(container) {
        this._super($("fieldset[name=userinfoaddfields]", container));

        this.login = $("input[name=login]", this.fieldset).textbox({
            required: true,
            validType: ["user_login_nonempty", "user_unique", "user_login_compliance"],
            validateOnBlur: true,
            delay: 1500,
            missingMessage: window.R.string.USERS_ERROR_BAD_LOGIN,
            width: "60%"
        });

        var id = "pwd_" + new Date().getTime().toString(36);
        this.password = $("input[name=password]", this.fieldset)
                .textbox({validType: "user_password_compliance", delay: 700, missingMessage: window.R.string.USERS_ERROR_PASSWORD_NON_COMPLIANT, width: "50%"});
        this.password.textbox("textbox")
                .on("input", $.proxy(function() { this.confirmPassword.textbox({required: this.password.textbox("textbox").val().length != 0}); }, this))
                .attr("id", id);
        this.confirmPassword = $("input[name=confirmpwd]", this.fieldset).textbox({validType: "user_password_confirm['#" + id + "']", missingMessage: window.R.string.USERS_ERROR_CONFIRM_PWD, width: "50%"});

        this.useMultiFactorAuth = $("input[name=multifactorauth]:checkbox", this.fieldset);
        $("a[role=button][name=resettotp]", this.fieldset).hide();
    },

    /** @override */
    show: function(listener) {
        this._adjustPasswordRequirements();
        this._super(listener);
    },

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

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

    getUseMultiFactorAuthentication: function() {
        return this.useMultiFactorAuth.is(":checked");
    },

    setUseMultiFactorAuthentication: function(value) {
        this.useMultiFactorAuth.prop("checked", !!value);
    },

    _adjustPasswordRequirements: function() {
        var opts = this.password.textbox("textbox").validatebox("options");
        var compliant = new jscape.Validator().isSatisfied(opts.validType, "");
        opts.required = !compliant;
    }
});

/** @class */
jscape.domain.EditUserInfoView = jscape.domain.BaseUserInfoView.extend(
    /** @lends {jscape.domain.EditUserInfoView.prototype} */
{
    /** @constructor */
    initialize: function(container) {
        this._super($("fieldset[name=userinfoeditfields]", container));

        this.changePasswordButton = $("a[role=button][name=changepwd]", this.fieldset).linkbutton({onClick: $.proxy(this._onClick$ChangePasswordButton, this)});

        this.useMultiFactorAuth = $("input[name=multifactorauth]:checkbox", this.fieldset).change($.proxy(function() {
            var enabled = this.useMultiFactorAuth.is(":checked");
            this.resetTotpKeyButton.linkbutton(enabled ? "enable" : "disable");
        }, this));
        this.resetTotpKeyButton = $("a[role=button][name=resettotp]", this.fieldset).linkbutton({disabled: true, onClick: $.proxy(this._onClick$ResetTotpKeyButton, this)});
        this.useMultiFactorAuth.change();
    },

    getUseMultiFactorAuthentication: function() {
        return this.useMultiFactorAuth.is(":checked");
    },

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

    _onClick$ChangePasswordButton: function () {
        this.changePasswordButton.linkbutton("disable");
        this.listener.onChangePassword(this)
                .always($.proxy(function() { this.changePasswordButton.linkbutton("enable"); }, this));
    },

    _onClick$ResetTotpKeyButton: function () {
        this.resetTotpKeyButton.linkbutton("disable");
        this.listener.onResetTotpKey(this)
                .always($.proxy(function () { this.resetTotpKeyButton.linkbutton("enable"); }, this));
    }
});
jscape.domain.EditUserInfoView.LISTENER = $.extend({
    onChangePassword: $.noop,
    onResetTotpKey: $.noop
}, jscape.domain.UserInfoView.LISTENER);


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

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

    onSubmit: function(dialog) {
        var password = dialog.getPassword();
        dialog.destroy();

        this.managementService.changeAccountPassword(this.domainName, this.accountName, password)
                .done($.proxy(this._showPasswordChangedMessage, this))
                .done($.proxy(function() { this.deferred.resolve(); this.deferred = null; }, this))
                .fail($.proxy(function() { this.deferred.reject(); this.deferred = null; }, this));
    },

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

    _setupDialog: function() {
        var dialog = new jscape.domain.ChangePasswordDialog();
        dialog.setAccountName(this.accountName);
        return dialog;
    },

    _showPasswordChangedMessage: function () {
        $.messager.alert(window.R.string.USERS_CHANGE_PASSWORD_TITLE,
                         window.R.string.USERS_CHANGE_PASSWORD_MESSAGE,
                         "info");
    }
});

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

        var id = "newpwd_" + new Date().getTime().toString(36);
        this.password = $("input[name=password]", this.fieldset).textbox({validType: "user_password_compliance", delay: 700, width: "70%"});
        this.password.textbox("textbox")
                .on("input", $.proxy(function() { this.confirmPassword.textbox({required: this.password.textbox("textbox").val().length != 0}); }, this))
                .attr("id", id);

        this.confirmPassword = $("input[name=confirmpwd]", this.fieldset).textbox({validType: "user_password_confirm['#" + id + "']", missingMessage: window.R.string.USERS_ERROR_CONFIRM_PWD, width: "70%"});
    },

    setAccountName: function(value) {
        this._adjustPasswordRequirements(value);
    },

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

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

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

    getPassword: function() {
        return this.password.val();
    },

    _adjustPasswordRequirements: function(username) {
        var compliant = new jscape.Validator().isSatisfied("user_password_compliance", "", username);
        var options = this.password.textbox("textbox").validatebox("options");
        options.validType = "user_password_compliance" + (username ? "['" + username + "']" : "");
        options.required = !compliant;
    },

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

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

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

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

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

    onSubmit: function(dialog) {
        var detailed = dialog.isDetailedView();
        dialog.destroy();
        this._openReport(detailed);
        this.deferred.resolve();
        this.deferred = null;
    },

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

    _openReport: function(detailed) {
        var url = window.location.pathname + "/accounts-report" + (detailed ? "?all=true" : "");
        window.open(url, "jscape-report-users");
    },

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

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

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

    isDetailedView: function() {
        return this.detailed.is(":checked");
    },

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