jscape.vfs = jscape.vfs || {};

/** @class */
jscape.VirtualFile = Class.extend(
    /** @lends {jscape.VirtualFile.prototype} */
{
    /** @constructor */
    initialize: function(a, b, c, d, e) {
        this.path = a == "" ? "/" : a;
        this.accessPermissions = b || new jscape.AccessPermissions();
        this.secured = c || false;
        this.denied = d || false;
        this.indexable = e || false;
    },

    isRoot: function() {
        return "/" === this.path;
    }
});
jscape.VirtualFile.local = function(path, permissions, secured, denied, indexable, realPath, create, pgpEncrypt, dlp) {
    return $.extend(new jscape.VirtualFile(path, permissions, secured, denied, indexable), {
        realPath: realPath,
        createIfNotExists: Boolean(create),
        pgpEncryption: pgpEncrypt || new jscape.PgpEncryption(),
        dataLossPrevention: dlp || new jscape.DataLossPrevention()
    });
};
jscape.VirtualFile.remote = function(path, permissions, secured, denied, reverseProxy) {
    return $.extend(new jscape.VirtualFile(path, permissions, secured, denied, false), {
        reverseProxy: reverseProxy,
        toJSON: function() { return $.extend({name: this.reverseProxy}, this); }
    });
};
jscape.VirtualFile.fromJSON = function(data) {
    var permissions = jscape.AccessPermissions.fromJSON(data.accessPermissions);
    return data.name && data.name.trim().length
            ? jscape.VirtualFile.remote(data.path, permissions, data.secured, data.denied, data.name)
            : jscape.VirtualFile.local(data.path, permissions, data.secured, data.denied, data.indexable, data.realPath,
                                       data.createIfNotExists,
                                       data.pgpEncryption ? jscape.PgpEncryption.fromJSON(data.pgpEncryption) : null,
                                       data.dataLossPrevention ? jscape.DataLossPrevention.fromJSON(data.dataLossPrevention) : null);
};

/** @class */
jscape.AccessPermissions = Class.extend(
    /** @lends {jscape.AccessPermissions.prototype} */
{
    FORMAT: {
        fileDownloading: "R", fileUploading: "W", fileOwerwriting: "O", fileAppending: "A", fileDeletion: "D", fileRenaming: "R", fileListing: "L",
        dirCreation: "C", dirDeletion: "D", dirListing: "L", dirBrowsing: "B",
        disabled: "-"
    },

    /** @constructor */
    initialize: function(a, b, c, d, e, f, g, h, i, j, k) {
        this.fileDownloadingAllowed = a != undefined ? a : true;
        this.fileUploadingAllowed = b != undefined ? b : true;
        this.fileOverwritingAllowed = c != undefined ? c : true;
        this.fileDeletionAllowed = d != undefined ? d : true;
        this.fileAppendingAllowed = e != undefined ? e : true;
        this.fileListingAllowed = f != undefined ? f : true;
        this.fileRenamingAllowed = g != undefined ? g : true;
        this.directoriesListingAllowed = h != undefined ? h : true;
        this.directoryMakingAllowed = i != undefined ? i : true;
        this.directoryDeletionAllowed = j != undefined ? j : true;
        this.subdirectoriesBrowsingAllowed = k != undefined ? k : true;
    },

    format: function () {
        return this._valueOf(this.fileDownloadingAllowed, this.FORMAT.fileDownloading)
               + this._valueOf(this.fileUploadingAllowed, this.FORMAT.fileUploading)
               + this._valueOf(this.fileOverwritingAllowed, this.FORMAT.fileOwerwriting)
               + this._valueOf(this.fileAppendingAllowed, this.FORMAT.fileAppending)
               + this._valueOf(this.fileDeletionAllowed, this.FORMAT.fileDeletion)
               + this._valueOf(this.fileRenamingAllowed, this.FORMAT.fileRenaming)
               + this._valueOf(this.fileListingAllowed, this.FORMAT.fileListing)
               + this._valueOf(this.directoryMakingAllowed, this.FORMAT.dirCreation)
               + this._valueOf(this.directoryDeletionAllowed, this.FORMAT.dirDeletion)
               + this._valueOf(this.directoriesListingAllowed, this.FORMAT.dirListing)
               + this._valueOf(this.subdirectoriesBrowsingAllowed, this.FORMAT.dirBrowsing);
    },

    _valueOf: function (value, str) {
        return value ? str : this.FORMAT.disabled;
    }
});
jscape.AccessPermissions.fromJSON = function(data) {
    return $.extend(new jscape.AccessPermissions(), data);
};

/** @class */
jscape.PgpEncryption = Class.extend(
    /** @lends {jscape.PgpEncryption.prototype} */
{
    /** @constructor */
    initialize: function(a, b) {
        this.keyProvider = a || new jscape.PgpFileKeyProvider();
        this.enabled = b || false;
    }
});
jscape.PgpEncryption.fromJSON = function(data) {
    var provider = data.keyProvider && data.keyProvider.hasOwnProperty("keyAlias")
                   ? new jscape.ServerKeyProvider(data.keyProvider.keyAlias)
                   : new jscape.PgpFileKeyProvider();
    return new jscape.PgpEncryption(provider, !!data.enabled);
};

/** @class */
jscape.PgpFileKeyProvider = jscape.FileKeyProvider.extend(
    /** @lends {jscape.PgpFileKeyProvider.prototype} */
{
    /** @constructor */
    initialize: function() {
        this._super("/.pgp/key.pub", "");
    }
});

/** @class */
jscape.DataLossPrevention = Class.extend(
    /** @lends {jscape.DataLossPrevention.prototype} */
{
    /** @constructor */
    initialize: function(a, b, c) {
        this.rules = $.isArray(a) ? a : [];
        this.icapAccess = b || null;
        this.enabled = c || false;
    }
});
jscape.DataLossPrevention.fromJSON = function(data) {
    return data
            ? new jscape.DataLossPrevention($.map($.isArray(data.rules) ? data.rules : [], jscape.DataLossPrevention.Entry.fromJSON),
                                            data.icapAccess,
                                            !!data.enabled)
            : new jscape.DataLossPrevention([], null, false);
};
/** @class */
jscape.DataLossPrevention.Entry = Class.extend(
    /** @lends {jscape.DataLossPrevention.Entry.prototype} */
{
    /** @constructor */
    initialize: function(a, b, c) {
        this.ruleName = a || null;
        this.access = b || null;
        this.enabled = c || false;
    }
});
jscape.DataLossPrevention.Entry.fromJSON = function(data) {
    return $.extend(new jscape.DataLossPrevention.Entry(), data);
};


/** @class */
jscape.vfs.VirtualFilesController = Class.extend(
    /** @lends {jscape.vfs.VirtualFilesController.prototype} */
{
    paths: [],

    /** @constructor */
    initialize: function(container) {
        this.view = new jscape.vfs.VirtualFilesView(container);
        this.addController = new jscape.vfs.AddPathController();
        this.editController = new jscape.vfs.EditPathController();
        this.deleteController = new jscape.vfs.DeletePathController();

        this._initValidators();
    },

    start: function(managementService, domainName, paths) {
        this.managementService = managementService;
        this.domainName = domainName;
        this.paths = [].concat(paths);

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

    getDescriptors: function() {
        return this.paths;
    },

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

    onEditPath: function(path) {
        var index = $.inArray(path, this.paths);
        if (index != -1) {
            this.editController.start(this.managementService, this.domainName, path)
                    .done($.proxy(this._pathEdited, this, index));
        }
    },

    onDeletePath: function(paths) {
        this.deleteController.start(paths)
                .done($.proxy(this._pathDeleted, this, paths));
    },

    onPathUp: function(path) {
        var index = $.inArray(path, this.paths);
        if (index > 0) {
            this.paths.splice(index - 1, 2, this.paths[index], this.paths[index - 1]);
            this.view.setPaths(this.paths);
            this.view.selectPath(path);
        }
    },

    onPathDown: function(path) {
        var index = $.inArray(path, this.paths);
        if (index != -1 && index != this.paths.length - 1) {
            this.paths.splice(index, 2, this.paths[index + 1], this.paths[index]);
            this.view.setPaths(this.paths);
            this.view.selectPath(path);
        }
    },

    _pathAdded: function(path) {
        this.paths.push(path);
        this.view.setPaths(this.paths);
        this.view.selectPath(path);
    },

    _pathEdited: function(index, path) {
        this.paths[index] = path;
        this.view.setPaths(this.paths);
        this.view.selectPath(path);
    },

    _pathDeleted: function (paths) {
        var index;
        while (paths.length) {
            index = $.inArray(paths.pop(), this.paths);
            if (index != -1) {
                this.paths.splice(index, 1);
            }
        }

        this.view.setPaths(this.paths);

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

    _setupView: function() {
        this.view.setPaths(this.paths);
    },

    _initValidators: function () {
        var v = new jscape.Validator();
        v.rule("vfs_unique", $.proxy(this._pathNotExists, this), window.R.string.VFS_ERROR_BAD_PATH);
        v.rule("vfs_root_found", $.proxy(this._rootPathFound, this), window.R.string.VFS_ERROR_ROOT_PATH_NOT_FOUND);
        v.nonEmptyRule("vfs_realpath_nonempty", window.R.string.VFS_ERROR_BAD_REAL_PATH);
    },

    _pathNotExists: function (path, excludes) {
        return $.grep(this.paths, function (file) {
                    return file.path == path && (excludes == undefined || $.inArray(path, excludes) == -1);
                }).length == 0;
    },

    _rootPathFound: function(paths) {
        return $.grep(paths || [], function(path) { return path.isRoot(); }).length != 0;
    }
});

/** @class */
jscape.vfs.VirtualFilesView = Class.extend(
    /** @lends {jscape.vfs.VirtualFilesView.prototype} */
{
    selection: [],

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

        this.data = $("table[role=grid][aria-label=paths]", this.fieldset);
        this.data.datagrid({
            fit: true,
            fitColumns: true,
            singleSelect: true,
            onSelect: $.proxy(this._adjustRowSelection, this),
            onUnselect: $.proxy(this._adjustRowSelection, this),
            onSortColumn: $.proxy(this._adjustButtonsState, this),
            onLoadSuccess: $.proxy(this._adjustButtonsState, this),
            onDblClickRow: $.proxy(this._onClick$EditButton, this),
            columns: [[
                {field: "path", title: $("thead th:nth-child(1)", this.data).text(), resizable: true, sortable: false, width: 60},
                {field: "mapping", title: $("thead th:nth-child(2)", this.data).text(), resizable: true, sortable: false, width: 100, formatter: function(_, row) { return (row.realPath ? row.realPath : (row.reverseProxy ? row.reverseProxy : "")).escapeXml(); }},
                {field: "permissions", title: $("thead th:nth-child(3)", this.data).text(), resizable: false, sortable: false, width: 70, formatter: function(_, row) { return row.accessPermissions.format(); }}
            ]]
        });

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

    show: function(listener) {
        this.listener = listener || jscape.vfs.VirtualFilesView.LISTENER;
        this.selection = [];
        this._initState();
    },

    setPaths: function(values) {
        this.data.datagrid("loadData", values);
    },

    selectPath: function(path) {
        this.data.datagrid("selectRow", this.data.datagrid("getRowIndex", path));
    },

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

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

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

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

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

    _initState: function() {
        this._adjustButtonsState();
    },

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

    _adjustButtonsState: function() {
        var index = this.selection.length == 1 ? this.data.datagrid("getRowIndex", this.selection[0]) : -1;
        var rowCount = this.data.datagrid("getRows").length;
        var deleteEnabled = this.selection.length > 0 && new jscape.Validator().isSatisfied("vfs_delete_allowed", this.selection);

        this.moveUpButton.linkbutton(index > 0 && index <= rowCount - 1 ? "enable" : "disable");
        this.moveDownButton.linkbutton(index >= 0 && index < rowCount - 1 ? "enable" : "disable");
        this.editButton.linkbutton(this.selection.length == 1 ? "enable" : "disable");
        this.deleteButton.linkbutton(this.selection.length > 0  ? "enable" : "disable");
    }
});
jscape.vfs.VirtualFilesView.LISTENER = {
    onAddPath: $.noop,
    onEditPath: $.noop,
    onDeletePath: $.noop,
    onPathUp: $.noop,
    onPathDown: $.noop
};

/** @class */
jscape.vfs.AddPathController = Class.extend(
    /** @lends {jscape.vfs.AddPathController.prototype} */
{
    VARIABLES: ["installdir", "domain", "sessionid", "username", "group", "queryattr['name']"],

    permissions: null,
    keyProvider: null,
    dlp: null,
    deferred: null,

    /** @constructor */
    initialize: function() {
        this.pgpSettingsController = new jscape.vfs.PgpEncryptSettingsController();
        this.dlpSettingsController = new jscape.vfs.DlpSettingsController();
        this.variableController = new jscape.VariableController();
    },

    start: function(managementService, domainName) {
        this.managementService = managementService;
        this.domainName = domainName;
        this.permissions = new jscape.AccessPermissions();
        this.keyProvider = new jscape.FileKeyProvider();
        this.dlp = new jscape.DataLossPrevention();
        this.deferred = $.Deferred();
        this._setupDialog().show(this);
        return this.deferred.promise();
    },

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

    onSelectPath: function () {
        return new SelectPathController($.proxy(this.managementService.listFileSystem, this.managementService),
                                        $.proxy(this.managementService.createFileSystemDir, this.managementService))
                .selectDirectory().then(function(entry) { return entry.path; });
    },

    onSetPgpEncryptUploadsSettings: function() {
        this.pgpSettingsController.start(this.managementService, this.domainName, this.keyProvider)
                .done($.proxy(function(provider) {
                    this.keyProvider = provider;
                }, this));
    },

    onSetDlpSettings: function() {
        this.dlpSettingsController.start(this.managementService, this.domainName, this.dlp)
                .done($.proxy(function(dlp) { this.dlp = dlp; }, this));
    },

    onSetPermission: function() {
        var dialog = new jscape.vfs.VirtualPathPermissionsDialog();
        dialog.setFileDownloading(this.permissions.fileDownloadingAllowed);
        dialog.setFileUploading(this.permissions.fileUploadingAllowed);
        dialog.setFileOverwriting(this.permissions.fileOverwritingAllowed);
        dialog.setFileDeletion(this.permissions.fileDeletionAllowed);
        dialog.setFileAppending(this.permissions.fileAppendingAllowed);
        dialog.setFileListing(this.permissions.fileListingAllowed);
        dialog.setFileRenaming(this.permissions.fileRenamingAllowed);
        dialog.setDirectoriesListing(this.permissions.directoriesListingAllowed);
        dialog.setDirectoryMaking(this.permissions.directoryMakingAllowed);
        dialog.setDirectoryDeletion(this.permissions.directoryDeletionAllowed);
        dialog.setSubdirectoriesBrowsing(this.permissions.subdirectoriesBrowsingAllowed);
        dialog.show({
            onSubmit: $.proxy(this._onSubmit$Permissions, this),
            onCancel: function(d) { d.destroy(); }
        });
    },

    onSubmit: function(dialog) {
        var file = this._createFile(dialog);
        file.accessPermissions = this.permissions;
        dialog.destroy();

        this.deferred.resolve(file);
    },

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

    _onSubmit$Permissions: function(dialog) {
        this.permissions = this._createAccessPermissions(dialog);
        dialog.destroy();
    },

    _createAccessPermissions: function (dialog) {
        return new jscape.AccessPermissions(dialog.getFileDownloading(),
                                            dialog.getFileUploading(),
                                            dialog.getFileOverwriting(),
                                            dialog.getFileDeletion(),
                                            dialog.getFileAppending(),
                                            dialog.getFileListing(),
                                            dialog.getFileRenaming(),
                                            dialog.getDirectoriesListing(),
                                            dialog.getDirectoryMaking(),
                                            dialog.getDirectoryDeletion(),
                                            dialog.getSubdirectoriesBrowsing());
    },

    _createFile: function(dialog) {
        return dialog.getReverseProxy() != null
               ? jscape.VirtualFile.remote(dialog.getPath(),
                                           this.permissions,
                                           dialog.getSecured(),
                                           dialog.getDenied(),
                                           dialog.getReverseProxy())
                : jscape.VirtualFile.local(dialog.getPath(),
                                           this.permissions,
                                           dialog.getSecured(),
                                           dialog.getDenied(),
                                           dialog.getIncludeInSearchIndex(),
                                           dialog.getRealPath(),
                                           dialog.getCreateIfNotFound(),
                                           new jscape.PgpEncryption(this.keyProvider, dialog.getPgpEncryptUploads()),
                                           new jscape.DataLossPrevention(this.dlp.rules, this.dlp.icapAccess, dialog.getDlpEnabled()));
    },

    _setupDialog: function () {
        var dialog = new jscape.vfs.VirtualPathDialog();
        dialog.setTitle(window.R.string.VFS_DIALOG_ADD_PATH_TITLE);
        dialog.setRealPath("");
        dialog.setCreateIfNotFound(true);
        dialog.setIncludeInSearchIndex(true);
        dialog.setSecured(false);
        dialog.setDenied(false);
        dialog.setPgpEncryptUploads(false);
        dialog.setDlpEnabled(false);
        dialog.show(this);

        this.managementService.getReverseProxyNames(this.domainName)
                .done(function (names) { dialog.setReverseProxies(names); });
        return dialog;
    }
});

/** @class */
jscape.vfs.EditPathController = Class.extend(
    /** @lends {jscape.vfs.EditPathController.prototype} */
{
    VARIABLES: ["installdir", "domain", "sessionid", "username", "group", "queryattr['name']"],

    permissions: null,
    keyProvider: null,
    dlp: null,
    deferred: null,

    /** @constructor */
    initialize: function() {
        this.pgpSettingsController = new jscape.vfs.PgpEncryptSettingsController();
        this.dlpSettingsController = new jscape.vfs.DlpSettingsController();
        this.variableController = new jscape.VariableController();
    },

    start: function(managementService, domainName, file) {
        this.managementService = managementService;
        this.domainName = domainName;
        this.permissions = file.accessPermissions;
        this.keyProvider = file.pgpEncryption ? file.pgpEncryption.keyProvider : null;
        this.dlp = file.dataLossPrevention ? file.dataLossPrevention : new jscape.DataLossPrevention();
        this.deferred = $.Deferred();
        this._setupDialog(file).show(this);
        return this.deferred.promise();
    },

    onSubmit: function (dialog) {
        var file = this._createFile(dialog);
        file.accessPermissions = this.permissions;
        dialog.destroy();

        this.deferred.resolve(file);
    },

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

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

    onSelectPath: function() {
        return new SelectPathController($.proxy(this.managementService.listFileSystem, this.managementService),
                                        $.proxy(this.managementService.createFileSystemDir, this.managementService))
                .selectDirectory().then(function (entry) { return entry.path; });
    },

    onSetPgpEncryptUploadsSettings: function() {
        this.pgpSettingsController.start(this.managementService, this.domainName, this.keyProvider)
                .done($.proxy(function(provider) {
                    this.keyProvider = provider;
                }, this));
    },

    onSetDlpSettings: function() {
        this.dlpSettingsController.start(this.managementService, this.domainName, this.dlp)
                .done($.proxy(function(dlp) { this.dlp = dlp; }, this));
    },

    onSetPermission: function () {
        var dialog = new jscape.vfs.VirtualPathPermissionsDialog();
        dialog.setFileDownloading(this.permissions.fileDownloadingAllowed);
        dialog.setFileUploading(this.permissions.fileUploadingAllowed);
        dialog.setFileOverwriting(this.permissions.fileOverwritingAllowed);
        dialog.setFileDeletion(this.permissions.fileDeletionAllowed);
        dialog.setFileAppending(this.permissions.fileAppendingAllowed);
        dialog.setFileListing(this.permissions.fileListingAllowed);
        dialog.setFileRenaming(this.permissions.fileRenamingAllowed);
        dialog.setDirectoriesListing(this.permissions.directoriesListingAllowed);
        dialog.setDirectoryMaking(this.permissions.directoryMakingAllowed);
        dialog.setDirectoryDeletion(this.permissions.directoryDeletionAllowed);
        dialog.setSubdirectoriesBrowsing(this.permissions.subdirectoriesBrowsingAllowed);
        dialog.show({
            onSubmit: $.proxy(this._onSubmit$Permissions, this),
            onCancel: function(dialog) { dialog.destroy(); }
        });
    },

    _onSubmit$Permissions: function(dialog) {
        this.permissions = this._createAccessPermissions(dialog);
        dialog.hide();
    },

    _createAccessPermissions: function(dialog) {
        return new jscape.AccessPermissions(dialog.getFileDownloading(),
                                            dialog.getFileUploading(),
                                            dialog.getFileOverwriting(),
                                            dialog.getFileDeletion(),
                                            dialog.getFileAppending(),
                                            dialog.getFileListing(),
                                            dialog.getFileRenaming(),
                                            dialog.getDirectoriesListing(),
                                            dialog.getDirectoryMaking(),
                                            dialog.getDirectoryDeletion(),
                                            dialog.getSubdirectoriesBrowsing());
    },

    _createFile: function (dialog) {
        return dialog.getReverseProxy() != null
                ? jscape.VirtualFile.remote(dialog.getPath(),
                                            this.permissions,
                                            dialog.getSecured(),
                                            dialog.getDenied(),
                                            dialog.getReverseProxy())
                : jscape.VirtualFile.local(dialog.getPath(),
                                           this.permissions,
                                           dialog.getSecured(),
                                           dialog.getDenied(),
                                           dialog.getIncludeInSearchIndex(),
                                           dialog.getRealPath(),
                                           dialog.getCreateIfNotFound(),
                                           new jscape.PgpEncryption(this.keyProvider, dialog.getPgpEncryptUploads()),
                                           new jscape.DataLossPrevention(this.dlp.rules, this.dlp.icapAccess, dialog.getDlpEnabled()));
    },

    _setupDialog: function (file) {
        var dialog = new jscape.vfs.VirtualPathDialog();
        dialog.setTitle(window.R.string.VFS_DIALOG_EDIT_PATH_TITLE.supplant({0: file.path}));
        dialog.setPath(file.path);
        if (file.realPath) {
            dialog.setRealPath(file.realPath);
            dialog.setCreateIfNotFound(file.createIfNotExists);
            dialog.setPgpEncryptUploads(file.pgpEncryption && file.pgpEncryption.enabled);
            dialog.setDlpEnabled(file.dataLossPrevention && file.dataLossPrevention.enabled);
        } else if (file.reverseProxy) {
            dialog.setPgpEncryptUploads(false);
            dialog.setDlpEnabled(false);
        }
        dialog.setIncludeInSearchIndex(file.indexable);
        dialog.setSecured(file.secured);
        dialog.setDenied(file.denied);

        this.managementService.getReverseProxyNames(this.domainName)
                .done(function (names) {
                          dialog.setReverseProxies(names);
                          if (file.reverseProxy) {
                              dialog.setReverseProxy(file.reverseProxy);
                          }
                      });
        return dialog;
    }
});

/** @class */
jscape.vfs.DeletePathController = Class.extend(
    /** @lends {jscape.vfs.DeletePathController.prototype} */
{
    start: function (files) {
        var text = $.map(files, function(file) { return file.path; }).join(", ");
        return jscape.ConfirmDialog.confirm(
                window.R.string.VFS_CONFIRM_DELETE_TITLE,
                window.R.string.VFS_CONFIRM_DELETE_MESSAGE.supplant({0: text.escapeXml()}),
                false);
    }
});

/** @class */
jscape.vfs.VirtualPathDialog = Class.extend(
    /** @lends {jscape.vfs.VirtualPathDialog.prototype} */
{
    currentField: null,

    /** @constructor */
    initialize: function() {
        this.dialog = $("#d-vfs-path").clone().attr("id", "");
        this.dialog.dialog({
            width: 600, 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=pathfields]", this.dialog);

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

        this.type = $("input[name=type]:radio", this.fieldset);
        this.type.on("change", $.proxy(this._adjustFieldState, this));
        this.typeRealPath = this.type.filter("[value=realpath]");
        this.typeReverseProxy = this.type.filter("[value=reverseproxy]");

        this.realPath = $("input[name=realpath]", this.fieldset).textbox({required: true, validType: "vfs_realpath_nonempty", missingMessage: window.R.string.VFS_ERROR_BAD_REAL_PATH, width: "60%"});
        this.browseButton = $("a[role=button][name=browse]", this.fieldset).linkbutton({onClick: $.proxy(this._onClick$BrowseButton, this)});

        this.reverseProxy = $("select[name=reverseproxy]", this.fieldset);
        this.reverseProxy.combobox({required: true, editable: true, limitToList: true, disabled: true, missingMessage: window.R.string.VFS_ERROR_BAD_REVERSE_PROXY, width: 300, panelHeight: "auto"});

        this.createIfNotFound = $("input[name=createifnotfound]", this.fieldset);
        this.includeInSearchIndex = $("input[name=includeinsearchindex]", this.fieldset);
        this.secured = $("input[name=secured]", this.fieldset);
        this.denied = $("input[name=denied]", this.fieldset);

        this.pgpEncryptUploads = $("input[name=pgpencryptupload]:checkbox", this.fieldset).on("change", $.proxy(this._adjustButtonsState, this));
        this.pgpSettingsButton = $("a[role=button][name=pgpsettings]", this.fieldset).linkbutton({disabled: true, onClick: $.proxy(this._onClick$PgpSettingsButton, this)});

        this.dlpEnabled = $("input[name=enabledlp]:checkbox", this.fieldset).on("change", $.proxy(this._adjustButtonsState, this));
        this.dlpSettingsButton = $("a[role=button][name=dlpsettings]", this.fieldset).linkbutton({disabled: true, onClick: $.proxy(this._onClick$DlpSettingsButton, this)});

        this.permissionsButton = $("a[role=button][name=permissions]", this.fieldset).linkbutton({onClick: $.proxy(this._onClick$PermissionsButton, this)});
        this.addVariableButton = $("a[role=button][name=addvar]", this.dialog).linkbutton({disabled: true, onClick: $.proxy(this._onClick$AddVariableButton, this)});

        this.fieldset.focusin($.proxy(function(e) {
            var field = $(e.target);
            if (field.is("input[type=text]") || field.is("textarea")) {
                this.addVariableButton.linkbutton("enable");
                this.currentField = field;
            } else {
                this.addVariableButton.linkbutton("disable");
                this.currentField = null;
            }
        }, this));
    },

    show: function (listener) {
        this.currentField = null;
        this.listener = listener;
        this.dialog.dialog("center");
        this.dialog.dialog("open");

        this._adjustFieldState();
        this._adjustButtonsState();
        this.fieldset.form("validate");
        this.path.textbox("textbox").focus();
    },

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

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

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

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

    setPath: function(value) {
        this.path.textbox("setValue", value);
        this.path.textbox("textbox").validatebox("options").validType = ["non_empty", "vfs_unique['" + value + "']"];
    },

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

    setRealPath: function(value) {
        this.typeRealPath.prop("checked", true).change();
        this.realPath.textbox("setValue", value);
    },

    setReverseProxies: function (values) {
        if (values && values.length) {
            this.reverseProxy.combobox("loadData", values);
            this.typeReverseProxy.prop("disabled", false);
        } else {
            this.reverseProxy.combobox("disable").combobox("disableValidation");
            this.typeReverseProxy.prop("disabled", true);
        }
    },

    getReverseProxy: function() {
        return this.typeReverseProxy.is(":checked") ? this.reverseProxy.combobox("getValue") : null;
    },

    setReverseProxy: function(value) {
        this.typeReverseProxy.prop("checked", true);
        this.reverseProxy.combobox("setValue", value).combobox("isValid");
        this._adjustFieldState();
    },

    getCreateIfNotFound: function() {
        return this.createIfNotFound.is(":checked");
    },

    setCreateIfNotFound: function(value) {
        this.createIfNotFound.prop("checked", !!value);
    },

    getIncludeInSearchIndex: function() {
        return this.includeInSearchIndex.is(":checked");
    },

    setIncludeInSearchIndex: function(value) {
        this.includeInSearchIndex.prop("checked", !!value);
    },

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

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

    getDenied: function() {
        return this.denied.is(":checked");
    },

    setDenied: function(value) {
        this.denied.prop("checked", !!value);
    },

    getPgpEncryptUploads: function() {
        return this.pgpEncryptUploads.is(":checked");
    },

    setPgpEncryptUploads: function(value) {
        this.pgpEncryptUploads.prop("checked", !!value);
        this._adjustButtonsState();
    },

    getDlpEnabled: function() {
        return this.dlpEnabled.is(":checked");
    },

    setDlpEnabled: function(value) {
        this.dlpEnabled.prop("checked", !!value);
        this._adjustButtonsState();
    },

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

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

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

    _onClick$PgpSettingsButton: function() {
        this.listener.onSetPgpEncryptUploadsSettings();
    },

    _onClick$DlpSettingsButton: function() {
        this.listener.onSetDlpSettings();
    },

    _onClick$PermissionsButton: function() {
        this.listener.onSetPermission();
    },

    _onClick$BrowseButton: function() {
        this.listener.onSelectPath()
                .done($.proxy(function (path) {
                          this.setRealPath(path);
                          this.realPath.textbox("textbox").select().focus();
                      }, this));
    },

    _onClick$AddVariableButton: function () {
        if (this.currentField != null && this.currentField.length && this.currentField.is(":not(:disabled)")) {
            this.addVariableButton.linkbutton("disable");
            this.listener.onAddVariable(this.currentField);
        }
    },

    _adjustFieldState: function () {
        var enabled = this.typeRealPath.is(":checked");

        this.realPath.textbox(enabled ? "enable" : "disable");
        this.browseButton.linkbutton(enabled ? "enable" : "disable");
        this.createIfNotFound.prop("disabled", !enabled);
        this.includeInSearchIndex.prop("disabled", !enabled);
        this.pgpEncryptUploads.prop("disabled", !enabled);
        this.pgpSettingsButton.linkbutton(enabled && this.getPgpEncryptUploads() ? "enable" : "disable");
        this.dlpEnabled.prop("disabled", !enabled);
        this.dlpSettingsButton.linkbutton(enabled && this.getDlpEnabled() ? "enable" : "disable");

        if (enabled) {
            this.realPath.textbox("enableValidation").textbox("validate");
            this.reverseProxy.combobox("disable").combobox("disableValidation");
        } else if (this.typeReverseProxy.is(":checked")) {
            this.realPath.textbox("disableValidation");
            this.reverseProxy.combobox("enable").combobox("enableValidation").combobox("isValid");
        }
    },

    _adjustButtonsState: function() {
        this.pgpSettingsButton.linkbutton(this.getPgpEncryptUploads() ? "enable" : "disable");
        this.dlpSettingsButton.linkbutton(this.getDlpEnabled() ? "enable" : "disable");
    }
});
jscape.vfs.VirtualPathDialog.LISTENER = {
    onSelectPath: $.noop,
    onSetPgpEncryptUploadsSettings: $.noop,
    onSetDlpSettings: $.noop,
    onSetPermission: $.noop,
    onSubmit: $.noop,
    onCancel: $.noop
};

/** @class */
jscape.vfs.VirtualPathPermissionsDialog = Class.extend(
    /** @lends {jscape.vfs.VirtualPathPermissionsDialog.prototype} */
{
    /** @constructor */
    initialize: function() {
        this.dialog = $("#d-vfs-path-permissions").clone().attr("id", new Date().getTime().toString(36)) ;
        this.dialog.dialog({
            width: 500, 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=permissionsfields]", this.dialog);

        this.fileDownload = $("input[name=filedownload]", this.fieldset);
        this.fileUpload = $("input[name=fileupload]", this.fieldset);
        this.fileOverwrite = $("input[name=fileoverwrite]", this.fieldset);
        this.fileAppend = $("input[name=fileappend]", this.fieldset);
        this.fileDelete = $("input[name=filedelete]", this.fieldset);
        this.fileRename = $("input[name=filerename]", this.fieldset);
        this.fileListing = $("input[name=filelisting]", this.fieldset);
        this.dirListing = $("input[name=dirlisting]", this.fieldset);
        this.dirCreate = $("input[name=dircreate]", this.fieldset);
        this.dirDelete = $("input[name=dirdelete]", this.fieldset);
        this.subdirBrowse = $("input[name=subdirbrowse]", this.fieldset);
    },

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

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

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

    getFileDownloading: function() {
        return this.fileDownload.is(":checked");
    },

    setFileDownloading: function(value) {
        this.fileDownload.prop("checked", !!value);
    },

    getFileUploading: function() {
        return this.fileUpload.is(":checked");
    },

    setFileUploading: function(value) {
        this.fileUpload.prop("checked", !!value);
    },

    getFileOverwriting: function() {
        return this.fileOverwrite.is(":checked");
    },

    setFileOverwriting: function(value) {
        this.fileOverwrite.prop("checked", !!value);
    },

    getFileAppending: function() {
        return this.fileAppend.is(":checked");
    },

    setFileAppending: function(value) {
        this.fileAppend.prop("checked", !!value);
    },

    getFileDeletion: function() {
        return this.fileDelete.is(":checked");
    },

    setFileDeletion: function(value) {
        this.fileDelete.prop("checked", !!value);
    },

    getFileRenaming: function() {
        return this.fileRename.is(":checked");
    },

    setFileRenaming: function(value) {
        this.fileRename.prop("checked", !!value);
    },

    getFileListing: function() {
        return this.fileListing.is(":checked");
    },

    setFileListing: function(value) {
        this.fileListing.prop("checked", !!value);
    },

    getDirectoriesListing: function() {
        return this.dirListing.is(":checked");
    },

    setDirectoriesListing: function(value) {
        this.dirListing.prop("checked", !!value);
    },

    getDirectoryMaking: function() {
        return this.dirCreate.is(":checked");
    },

    setDirectoryMaking: function(value) {
        this.dirCreate.prop("checked", !!value);
    },

    getDirectoryDeletion: function() {
        return this.dirDelete.is(":checked");
    },

    setDirectoryDeletion: function(value) {
        this.dirDelete.prop("checked", !!value);
    },

    getSubdirectoriesBrowsing: function() {
        return this.subdirBrowse.is(":checked");
    },

    setSubdirectoriesBrowsing: function(value) {
        this.subdirBrowse.prop("checked", !!value);
    },

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

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

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

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

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

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

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

    _createKeyProvider: function(dialog) {
        return dialog.getUserKeySelected()
                ? new jscape.PgpFileKeyProvider()
                : new jscape.ServerKeyProvider(dialog.getSystemKey());
    },

    _setupDialog: function (keyProvider) {
        var dialog = new jscape.vfs.PgpEncryptSettingsDialog();
        $.when(this.managementService.getPgpPublicKeys(),
               this.managementService.getPgpSecretKeys())
                .done(function (publicKeys, secretKeys) {
                          publicKeys = $.map(publicKeys, function (key) { return key.name; });
                          secretKeys = $.map(secretKeys, function (key) { return key.name; });

                          dialog.setSystemKeys(publicKeys.concat(secretKeys));

                          if (keyProvider instanceof jscape.ServerKeyProvider) {
                              dialog.setSystemKey(keyProvider.keyAlias);
                          } else {
                              dialog.setUserKeySelected(true);
                          }
                      });
        return dialog;
    }
});

/** @class */
jscape.vfs.PgpEncryptSettingsDialog = Class.extend(
    /** @lends {jscape.vfs.PgpEncryptSettingsDialog.prototype} */
{
    /** @constructor */
    initialize: function() {
        this.dialog = $("#d-vfs-pgpencrypt").clone().attr("id", new Date().getTime().toString(36));
        this.dialog.dialog({
            width: 600, 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=pgpencryptfields]", this.dialog);

        this.type = $("input[name=type]:radio", this.fieldset);
        this.typeUserKey = this.type.filter("[value=user]");
        this.typeSystemKey = this.type.filter("[value=system]");
        this.typeUserKey.on("change", $.proxy(this._adjustFieldState, this));
        this.typeSystemKey.on("change", $.proxy(this._adjustFieldState, this));

        this.systemKeys = $("select[name=systemkeys]", this.fieldset);
        this.systemKeys.combobox({
            required: true,
            editable: false,
            disabled: true,
            width: 230, panelHeight: "auto",
            formatter: function(rowData) { var t = rowData[$(this).combobox("options").textField]; return t.escapeXml(); }
        });
    },

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

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

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

    getUserKeySelected: function() {
        return this.typeUserKey.is(":checked");
    },

    setUserKeySelected: function(value) {
        this.typeUserKey.prop("checked", !!value);
    },

    setSystemKeys: function(values) {
        if (values && values.length) {
            this.systemKeys.combobox("loadData", values);
            this.typeSystemKey.prop("disabled", false);
        } else {
            this.systemKeys.combobox("disable").combobox("disableValidation");
            this.typeSystemKey.prop("disabled", true);
        }
    },

    getSystemKey: function() {
        return this.systemKeys.combobox("getValue");
    },

    setSystemKey: function(value) {
        this.typeSystemKey.prop("checked", true).change();
        this.systemKeys.combobox("clear").combobox("select", value);
        this._adjustFieldState();
    },

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

    _adjustFieldState: function () {
        if (this.typeUserKey.is(":checked")) {
            this.systemKeys.combobox("disable").combobox("disableValidation");
        } else if (this.typeSystemKey.is(":checked")) {
            this.systemKeys.combobox("enable").combobox("enableValidation").combobox("isValid");
        }
    }
});

/** @class */
jscape.vfs.DlpSettingsController = Class.extend(
    /** @lends {jscape.vfs.DlpSettingsController.prototype} */
{
    rules: null,
    deferred: null,

    /** @constructor */
    initialize: function() {
        this.rulesController = new jscape.vfs.DlpRulesController();
    },

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

    onDlpRules: function() {
        return this.rulesController.start(this.managementService, this.domainName, this._copyRules(this.rules))
                .done($.proxy(function(rules) { this.rules = rules; }, this));
    },

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

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

    _createDlp: function(dialog) {
        return new jscape.DataLossPrevention(this.rules, dialog.isUseIcap() ? dialog.getIcapAccess() : null);
    },

    _copyRules: function(rules) {
        return $.map(rules || [], jscape.DataLossPrevention.Entry.fromJSON);
    },

    _setupDialog: function(dlp) {
        var dialog = new jscape.vfs.DlpSettingsDialog();
        if (dlp.icapAccess) {
            dialog.setUseIcap();
            dialog.setIcapAccess(dlp.icapAccess);
        } else {
            dialog.setUseRules();
        }
        return dialog;
    }
});

/** @class */
jscape.vfs.DlpSettingsDialog = Class.extend(
    /** @lends {jscape.vfs.DlpSettingsDialog.prototype} */
{
    /** @constructor */
    initialize: function() {
        this.dialog = $("#d-vfs-dlpsettings").clone().attr("id", "");
        this.dialog.dialog({
            width: 500, 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=dlpsettingsfields]", this.dialog);

        this.type = $("input[name=type]:radio", this.fieldset);
        this.typeRules = this.type.filter("[value=rules]").change($.proxy(this._adjustFieldState, this));
        this.typeIcap= this.type.filter("[value=icap]").change($.proxy(this._adjustFieldState, this));

        this.icapAccess = $("select[name=icapaccess]", this.fieldset).combobox({required: true, editable: false, width: 150, panelHeight: "auto"});
        this.rulesButton = $("a[role=button][name=dlprules]", this.fieldset).linkbutton({onClick: $.proxy(this._onClick$DlpRulesButton, this)});
    },

    isUseIcap: function() {
        return this.typeIcap.is(":checked");
    },

    setUseIcap: function() {
        this.typeIcap.prop("checked", true).change();
    },

    isUseRules: function() {
        return this.typeRules.is(":checked");
    },

    setUseRules: function () {
        this.typeRules.prop("checked", true).change();
    },

    getIcapAccess: function() {
        return this.icapAccess.combobox("getValue");
    },

    setIcapAccess: function(access) {
        this.icapAccess.combobox("select", access);
    },

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

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

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

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

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

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

    _onClick$DlpRulesButton: function() {
        this.rulesButton.linkbutton("disable");
        this.listener.onDlpRules()
                .always($.proxy(function() { this.rulesButton.linkbutton("enable"); }, this));
    },

    _adjustFieldState: function() {
        if (this.isUseRules()) {
            this.rulesButton.linkbutton("enable");
            this.icapAccess.combobox("disable");
        } else {
            this.rulesButton.linkbutton("disable");
            this.icapAccess.combobox("enable").combobox("isValid");
        }
    }
});
jscape.vfs.DlpSettingsDialog.LISTENER = {
    onDlpRules: $.noop,
    onSubmit: $.noop,
    onCancel: $.noop
};

/** @class */
jscape.vfs.DlpRulesController = Class.extend(
    /** @lends {jscape.vfs.DlpRulesController.prototype} */
{
    entries: null,
    dlpRuleNames: null,
    deferred: null,

    /** @constructor */
    initialize: function() {
        this.deleteController = new jscape.vfs.DeleteDlpRuleController();
    },

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

        this._setupDialog(entries).show(this);

        this.managementService.getDlpRules(this.domainName)
                .done($.proxy(function (rules) {
                          this.dlpRuleNames = $.map(rules, function (rule) { return rule.name; });
                      }, this))
                .fail($.proxy(function () { this.dlpRuleNames = []; }, this));

        return this.deferred.promise();
    },

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

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

    onAddEntry: function(dialog) {
        var addDialog = new jscape.vfs.DlpRuleDialog();
        addDialog.setTitle(window.R.string.VFS_DLP_DIALOG_ADD_RULE_TITLE);
        addDialog.setDlpRules(this._filterDlpRules(this.dlpRuleNames));
        addDialog.setEnabled(true);
        addDialog.show({
            onSubmit: $.proxy(function(d) {
                var entry = this._createDlpEntry(d);
                d.destroy();
                this._entryAdded(entry, dialog);
            }, this),
            onCancel: function(d) { d.destroy(); }
        });
    },

    onEditEntry: function(entry, dialog) {
        var index = $.inArray(entry, this.entries);
        if (index != -1) {
            var editDialog = new jscape.vfs.DlpRuleDialog();
            editDialog.setTitle(window.R.string.VFS_DLP_DIALOG_EDIT_RULE_TITLE.supplant({0: entry.ruleName}));
            editDialog.setDlpRules(this._filterDlpRules(this.dlpRuleNames, entry.ruleName));
            editDialog.setRule(entry.ruleName);
            editDialog.setAccess(entry.access);
            editDialog.setEnabled(entry.enabled);
            editDialog.show({
                onSubmit: $.proxy(function(d) {
                    var entry = this._createDlpEntry(d);
                    d.destroy();
                    this._entryEdited(index, entry, dialog);
                }, this),
                onCancel: function(d) { d.destroy(); }
            });
        }
    },

    onDeleteEntry: function(entries, dialog) {
        this.deleteController.start(entries)
                .done($.proxy(this._entryDeleted, this, entries, dialog));
    },

    onEntryUp: function(entry, dialog) {
        var index = $.inArray(entry, this.entries);
        if (index > 0) {
            this.entries.splice(index - 1, 2, this.entries[index], this.entries[index - 1]);
            dialog.setEntries(this.entries);
            dialog.selectEntry(entry);
        }
    },

    onEntryDown: function(entry, dialog) {
        var index = $.inArray(entry, this.entries);
        if (index != -1 && index != this.entries.length - 1) {
            this.entries.splice(index, 2, this.entries[index + 1], this.entries[index]);
            dialog.setEntries(this.entries);
            dialog.selectEntry(entry);
        }
    },

    _createDlpEntry: function(dialog) {
        return new jscape.DataLossPrevention.Entry(dialog.getRule(), dialog.getAccess(), dialog.getEnabled());
    },

    _entryAdded: function(entry, dialog) {
        this.entries.push(entry);
        dialog.setEntries(this.entries);
        dialog.selectEntry(entry);
    },

    _entryEdited: function(index, entry, dialog) {
        this.entries[index] = entry;
        dialog.setEntries(this.entries);
        dialog.selectEntry(entry);
    },

    _entryDeleted: function (entries, dialog) {
        var index;
        while (entries.length) {
            index = $.inArray(entries.pop(), this.entries);
            if (index != -1) {
                this.entries.splice(index, 1);
            }
        }

        dialog.setEntries(this.entries);

        if (this.entries.length) {
            index = Math.max(0, Math.min(index, this.entries.length - 1));
            dialog.selectEntry(this.entries[index]);
        }
    },

    _setupDialog: function (entries) {
        var dialog = new jscape.vfs.DlpRulesDialog();
        dialog.setEntries(entries);
        return dialog;
    },

    _filterDlpRules: function(ruleNames, exclude) {
        var entryRuleNames = $.map(this.entries, function(entry) { return entry.ruleName; });
        return $.grep(ruleNames, function(ruleName) {
            return $.inArray(ruleName, entryRuleNames) == -1 || exclude === ruleName;
        });
    }
});


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

    /** @constructor */
    initialize: function() {
        this.dialog = $("#d-vfs-dlprules").clone().attr("id", "");
        this.dialog.dialog({
            width: 650, 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=dlprulesfields]", this.dialog);
        this.data = $("table[role=grid][aria-label=entries]", this.fieldset);
        this.data.datagrid({
            height: 220,
            fitColumns: true,
            singleSelect: true,
            onSelect: $.proxy(this._adjustRowSelection, this),
            onUnselect: $.proxy(this._adjustRowSelection, this),
            onLoadSuccess: $.proxy(this._adjustRowSelection, this),
            onDblClickRow: $.proxy(this._onClick$EditButton, this),
            columns: [[
                {field: "ruleName", title: $("thead th:nth-child(1)", this.data).text(), resizable: true, sortable: false, width: 100},
                {field: "enabled", title: $("thead th:nth-child(2)", this.data).text(), resizable: false, sortable: false, width: 40, styler: function(value) { return value ? "color:green" : "color:red"; }},
                {field: "access", title: $("thead th:nth-child(3)", this.data).text(), resizable: true, sortable: false, width: 130, formatter: function(value) { return window.R.string[("VFS_DLP_RULES_ACCESS_" + value).toUpperCase()] || ""; }}
            ]]
        });

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

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

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

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

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

    selectEntry: function(entry) {
        this.data.datagrid("selectRow", this.data.datagrid("getRowIndex", entry));
    },

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

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

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

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

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

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

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

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

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

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

        this.moveUpButton.linkbutton(index > 0 && index <= count - 1 ? "enable" : "disable");
        this.moveDownButton.linkbutton(index >= 0 && index < count - 1 ? "enable" : "disable");
        this.editButton.linkbutton(this.selection.length == 1 ? "enable" : "disable");
        this.deleteButton.linkbutton(this.selection.length !=0 ? "enable" : "disable");
    }
});
jscape.vfs.DlpRulesDialog.LISTENER = {
    onAddEntry: $.noop,
    onEditEntry: $.noop,
    onDeleteEntry: $.noop,
    onEntryUp: $.noop,
    onEntryDown: $.noop
};

/** @class */
jscape.vfs.DlpRuleDialog = Class.extend(
    /** @lends {jscape.vfs.DlpRuleDialog.prototype} */
{
    /** @constructor */
    initialize: function() {
        var id = "dlg_" + new Date().getTime().toString(36);
        var okBtnId = id + "_btn_ok";
        this.dialog = $("#d-vfs-dlp-rule").clone().attr("id", 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), disabled: true, id: okBtnId},
                {text: window.R.string.DIALOG_BUTTON_CANCEL || "Cancel", handler: $.proxy(this._onCancel, this)}
            ],
            onClose: $.proxy(function() {if (!this.closing) { this._onCancel(); }}, this)
        }).show();

        this.okButton = $("#" + okBtnId, this.dialog.dialog("dialog"));
        this.fieldset = $("fieldset[name=dlprulefields]", this.dialog);

        this.rule = $("select[name=rule]", this.fieldset).combobox({required: true, editable: false, width: 170, onLoadSuccess: $.proxy(this._adjustButtonsState, this)});
        this.access = $("select[name=access]", this.fieldset).combobox({required: true, editable: false, width: 120, panelHeight: "auto"});
        this.enabled = $("input[name=enabled]:checkbox", this.fieldset);
    },

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

         this._adjustButtonsState();
         this.fieldset.form("validate");
     },

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

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

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

    setDlpRules: function(values) {
        this.rule.combobox("loadData", values.sort());
        if (values.length) {
            this.rule.combobox("setValue", values[0]);
        }
    },

    getRule: function() {
        return this.rule.combobox("getValue");
    },

    setRule: function(value) {
        this.rule.combobox("setValue", value);
    },

    getAccess: function() {
        return this.access.combobox("getValue");
    },

    setAccess: function(value) {
        this.access.combobox("setValue", value);
    },

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

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

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

    _adjustButtonsState: function() {
        var enabled = this.fieldset.form("validate");
        this.okButton.linkbutton(enabled ? "enable" : "disable");
    }
});

/** @class */
jscape.vfs.DeleteDlpRuleController = Class.extend(
    /** @lends {jscape.vfs.DeleteDlpRuleController.prototype} */
{
    start: function (entries) {
        var text = $.map(entries, function(entries) { return entries.ruleName; }).join(", ");
        return jscape.ConfirmDialog.confirm(
                window.R.string.VFS_DLP_CONFIRM_DELETE_TITLE,
                window.R.string.VFS_DLP_CONFIRM_DELETE_MESSAGE.supplant({0: text.escapeXml()}),
                false);
    }
});