jscape.account = jscape.account || {};

/** @class */
jscape.IpAccessRule = Class.extend(
    /** @lends {jscape.IpAccessRule.prototype} */
{
    /** @constructor */
    initialize: function(a, b, c) {
        this.mask = a || "";
        this.reason = b || "";
        this.allowed = c || false;
    }
});
jscape.IpAccessRule.fromJSON = function(data) {
    return data ? new jscape.IpAccessRule(data.mask, data.reason, data.allowed) : null;
};


/** @class */
jscape.account.UsersController = jscape.ui.DatagridController.extend(
    /** @lends {jscape.account.UsersController.prototype} */
{
    username: null,

    /** @constructor */
    initialize: function(username) {
        this.username = username;
        this.view = new jscape.account.UsersView();

        this.addController = new jscape.account.AddUserController();
        this.editController = new jscape.account.EditUserController();
        this.deleteController = new jscape.account.DeleteUserController();

        this._initValidators();
    },

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

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

    onRefresh: function(params) {
        params = jscape.Page.requestParameters(params);
        return jscape.API.listUsers(params.startIndex, params.count, params.query)
                .then(jscape.Page.datagridFormatter());
    },

    onAddUser: function() {
        this.addController.start()
                .done($.proxy(this._userAdded, this));
    },

    onEditUser: function(user) {
        this.editController.start(user)
                .done($.proxy(this._userEdited, this));
    },

    onDeleteUser: function(user) {
        this.deleteController.start(user)
                .done($.proxy(this._userDeleted, this, user));
    },

    deleteAllowed: function(user) {
        return user && user.login !== this.username;
    },

    _userAdded: function (user) {
        this._recordAdded(user);
    },

    _userEdited: function (user) {
        this._recordEdited(user);
    },

    _userDeleted: function (users) {
        this._recordDeleted(users);
    },

    _initValidators: function () {
        var v = new jscape.Validator();
        v.nonEmptyRule("user_login_nonempty", window.R.string.USER_ERROR_BAD_NAME);
        v.rule("user_unique", $.proxy(this._userNotExists, this), window.R.string.USER_ERROR_ALREADY_EXIST);
        v.rule("user_password_compliance", $.proxy(this._passwordCompliant, this), window.R.string.USER_ERROR_PASSWORD_NON_COMPLIANT);
        v.rule("user_password_confirm", $.proxy(this._passwordConfirmed, this), window.R.string.USER_ERROR_CONFIRM_PWD);
    },

    _userNotExists: function(value) {
        var names = $.map(this.view.getUsers(), function(user) { return user.login.toUpperCase(); });
        return $.inArray((value || "").toUpperCase(), names) == -1;
    },

    _passwordCompliant: function (value, params) {
        var accountName = params && params.length ? params[0] : null;
        var result = jscape.API.testPasswordCompliance(accountName, value);
        if ($.isPlainObject(result)) {
            if (result.valid === false && result.message) {
                new jscape.Validator().ruleMessage("user_password_compliance", result.message);
            }
            return !!result.valid;
        }
        return true;
    },

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

/** @class */
jscape.account.UsersView = jscape.ui.DatagridView.extend(
    /** @lends {jscape.account.UsersView.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,
            ctrlSelect: true,
            pagination: true,
            search: true,
            remoteSearch: true,
            remoteSort: true,
            sortName: "name",
            idField: "login",
            columns: [[
                {field: "name", title: $("thead th:nth-child(1)", this.data).text(), width: "25%", sortable: true},
                {field: "login", title: $("thead th:nth-child(2)", this.data).text(), width: "15%", sortable: true},
                {field: "email", title: $("thead th:nth-child(3)", this.data).text(), width: "25%", searchable: false},
                {field: "owner", title: $("thead th:nth-child(4)", this.data).text(), width: "15%", sortable: true},
                {field: "company", title: $("thead th:nth-child(5)", this.data).text(), width: "20%", sortable: true}
            ]],
            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.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)});

        initializing = false;
    },

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

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

    _onLoad$Data: function(params, success, error) {
        this.listener.onRefresh(params).done(success).fail(error);
        this.data.datagrid("resize", {width: "100%"}).datagrid("fitColumns");
    },

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

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

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

    _adjustState: function() {
        this.selection = this.data.datagrid("getSelections");
        this.editButton.linkbutton(this.selection.length == 1 ? "enable" : "disable");
        this.deleteButton.linkbutton(this.selection.length != 0 && this._deleteAllowed() ? "enable" : "disable");
    },

    _deleteAllowed: function() {
        for (var i = 0; i < this.selection.length; i++) {
            if (!this.listener.deleteAllowed(this.selection[i])) {
                return false;
            }
        }
        return true;
    }
});
jscape.account.UsersView.LISTENER = {
    onRefresh: $.noop,
    onAddUser: $.noop,
    onEditUser: $.noop,
    onDeleteUser: $.noop,
    deleteAllowed: $.noop
};

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

    deferred: null,
    templateName: null,

    start: function() {
        this.deferred = $.Deferred();
        this.templateName = null;
        jscape.API.getUserTemplateNames()
                .then($.proxy(this._selectAccountTemplate, this))
                .then($.proxy(function(templateName) { this.templateName = templateName; return jscape.API.getUserTemplate(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 data = this._createData(dialog);
        dialog.destroy();
        jscape.API.addUser(data, this.templateName)
                .done($.proxy(function(info) { this.deferred.resolve(info); 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;
    },

    _selectAccountTemplate: function(templateNames) {
        var deferred = $.Deferred();
        var dialog = new jscape.account.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.account.AddUserDialog();
        window.setTimeout($.proxy(function() {
            try {
                if (template) {
                    this._setupDefaults(dialog, template);
                }
            } catch (e) {
                dialog.destroy();
            } finally {
                dialog = null;
            }
        }, this), 0);
        return dialog;
    },

    _setupDefaults: function (dialog, template) {
        dialog.setName(template.name);
        dialog.setEmail(template.email);
        dialog.setCompany(template.company);
        dialog.setPhone(template.phone);
        dialog.setLoginRedirection(template.loginRedirection);
        dialog.setExpirationTime(template.expirationTime);
        dialog.setEnabled(template.enabled);
        dialog.setSecured(template.secured);
        dialog.setAllowAdHocTransfers(template.emailFileTransferAllowed);
        dialog.setAllowPasswordChanging(template.passwordChangingAllowed);
        dialog.setUseMultiFactorAuthentication(template.usePhoneAuthentication);
        dialog.setUploadsQuota(template.uploadsQuota);
        dialog.setDownloadsQuota(template.downloadsQuota);
        dialog.setTransfersQuota(template.transfersQuota);
        dialog.setMaxTransferRate(template.maxTransferRate);
        dialog.setMaxDownloadsPerSession(template.maxUploadsPerSession);
        dialog.setMaxUploadsPerSession(template.maxDownloadsPerSession);

        jscape.API.getGroupNames()
                .done(function (values) {
                          dialog.setAvailableGroups(values);
                          dialog.setGroups(template.groups);
                      });
    },

    _createData: function(dialog) {
        var data = new jscape.UserData(dialog.getName(),
                                       dialog.getUsername(),
                                       dialog.getEmail(),
                                       dialog.getCompany(),
                                       dialog.getPhone(),
                                       dialog.getGroups(),
                                       dialog.getLoginRedirection(),
                                       dialog.getExpirationTime(),
                                       null,
                                       dialog.getEnabled(),
                                       dialog.getSecured(),
                                       dialog.getAllowPasswordChanging(),
                                       dialog.getAllowAdHocTransfers(),
                                       dialog.getUseMultiFactorAuthentication(),
                                       [jscape.VirtualFileData.local("/", null, false, false, true, dialog.getRootPath())],
                                       dialog.getUploadsQuota(),
                                       dialog.getDownloadsQuota(),
                                       dialog.getTransfersQuota(),
                                       dialog.getMaxTransferRate(),
                                       dialog.getMaxUploadsPerSession(),
                                       dialog.getMaxDownloadsPerSession());
        data.password = dialog.getPassword();
        return data;
    }
});

/** @class */
jscape.account.UserTemplateDialog = Class.extend(
    /** @lends {jscape.account.UserTemplateDialog.prototype} */
{
    /** @constructor */
    initialize: function() {
        this.dialog = $("#d-users-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, handler: $.proxy(this._onSubmit, this)},
                {text: window.R.string.DIALOG_BUTTON_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: false, 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.account.UserInfoView = Class.extend(
    /** @lends {jscape.account.UserInfoView.prototype} */
{
    /** @constructor */
    initialize: function(container) {
        this.fieldset = $("fieldset[name=userinfofields]", container);

        this.name = $("input[name=name]", this.fieldset).textbox({width: "50%"});
        this.email = $("input[name=email]", this.fieldset).textbox({validType: {any: ["variable", "multi_value['email',',']"]}, invalidMessage: window.R.string.USER_ERROR_BAD_EMAIL, width: "40%"});
        this.company = $("input[name=company]", this.fieldset).textbox({width: "40%"});

        this.phoneCode = $("input[name=phonecode]", this.fieldset).textbox({width: 60, validType: "pattern['^[\\\\d]+$']", invalidMessage: window.R.string.USER_ERROR_BAD_PHONE});
        this.phoneNumber = $("input[name=phonenum]", this.fieldset).textbox({width: 140, validType: "pattern['^[\\\\d- ]+$']", invalidMessage: window.R.string.USER_ERROR_BAD_PHONE});
        this.phoneExtension = $("input[name=phoneext]", this.fieldset).textbox({width: 60, validType: "pattern['^[\\\\d- ]+$']", invalidMessage: window.R.string.USER_ERROR_BAD_PHONE});

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

        this.groups = $("table[role=grid][aria-label=usergroups]", this.fieldset);
        this.groups.datagrid({
            fit: true,
            fitColumns: true,
            singleSelect: false,
            checkOnSelect: true,
            selectOnCheck: true,
            remoteSort: false,
            onLoadSuccess: function(data) { $(this).datagrid("getPanel").find("div.datagrid-header-check input:checkbox").prop("disabled", data.rows.length == 0); },
            columns: [[
                  {field: "allowed", checkbox: true},
                  {field: "name", title: $("thead th:nth-child(1)", this.groups).text(), sortable: true, width: 100, formatter: function (_, row) {return String(row || "").escapeXml(); }}
            ]]
        });

        this.expires = $("input[name=expires]:checkbox", this.fieldset);
        this.expires.on("change", $.proxy(function() {
            var enabled = this.expires.is(":checked");
            this.expirationDate.datebox(enabled ? "enable" : "disable").datebox(enabled ? "enableValidation" : "disableValidation");
        }, this));
        this.expirationDate = $("input[name=expirationdate]", this.fieldset);
        this.expirationDate.datebox({
            required: true,
            editable: false,
            disabled: true,
            width: 120,
            formatter: $.proxy(this._formatDate, this),
            parser: $.proxy(this._parseDate, this)
        }).datebox("calendar").calendar({validator: function(date) {
            var d = new Date();
            return date.getFullYear() >= d.getFullYear() && date.getMonth() >= d.getMonth() && date.getDate() >= d.getDate();
        }});

        this.enabled = $("input[name=enabled]:checkbox", this.fieldset);
        this.secured = $("input[name=secured]:checkbox", this.fieldset);
        this.allowPasswordChange = $("input[name=pwdchange]:checkbox", this.fieldset);
        this.allowAdHocTransfers = $("input[name=emailfile]:checkbox", this.fieldset);
    },

    show: function(listener) {
        this.listener = listener || jscape.account.UserInfoView.LISTENER;
        this.fieldset.css({visible: "visible"});
        this.fieldset.form("validate");
    },

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

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

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

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

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

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

    getPhone: function () {
        return this.phoneCode.textbox("isValid") && this.phoneNumber.textbox("isValid")
                ? new jscape.Phone(this.phoneCode.textbox("getValue"), this.phoneNumber.textbox("getValue"), this.phoneExtension.textbox("getValue"))
                : null;
    },

    setPhone: function(phone) {
        if (phone != null) {
            this.phoneCode.textbox("setValue", phone.code);
            this.phoneNumber.textbox("setValue", phone.number);
            this.phoneExtension.textbox("setValue", phone.extension);
        }
    },

    getLoginRedirection: function() {
        return this.loginRedirection.combobox("getValue");
    },

    setLoginRedirection: function(value) {
        this.loginRedirection.combobox("setValue", value);
    },

    setAvailableGroups: function(values) {
        if (this.groups.length) {
            this.groups.datagrid("loading").datagrid("loadData", values).datagrid("loaded");
        }
    },

    getGroups: function() {
        return this.groups.length ? this.groups.datagrid("getChecked") : null;
    },

    setGroups: function(values) {
        if (this.groups.length == 0) {
            return;
        }
        if (values && values.length) {
            var rows = this.groups.datagrid("getRows");
            for (var i = 0; i < values.length; i++) {
                this.groups.datagrid("checkRow", $.inArray(values[i], rows));
            }
        } else {
            this.groups.datagrid("clearChecked");
        }
    },

    getExpirationTime: function() {
        return this.expires.is(":checked")
                ? this.expirationDate.datebox("calendar").calendar("options").current.getTime()
                : null;
    },

    setExpirationTime: function(value) {
        this.expires.prop("checked", value != null).change();
        var formatter = this.expirationDate.datebox("options").formatter;
        this.expirationDate.datebox("setValue", formatter(value != null ? new Date(value) : new Date()));
    },

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

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

    getSecured: function() {
        return this.secured.is(":checked");
    },

    setSecured: function(value) {
        this.secured.prop("checked", !!value);
    },

    getAllowAdHocTransfers: function() {
        return this.allowAdHocTransfers.is(":checked");
    },

    setAllowAdHocTransfers: function(value) {
        this.allowAdHocTransfers.prop("checked", !!value);
    },

    getAllowPasswordChanging: function() {
        return this.allowPasswordChange.is(":checked");
    },

    setAllowPasswordChanging: function(value) {
        this.allowPasswordChange.prop("checked", !!value);
    },

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

    _parseDate: function (value) {
        var matches = /(\d{1,2})\/(\d{1,2})\/(\d{2,4})/.exec(value);
        if (matches != null && matches.length == 4) {
            var m = parseInt(matches[1], 10), d = parseInt(matches[2], 10), y = parseInt(matches[3], 10);
            if (!isNaN(d) && !isNaN(m) && !isNaN(y)) {
                return new Date(y, m - 1, d);
            }
        }
        return new Date();
    }
});
jscape.account.UserInfoView.LISTENER = {};

/** @class */
jscape.account.UserQuotaView = Class.extend(
    /** @lends {jscape.account.UserQuotaView.prototype} */
{
    PERIOD_FACTOR: 24 * 60 * 60 * 1000,

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

        this.downloadQuota = new jscape.account.QuotaPane(
                $("input[name=maxdloadenabled]:checkbox", this.fieldset),
                $("input[name=maxdload]", this.fieldset).numberspinner({
                    required: true, min: 0, max: 9999, value: 1000, increment: 10, disabled: true, width: 80,
                    unitbox: $("select[name=maxdloadunit]", this.fieldset).combobox({
                        required: true, editable: false, disabled: true, width: 60, panelHeight: "auto"
                    })
                }),
                $("input[name=maxdloadresetperiod]", this.fieldset).numberspinner({required: true, min: 1, max: 1000, value: 1, disabled: true, width: 80})
        );

        this.uploadQuota = new jscape.account.QuotaPane(
                $("input[name=maxuploadenabled]:checkbox", this.fieldset),
                $("input[name=maxupload]", this.fieldset).numberspinner({
                    required: true, min: 0, max: 9999, value: 1000, increment: 10, disabled: true, width: 80,
                    unitbox: $("select[name=maxuploadunit]", this.fieldset).combobox({
                        required: true, editable: false, disabled: true, width: 60, panelHeight: "auto"
                    })
                }),
                $("input[name=maxuploadresetperiod]", this.fieldset).numberspinner({required: true, min: 1, max: 1000, value: 1, disabled: true, width: 80})
        );

        this.transferQuota = new jscape.account.QuotaPane(
                $("input[name=maxtransferenabled]:checkbox", this.fieldset),
                $("input[name=maxtransfer]", this.fieldset).numberspinner({
                    required: true, min: 0, max: 9999, value: 1000, increment: 10, disabled: true, width: 80,
                    unitbox: $("select[name=maxtransferunit]", this.fieldset).combobox({required: true, editable: false, disabled: true, width: 60, panelHeight: "auto"})
                }),
                $("input[name=maxtransferresetperiod]", this.fieldset).numberspinner({required: true, min: 1, max: 1000, value: 1, disabled: true, width: 80})
        );

        this.maxTransferRate = new jscape.account.QuotaPane(
                $("input[name=maxtransferrateenabled]:checkbox", this.fieldset),
                $("input[name=maxtransferrate]", this.fieldset).numberspinner({
                    required: true, min: 1, max: 9999, value: 1000, disabled: true, width: 80,
                    unitbox: $("select[name=maxtransferrateunit]", this.fieldset).combobox({
                        required: true, editable: false, disabled: true, width: 70, panelHeight: "auto"
                    })
                })
        );

        this.downloadPerSessionEnabled = $("input[name=maxdloadsessionenabled]:checkbox", this.fieldset).click($.proxy(this._adjustDownloadPerSession, this));
        this.downloadPerSession = $("input[name=maxdloadsession]", this.fieldset).numberspinner({required: true, disabled: true, min: 1, max: 1000, value: 1, width: 80});
        this.uploadPerSessionEnabled = $("input[name=maxuploadsessionenabled]:checkbox", this.fieldset).click($.proxy(this._adjustUploadPerSession, this));
        this.uploadPerSession = $("input[name=maxuploadsession]", this.fieldset).numberspinner({required: true, disabled: true, min: 1, max: 1000, value: 1, width: 80});
    },

    show: function(listener) {
        this.listener = listener || jscape.account.UserQuotaView.LISTENER;
        this.downloadQuota.show(this);
        this.uploadQuota.show(this);
        this.transferQuota.show(this);
        this.maxTransferRate.show(this);
    },

    onStateChanged: function(view) {
        if (view.isEnabled()) {
            if (view == this.transferQuota) {
                this.downloadQuota.setEnabled(false);
                this.uploadQuota.setEnabled(false);
            } else if (view == this.downloadQuota || view == this.uploadQuota){
                this.transferQuota.setEnabled(false);
            }
        }
    },

    getDownloadsQuota: function() {
        return this._getQuota(this.downloadQuota);
    },

    setDownloadsQuota: function(value) {
        this._setQuota(this.downloadQuota, value);
    },

    getUploadsQuota: function() {
        return this._getQuota(this.uploadQuota);
    },

    setUploadsQuota: function(value) {
        this._setQuota(this.uploadQuota, value);
    },

    getTransfersQuota: function() {
        return this._getQuota(this.transferQuota);
    },

    setTransfersQuota: function(value) {
        this._setQuota(this.transferQuota, value);
    },

    getMaxTransferRate: function() {
        return this.maxTransferRate.val();

    },

    setMaxTransferRate: function(value) {
        this.maxTransferRate.val(value);
    },

    getMaxDownloadsPerSession: function() {
        return this.downloadPerSessionEnabled.is(":checked")
               ? parseInt(this.downloadPerSession.numberspinner("getValue"))
               : null;
    },

    setMaxDownloadsPerSession: function(value) {
        value = parseInt(value);
        if (!isNaN(value)) {
            this.downloadPerSessionEnabled.prop("checked", true);
            this.downloadPerSession.numberspinner("setValue", value);
        } else {
            this.downloadPerSessionEnabled.prop("checked", false);
            this.downloadPerSession.numberspinner("reset");
        }
        this._adjustDownloadPerSession();
    },

    getMaxUploadsPerSession: function() {
        return this.uploadPerSessionEnabled.is(":checked")
               ? parseInt(this.uploadPerSession.numberspinner("getValue"))
               : null;
    },

    setMaxUploadsPerSession: function(value) {
        value = parseInt(value);
        if (!isNaN(value)) {
            this.uploadPerSessionEnabled.prop("checked", true);
            this.uploadPerSession.numberspinner("setValue", value);
        } else {
            this.uploadPerSessionEnabled.prop("checked", false);
            this.uploadPerSession.numberspinner("reset");
        }
        this._adjustUploadPerSession();
    },

    _getQuota: function(view) {
        var quota = view.val();
        return quota != null ? new jscape.QuotaData(quota, view.getResetPeriod() * this.PERIOD_FACTOR) : null;
    },

    _setQuota: function(view, quota) {
        if (quota != null) {
            view.val(quota.bytes);
            view.setResetPeriod(quota.resetPeriod / this.PERIOD_FACTOR);
        } else {
            view.val(null);
        }
    },

    _adjustDownloadPerSession: function() {
        var enabled = this.downloadPerSessionEnabled.is(":checked");
        this.downloadPerSession.numberspinner(enabled ? "enable" : "disable").numberspinner(enabled ? "enableValidation" : "disableValidation");
    },

    _adjustUploadPerSession: function() {
        var enabled = this.uploadPerSessionEnabled.is(":checked");
        this.uploadPerSession.numberspinner(enabled ? "enable" : "disable").numberspinner(enabled ? "enableValidation" : "disableValidation");
    }
});
jscape.account.UserQuotaView.LISTENER = {};

/** @class */
jscape.account.QuotaPane = Class.extend(
    /** @lends {jscape.account.QuotaPane.prototype} */
{
    /** @constructor */
    initialize: function(checkbox, count, resetPeriod) {
        this.enabled = checkbox
                .click($.proxy(this._onClick$Enable, this))
                .change($.proxy(this._onChange$Enable, this));

        this.input = count;
        this.period = resetPeriod;
    },

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

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

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

    getResetPeriod: function() {
        return this.period && this.period.length ? parseInt(this.period.numberspinner("getValue")) : null;
    },

    setResetPeriod: function(value) {
        if (this.period && this.period.length) {
            value = parseInt(value);
            if (!isNaN(value)) {
                this.period.numberspinner("setValue", value);
            }
        }
    },

    val: function (value) {
        if (!arguments.length) {
            return this.isEnabled() ? parseInt(this.input.numberspinner("getValue")) : null;
        } else {
            value = parseInt(value);
            if (isNaN(value)) {
                this.setEnabled(false);
            } else {
                this.setEnabled(true);
                this.input.numberspinner("setValue", value);
            }
        }
    },

    _onChange$Enable: function () {
        var unitbox = this.input.numberspinner("options").unitbox;
        if (this.isEnabled()) {
            this.input.numberspinner("enable").numberspinner("enableValidation");
            if (this.period && this.period.length) {
                this.period.numberspinner("enable").numberspinner("enableValidation");
            }
            if (unitbox && unitbox.length) {
                unitbox.combobox("enable").combobox("enableValidation");
            }
        } else {
            this.input.numberspinner("disable").numberspinner("disableValidation");
            if (this.period && this.period.length) {
                this.period.numberspinner("disable").numberspinner("disableValidation");
            }
            if (unitbox && unitbox.length) {
                unitbox.combobox("disable").combobox("disableValidation");
            }
        }
    },

    _onClick$Enable: function() {
        this.listener.onStateChanged(this);
    }
});
jscape.account.QuotaPane.LISTENER = {
    onStateChanged: $.noop
};

/** @class */
jscape.account.UserDialog = Class.extend(
    /** @lends {jscape.account.UserDialog.prototype} */
{
    /** @constructor */
    initialize: function(dialog) {
        this.dialog = $(dialog).clone().attr("id", "");
        this.dialog.dialog({
            width: 800, height: "auto",
            modal: true, resizable: false, closable: true, closed: true,
            buttons: [
                {text: window.R.string.DIALOG_BUTTON_OK, handler: $.proxy(this._onSubmit, this)},
                {text: window.R.string.DIALOG_BUTTON_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.fieldset = $("fieldset[name=userfields]", this.dialog);

        this.infoView = new jscape.account.UserInfoView(this.dialog);
        this.quotaView = new jscape.account.UserQuotaView(this.dialog);

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

    getName: function() {
        return this.infoView.getName();
    },

    setName: function(value) {
        this.infoView.setName(value);
    },

    getEmail: function() {
        return this.infoView.getEmail();
    },

    setEmail: function(value) {
        this.infoView.setEmail(value);
    },

    getCompany: function() {
        return this.infoView.getCompany();
    },

    setCompany: function(value) {
        this.infoView.setCompany(value);
    },

    getPhone: function() {
        return this.infoView.getPhone();
    },

    setPhone: function(value) {
        this.infoView.setPhone(value);
    },

    getLoginRedirection: function() {
        return this.infoView.getLoginRedirection();
    },

    setLoginRedirection: function(value) {
        this.infoView.setLoginRedirection(value);
    },

    setAvailableGroups: function(values) {
        this.infoView.setAvailableGroups(values);
    },

    getGroups: function() {
        return this.infoView.getGroups();
    },

    setGroups: function(values) {
        this.infoView.setGroups(values);
    },

    getExpirationTime: function() {
        return this.infoView.getExpirationTime();
    },

    setExpirationTime: function(value) {
        this.infoView.setExpirationTime(value);
    },

    getEnabled: function() {
        return this.infoView.getEnabled();
    },

    setEnabled: function(value) {
        this.infoView.setEnabled(value);
    },

    getSecured: function() {
        return this.infoView.getSecured();
    },

    setSecured: function(value) {
        this.infoView.setSecured(value);
    },

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

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

    getAllowAdHocTransfers: function() {
        return this.infoView.getAllowAdHocTransfers();
    },

    setAllowAdHocTransfers: function(value) {
        this.infoView.setAllowAdHocTransfers(value);
    },

    getAllowPasswordChanging: function() {
        return this.infoView.getAllowPasswordChanging();
    },

    setAllowPasswordChanging: function(value) {
        this.infoView.setAllowPasswordChanging(value);
    },

    getDownloadsQuota: function() {
        return this.quotaView.getDownloadsQuota();
    },

    setDownloadsQuota: function(value) {
        this.quotaView.setDownloadsQuota(value);
    },

    getUploadsQuota: function() {
        return this.quotaView.getUploadsQuota();
    },

    setUploadsQuota: function(value) {
        return this.quotaView.setUploadsQuota(value);
    },

    getTransfersQuota: function() {
        return this.quotaView.getTransfersQuota();
    },

    setTransfersQuota: function(value) {
        this.quotaView.setTransfersQuota(value);
    },

    getMaxTransferRate: function() {
        return this.quotaView.getMaxTransferRate();
    },

    setMaxTransferRate: function(value) {
        this.quotaView.setMaxTransferRate(value);
    },

    getMaxDownloadsPerSession: function() {
        return this.quotaView.getMaxDownloadsPerSession();
    },

    setMaxDownloadsPerSession: function(value) {
        this.quotaView.setMaxDownloadsPerSession(value);
    },

    getMaxUploadsPerSession: function() {
        return this.quotaView.getMaxUploadsPerSession();
    },

    setMaxUploadsPerSession: function(value) {
        this.quotaView.setMaxUploadsPerSession(value);
    },

    show: function (listener) {
        this.listener = listener;
        this.dialog.dialog("center").dialog("open");
        this.infoView.show(listener);
        this.quotaView.show(listener);
        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.account.AddUserDialog = jscape.account.UserDialog.extend(
    /** @lends {jscape.account.AddUserDialog.prototype} */
{
    /** @constructor */
    initialize: function() {
        this._super($("#d-users-add"));

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

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

        var id = "newpwd_" + $.now().toString(36);
        this.password = $("input[name=password]", this.fieldset).textbox({type: "password", validType: "user_password_compliance", width: "40%"});
        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({type: "password", validType: "user_password_confirm['#" + id + "']", missingMessage: window.R.string.USER_ERROR_CONFIRM_PWD, width: "40%"});

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

        $("a[role=button][name=resettotp]", this.fieldset).hide();
    },

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

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

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

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

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

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

/** @class */
jscape.account.EditUserDialog = jscape.account.UserDialog.extend(
    /** @lends {jscape.account.EditUserDialog.prototype} */
{
    /** @constructor */
    initialize: function() {
        this._super($("#d-users-edit"));

        var initializing = true;

        this.sizeFormat = new jscape.SizeFormat();
        this.title = this.dialog.dialog("header").text() || "";

        this.tabs = $("div[role=tablist]", this.dialog).tabs({tabPosition: "top", plain: true});
        this.changePasswordButton = $("a[role=button][name=changepwd]", this.dialog).linkbutton({onClick: $.proxy(this._onClick$ChangePasswordButton, this)});

        this.useMultiFactorAuth.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({onClick: $.proxy(this._onClick$ResetTotpKeyButton, this)});
        this.useMultiFactorAuth.change();

        this.monitors = $("table[role=grid][aria-label=dirmonitors]", this.dialog);
        this.monitors.datagrid({
            fit: true,
            fitColumns: true,
            singleSelect: true,
            pagination: true,
            search: true,
            remoteSearch: true,
            remoteSort: true,
            sortName: "name",
            idField: "name",
            columns: [[
                {field: "path", title: $("thead th:nth-child(1)", this.monitors).text(), width: 200, sortable: true},
                {field: "quota", title: $("thead th:nth-child(2)", this.monitors).text(), width: 200, searchable: false, formatter: $.proxy(this._formatQuota, this), styler: $.proxy(this._styleQuota, this)}
            ]],
            loader: $.proxy(this._onLoad$DirMonitors, this),
            onBeforeLoad: function() { return !initializing; }
        });

        initializing = false;
    },

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

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

    /** @override */
    show: function(listener) {
        this._super(listener);
        this.monitors.datagrid("reload");
    },

    _formatQuota: function (quota) {
        return quota ? window.R.string.QUOTAS_TEMPLATE_USAGE.supplant({0: this.sizeFormat.format(quota.currentValue), 1: this.sizeFormat.format(quota.value)}) : "";
    },

    _styleQuota: function(quota) {
        return quota && !quota.exceeded() ? "color:green" : "color:red";
    },

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

    _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.account.EditUserDialog.LISTENER = {
    onChangePassword: $.noop,
    onRefreshMonitors: $.noop,
    onResetTotpKey: $.noop
};

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

    start: function(user) {
        this.deferred = $.Deferred();
        this.user = user;
        jscape.API.getUser(this.user.login)
                .done($.proxy(function(data) { this._setupDialog(data).show(this); }, this))
                .fail($.proxy(function() { this.deferred.reject(); this.deferred = null; }, this));
        return this.deferred.promise();
    },

    onSubmit: function(dialog) {
        var data = this._createData(dialog);
        dialog.destroy();
        jscape.API.updateUser(this.user.login, data)
                .done($.proxy(function(info) { this.deferred.resolve(info); 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;
    },

    onChangePassword: function(dialog) {
        var username = this.user.login;
        var controller = new jscape.account.ChangePasswordController();
        return controller.start(username)
                .then(function () { return jscape.API.getUser(username); })
                .done($.proxy(function (data) {
                          data = $.extend(true, data, this._createData(dialog));
                          this._setupView(dialog, data);
                      }, this));
    },

    onResetTotpKey: function(dialog) {
        var username = this.user.login;
        return jscape.API.resetUserOtp(username)
                .then(function () { return jscape.API.getUser(username); })
                .done($.proxy(this._showMessageTotpKeyReset, this))
                .done($.proxy(function (data) {
                          data = $.extend(true, data, this._createData(dialog));
                          this._setupView(dialog, data);
                      }, this));
    },

    onRefreshMonitors: function (params) {
        params = jscape.Page.requestParameters(params);
        return jscape.API.listDirectoryMonitors(this.user.login, params.startIndex, params.count, params.query)
                .then(jscape.Page.datagridFormatter(), function() { return {total: 0, rows: []}; });
    },

    _setupDialog: function(data) {
        var dialog = new jscape.account.EditUserDialog();
        this.vfsController = new jscape.vfs.VirtualFilesController(dialog.container());
        this.ipAccessController = new jscape.account.UserIpAccessController(dialog.container());
        if (data) {
            this._setupView(dialog, data);
        }
        return dialog;
    },

    _setupView: function(dialog, data) {
        dialog.setName(data.name);
        dialog.setUsername(data.username);
        dialog.setEmail(data.email);
        dialog.setCompany(data.company);
        dialog.setPhone(data.phone);
        dialog.setLoginRedirection(data.loginRedirection);
        dialog.setExpirationTime(data.expirationTime);
        dialog.setEnabled(data.enabled);
        dialog.setSecured(data.secured);
        dialog.setAllowAdHocTransfers(data.emailFileTransferAllowed);
        dialog.setAllowPasswordChanging(data.passwordChangingAllowed);
        dialog.setUseMultiFactorAuthentication(data.usePhoneAuthentication);

        dialog.setUploadsQuota(data.uploadsQuota);
        dialog.setDownloadsQuota(data.downloadsQuota);
        dialog.setTransfersQuota(data.transfersQuota);
        dialog.setMaxTransferRate(data.maxTransferRate);
        dialog.setMaxDownloadsPerSession(data.maxUploadsPerSession);
        dialog.setMaxUploadsPerSession(data.maxDownloadsPerSession);

        jscape.API.getGroupNames()
                .done(function (values) {
                          dialog.setAvailableGroups(values);
                          dialog.setGroups(data.groups);
                      });

        this.vfsController.start(data.resources);
        this.ipAccessController.start(data.ipAccessRules);
    },

    _createData: function (dialog) {
        return new jscape.UserData(dialog.getName(),
                                   this.user.login,
                                   dialog.getEmail(),
                                   dialog.getCompany(),
                                   dialog.getPhone(),
                                   dialog.getGroups(),
                                   dialog.getLoginRedirection(),
                                   dialog.getExpirationTime(),
                                   null,
                                   dialog.getEnabled(),
                                   dialog.getSecured(),
                                   dialog.getAllowPasswordChanging(),
                                   dialog.getAllowAdHocTransfers(),
                                   dialog.getUseMultiFactorAuthentication(),
                                   this.vfsController.getResources(),
                                   dialog.getUploadsQuota(),
                                   dialog.getDownloadsQuota(),
                                   dialog.getTransfersQuota(),
                                   dialog.getMaxTransferRate(),
                                   dialog.getMaxUploadsPerSession(),
                                   dialog.getMaxDownloadsPerSession(),
                                   this.ipAccessController.getIpAccessRules());
    },

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

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

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

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

    _deleteConfirmed: function (users) {
        $.when.apply(jQuery, $.map(users, $.proxy(function(user) { return jscape.API.deleteUser(user.login); }, this)))
                .done($.proxy(function () { this.deferred.resolve(users); this.deferred = null; }, this))
                .fail($.proxy(function() { this.deferred.reject(); this.deferred = null; }, this));
    }
});


/** @class */
jscape.account.UserIpAccessController = jscape.ui.DatagridController.extend(
    /** @lends {jscape.account.UserIpAccessController.prototype} */
{
    rules: null,

    /** @constructor */
    initialize: function(container) {
        this.view = new jscape.account.UserIpAccessView(container);

        this.addController = new jscape.account.AddUserIpAccessController();
        this.editController = new jscape.account.EditUserIpAccessController();
        this.deleteController = new jscape.account.DeleteUserIpAccessController();

        this._initValidators();
    },

    start: function(rules) {
        this.rules = rules || [];

        this.view.setRules(this.rules);
        this.view.show(this);
    },

    getIpAccessRules: function() {
        return this.rules;
    },

    onAddRule: function() {
        this.addController.start().done($.proxy(this._ruleAdded, this));
    },

    onEditRule: function(rule) {
        var index = $.inArray(rule, this.rules);
        if (index != -1) {
            this.editController.start(rule).done($.proxy(this._ruleEdited, this, index));
        }
    },

    onDeleteRule: function(rules) {
        this.deleteController.start(rules).done($.proxy(this._ruleDeleted, this, rules));
    },

    onRuleUp: function(rule) {
        var index = $.inArray(rule, this.rules);
        if (index > 0) {
            this.rules.splice(index - 1, 2, this.rules[index], this.rules[index - 1]);
            this.view.setRules(this.rules);
            this.view.selectRule(rule);
        }
    },

    onRuleDown: function(rule) {
        var index = $.inArray(rule, this.rules);
        if (index != -1 && index < this.rules.length - 1) {
            this.rules.splice(index, 2, this.rules[index + 1], this.rules[index]);
            this.view.setRules(this.rules);
            this.view.selectRule(rule);
        }
    },

    _ruleAdded: function(rule) {
        this.rules.push(rule);
        this.view.setRules(this.rules);
        this.view.selectRule(rule);
    },

    _ruleEdited: function(index, rule) {
        this.rules[index] = rule;
        this.view.setRules(this.rules);
        this.view.selectRule(rule);
    },

    _ruleDeleted: function(rules) {
        var index = -1;
        while (rules.length) {
            index = $.inArray(rules.pop(), this.rules);
            this.rules.splice(index, 1);
        }
        this.view.setRules(this.rules);

        if (this.rules.length) {
            index = Math.max(0, Math.min(index, this.rules.length - 1));
            this.view.selectRule(this.rules[index]);
        }
    },

    _initValidators: function() {
        var v = new jscape.Validator();
        v.nonEmptyRule("user_ipaccess_mask_nonempty", window.R.string.USERS_IP_ACCESS_ERROR_BAD_MASK);
        v.rule("user_ipaccess_unique", $.proxy(this._ruleNotExists, this), window.R.string.USERS_IP_ACCESS_ERROR_ALREADY_EXIST);
    },

    _ruleNotExists: function(value, excludes) {
        return $.grep(this.rules, function(rule) {
            return rule.mask == value && (excludes == undefined || $.inArray(rule.mask, excludes) == -1);
        }).length == 0;
    }
});

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

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

        this.data = $("table[role=grid][aria-label=ipaccess]", this.fieldset);
        this.data.datagrid({
            fit: true,
            fitColumns: true,
            singleSelect: true,
            columns: [[
                {field: "mask", title: $("thead th:nth-child(1)", this.data).text(), width: 60},
                {field: "allowed", title: $("thead th:nth-child(2)", this.data).text(), width: 15, formatter: $.proxy(this._formatAccess, this), styler: $.proxy(this._styleAccess, this)},
                {field: "reason", title: $("thead th:nth-child(3)", this.data).text(), width: 25}
            ]],
            onDblClickRow: $.proxy(this._onClick$EditButton, this),
            onSelect: $.proxy(this._adjustState, this),
            onUnselect: $.proxy(this._adjustState, this),
            onLoadSuccess: $.proxy(this._adjustState, this)
        });

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

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

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

    selectRule: function(rule) {
        this.selectRecord(rule);
    },

    _formatAccess: function(value) {
        return !!value ? window.R.string.USERS_IP_ACCESS_RULE_ALLOWED : window.R.string.USERS_IP_ACCESS_RULE_DENIED;
    },

    _styleAccess: function(value) {
        return !!value ? "color:green" : "color:red";
    },

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

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

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

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

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

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

        this.moveUpButton.linkbutton(index > 0 && index <= count - 1 ? "enable" : "disable");
        this.moveDownButton.linkbutton(index >= 0 && index < count - 1 ? "enable" : "disable");
        this.editButton.linkbutton(this.selection.length == 1 ? "enable" : "disable");
        this.deleteButton.linkbutton(this.selection.length !=0 ? "enable" : "disable");
    }
});
jscape.account.UserIpAccessView.LISTENER = {
    onAddRule: $.noop,
    onEditRule: $.noop,
    onDeleteRule: $.noop,
    onRuleUp: $.noop,
    onRuleDown: $.noop
};

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

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

    onSubmit: function (dialog) {
        var rule = this._createRule(dialog);
        dialog.hide();
        this.deferred.resolve(rule);
        this.deferred = null;
    },

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

    _createRule: function(dialog) {
        return new jscape.IpAccessRule(dialog.getMask(),
                                       dialog.getReason(),
                                       dialog.getAllowed());
    },

    _setupDialog: function () {
        var dialog = new jscape.account.UserIpAccessRuleDialog();
        dialog.setTitle(window.R.string.USERS_IP_ACCESS_DIALOG_ADD_TITLE);
        dialog.setAllowed(true);
        return dialog;
    }
});

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

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

    onSubmit: function(dialog) {
        var rule = this._createRule(dialog);
        dialog.hide();
        this.deferred.resolve(rule);
        this.deferred = null;
    },

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

    _createRule: function(dialog) {
        return new jscape.IpAccessRule(dialog.getMask(),
                                       dialog.getReason(),
                                       dialog.getAllowed());
    },

    _setupDialog: function (rule) {
        var dialog = new jscape.account.UserIpAccessRuleDialog();
        dialog.setTitle(window.R.string.USERS_IP_ACCESS_DIALOG_EDIT_TITLE);
        dialog.setMask(rule.mask);
        dialog.setReason(rule.reason);
        dialog.setAllowed(rule.allowed);
        return dialog;
    }
});

/** @class */
jscape.account.DeleteUserIpAccessController = Class.extend(
    /** @lends {jscape.account.DeleteUserIpAccessController.prototype} */
{
    start: function (rules) {
        var text = $.map(rules, function (rule) { return rule.mask; }).join(", ");
        return jscape.ConfirmDialog.confirm(window.R.string.USERS_IP_ACCESS_CONFIRM_DELETE_TITLE,
                                            window.R.string.USERS_IP_ACCESS_CONFIRM_DELETE_MESSAGE.supplant({0: text.escapeXml()}),
                                            false);
    }
});

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

        this.mask = $("input[name=mask]", this.fieldset).textbox({required: true, validType: ["user_ipaccess_mask_nonempty", "user_ipaccess_unique"], missingMessage: window.R.string.USERS_IP_ACCESS_ERROR_BAD_MASK, width: "60%"});
        this.reason = $("input[name=reason]", this.fieldset).textbox({width: "60%"});
        this.allowed = $("input[name=allowed]:radio", this.fieldset);
    },

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

    show: function (listener) {
        this.listener = listener;
        this.dialog.dialog("center").dialog("open");
        this.fieldset.form("validate");
        this.mask.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");
    },

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

    setMask: function (value) {
        this.mask.textbox("setValue", value);
        if (value && value.trim().length) {
            this.mask.textbox("textbox").validatebox("options").validType = ["user_ipaccess_mask_nonempty", "user_ipaccess_unique['" + value + "']"];
        }
    },

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

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

    getAllowed: function () {
        return (/^true$/i).test(this.allowed.filter(":checked").val());
    },

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

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