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

/** @class */
jscape.DirectoryMonitor = Class.extend(
    /** @lends {jscape.DirectoryMonitor.prototype} */
{
    /** @constructor */
    initialize: function (a, b, c, d, e, f, g, h, i, j) {
        this.name = a || "";
        this.tradingPartner = b || "";
        this.path = c || "";
        this.recursive = d || false;
        this.timeout = parseInt(e) || null;
        this.latency = parseInt(f) || null;
        this.owner = g || null;
        this.quota = h || null;
        this.events = i || new jscape.DirectoryMonitor.Event();
        this.tags = j || [];
    },

    toJSON: function() {
        var data = $.extend(this.events.toJSON(), this);
        data.events = undefined;
        return data;
    }
});
jscape.DirectoryMonitor.fromJSON = function(data) {
    return new jscape.DirectoryMonitor(data.name,
                                       data.tradingPartner,
                                       data.path,
                                       data.recursive,
                                       data.timeout,
                                       data.latency,
                                       data.owner,
                                       jscape.DirectoryQuota.fromJSON(data.quota),
                                       jscape.DirectoryMonitor.Event.fromJSON(data),
                                       data.tags);
};
/** @class */
jscape.DirectoryMonitor.Event = Class.extend(
    /** @lends {jscape.DirectoryMonitor.Event.prototype} */
{
    /** @const */
    MASK_ADD: 1 << 0,
    MASK_CHANGE: 1 << 1,
    MASK_DELETE: 1 << 2,

    /** @constructor */
    initialize: function(adding, changing, deleting, maxFileAge) {
        this.mask = 0;
        this.monitorAdd(!!adding);
        this.monitorChange(!!changing);
        this.monitorDelete(!!deleting);
        this.maxFileAge = parseInt(maxFileAge) || null;
    },

    monitorAdd: function(value) {
        return this._mask(value, this.MASK_ADD);
    },

    monitorChange: function(value) {
        return this._mask(value, this.MASK_CHANGE);
    },

    monitorDelete: function(value) {
        return this._mask(value, this.MASK_DELETE);
    },

    monitorFileAge: function(value) {
        if (!arguments.length) {
            return this.maxFileAge != null;
        }
        this.maxFileAge = parseInt(value) || null;
        return undefined;
    },

    _mask: function (value, flag) {
        if (value !== undefined) {
            this.mask |= value ? flag : 0;
            return undefined;
        }
        return (this.mask & flag) != 0;
    },

    toJSON: function() {
        return {
            monitorAdding: this.monitorAdd(),
            monitorChanging: this.monitorChange(),
            monitorDeleting: this.monitorDelete(),
            maxFileAge: this.maxFileAge
        }
    }
});
jscape.DirectoryMonitor.Event.fromJSON = function(data) {
    return new jscape.DirectoryMonitor.Event(data.monitorAdding,
                                             data.monitorChanging,
                                             data.monitorDeleting,
                                             data.maxFileAge);
};
/** @class */
jscape.DirectoryQuota = Class.extend(
    /** @lends {jscape.DirectoryQuota.prototype} */
{
    /** @constructor */
    initialize: function(a, b, c, d) {
        this.type = jscape.DirectoryQuota.Type.valueOf(a);
        this.value = parseInt(b) || 0;
        this.currentValue = parseInt(c) || 0;
        this.exceeded = d || false;
    }
});
jscape.DirectoryQuota.fromJSON = function(data) {
    return data ? new jscape.DirectoryQuota(data.type, data.value, data.currentValue, data.exceeded) : null;
};
jscape.DirectoryQuota.Type = {
    HARD: "HARD", SOFT: "SOFT",
    values: function() { return $.map(this, function(entry) { return typeof entry == "function" ? null : entry; }); },
    valueOf: function (value) { value = (value || "").toUpperCase(); return $.inArray(value, this.values()) != -1 ? value : jscape.DirectoryQuota.Type.SOFT; }
};

/** @class */
jscape.DirectoryMonitorServiceConfiguration = Class.extend(
    /** @lends {jscape.DirectoryMonitorServiceConfiguration.prototype} */
{
    /** @constructor */
    initialize: function(a) {
        this.maxThreadCount = parseInt(a) || 0;
    }
});
jscape.DirectoryMonitorServiceConfiguration.fromJSON = function(data) {
    return new jscape.DirectoryMonitorServiceConfiguration(data.maxThreadCount);
};

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

        this.monitorsController = new jscape.domain.DirectoryMonitorsController();
        this.monitorsController.onCreate(this.managementService, this.domainName);

        this.configController = new jscape.domain.DirectoryMonitorsConfigurationController();
        this.configController.onCreate(this.managementService, this.domainName);
    },

    onStart: function () {
        this.monitorsController.onStart();
        this.configController.onStart();
    },

    onPause: function () {
        if (this.configController.hasChanged()) {
            this._confirmAndApply([this.configController]);
        }
    },

    onResume: function() {
        this.monitorsController.onResume();
        this.configController.onResume();
    }
});

/** @class */
jscape.domain.DirectoryMonitorsController = jscape.ui.DatagridController.extend(
    /** @lends {jscape.DirectoryMonitorsController.prototype} */
{
    TRADING_PARTNER_PROTOCOLS: ["AFTP", "AmazonS3", "FTP", "Implicit FTPS", "Explicit FTPS", "SFTP", "SMB", "WebDAV", "WebDAV SSL"],

    view: null,

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

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

        this.addController = new jscape.domain.AddDirectoryMonitorController(this.TRADING_PARTNER_PROTOCOLS);
        this.editController = new jscape.domain.EditDirectoryMonitorController(this.TRADING_PARTNER_PROTOCOLS);
        this.deleteController = new jscape.domain.DeleteDirectoryMonitorController();
    },

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

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

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

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

    onEditMonitor: function(monitor) {
        var index = $.inArray(monitor, this.view.getMonitors(monitor));
        if (index != -1) {
            this.editController.start(this.managementService, this.domainName, monitor)
                    .done($.proxy(this._monitorEdited, this, index));
        }
    },

    onDeleteMonitor: function(monitors) {
        this.deleteController.start(this.managementService, this.domainName, monitors)
                .done($.proxy(this._monitorDeleted, this));
    },

    onRunMonitor: function(monitor) {
        this.managementService.runDirectoryMonitor(this.domainName, monitor.name);
    },

    _monitorAdded: function(monitor) {
        this._recordAdded(monitor);
    },

    _monitorEdited: function(index, monitor) {
        this._recordEdited(monitor);
    },

    _monitorDeleted: function (monitors) {
        this._recordDeleted(monitors);
    },

    _initValidators: function() {
        var v = new jscape.Validator();
        v.nonEmptyRule("dirmonitor_name_nonempty", window.R.string.DIR_MONITOR_ERROR_BAD_NAME);
        v.nonEmptyRule("dirmonitor_path_nonempty", window.R.string.DIR_MONITOR_ERROR_BAD_PATH);
        v.rule("dirmonitor_unique", $.proxy(this._monitorNotExists, this), window.R.string.DIR_MONITOR_ERROR_ALREADY_EXIST);
        v.rule("dirmonitor_filename", $.proxy(this._filenameValid, this), window.R.string.DIR_MONITOR_ERROR_BAD_FILENAME);
    },

    _monitorNotExists: function (name) {
        var values = $.map(this.view.getMonitors(), function(monitor) { return monitor.name; });
        return $.inArray(name, values) == -1;
    },

    _filenameValid: function(value) {
        return !/[\*\?\<\>\|"]/g.test(value);
    }
});

/** @class */
jscape.domain.DirectoryMonitorsView = jscape.ui.DatagridView.extend(
    /** @lends {jscape.domain.DirectoryMonitorsView.prototype} */
{
    /** @const */
    TIMEOUT_FACTOR: 1000,

    selection: null,

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

        this.sizeFormat = new jscape.SizeFormat();
        this.fieldset = $("fieldset[name=dirmonitorslistfields]");

        this.data = $("table[role=grid][aria-label=dirmonitors]", this.fieldset);
        this.data.datagrid({
            fit: true,
            fitColumns: true,
            singleSelect: true,
            pagination: true,
            search: true,
            remoteSearch: true,
            remoteSort: true,
            sortName: "name",
            idField: "name",
            columns: [[
                {field: "name", title: $("thead th:nth-child(1)", this.data).text(), sortable: true, width: "13%"},
                {field: "path", title: $("thead th:nth-child(2)", this.data).text(), width: "22%"},
                {field: "timeout", title: $("thead th:nth-child(3)", this.data).text(), width: "10%", align: "right", formatter: $.proxy(this._formatTimeout, this)},
                {field: "quota", title: $("thead th:nth-child(4)", this.data).text(), width: "15%", align: "right", formatter: $.proxy(this._formatQuota, this), styler: $.proxy(this._styleQuota, this)},
                {field: "owner", title: $("thead th:nth-child(5)", this.data).text(), sortable: true, width: "10%"},
                {field: "events", title: $("thead th:nth-child(6)", this.data).text(), width: "15%", formatter: $.proxy(this._formatEvents, this)},
                {field: "recursive", title: $("thead th:nth-child(7)", this.data).text(), width: "5%"},
                {field: "tags", title: $("thead th:nth-child(8)", this.data).text(), width: "10%", formatter: function(value) { return String($.isArray(value) ? value.join(", ") : value).escapeXml(); }}
            ]],
            onSelect: $.proxy(this._adjustRowSelection, this),
            onUnselect: $.proxy(this._adjustRowSelection, this),
            onDblClickRow: $.proxy(this._onClick$EditButton, this),
            loader: $.proxy(this._onLoad$Data, this),
            onBeforeLoad: function () { return !initializing; },
            onLoadSuccess: $.proxy(this._adjustRowSelection, this)
        });

        this.addButton = $("a[role=button][name=add]", this.fieldset).linkbutton({onClick: $.proxy(this._onClick$AddButton, this)});
        this.editButton = $("a[role=button][name=edit]", this.fieldset).linkbutton({disabled: true, onClick: $.proxy(this._onClick$EditButton, this)});
        this.runButton = $("a[role=button][name=run]", this.fieldset).linkbutton({disabled: true, onClick: $.proxy(this._onClick$RunButton, this)});
        this.deleteButton = $("a[role=button][name=delete]", this.fieldset).linkbutton({disabled: true, onClick: $.proxy(this._onClick$DeleteButton, this)});

        initializing = false;
    },

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

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

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

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

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

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

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

    _formatTimeout: function (timeout) {
        return timeout != null
                ? window.R.string.DIR_MONITOR_TEMPLATE_INTERVAL.supplant({0: timeout / this.TIMEOUT_FACTOR})
                : window.R.string.DIR_MONITOR_TEMPLATE_INTERVAL_NONE;
    },

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

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

    _formatEvents: function(events) {
        var t = [];
        events.monitorAdd() && t.push(window.R.string.DIR_MONITOR_EVENTS_ADDING);
        events.monitorChange() && t.push(window.R.string.DIR_MONITOR_EVENTS_CHANGING);
        events.monitorDelete() && t.push(window.R.string.DIR_MONITOR_EVENTS_DELETING);
        events.monitorFileAge() && t.push(window.R.string.DIR_MONITOR_EVENTS_FILE_AGING);
        return t.join(", ").escapeXml();
    },

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

    _adjustButtonsState: function () {
        var singleSelection = this.selection.length == 1;
        this.editButton.linkbutton(singleSelection ? "enable" : "disable");
        this.runButton.linkbutton(singleSelection ? "enable" : "disable");
        this.deleteButton.linkbutton(this.selection.length != 0 ? "enable" : "disable");
    }
});
jscape.domain.DirectoryMonitorsView.LISTENER = {
    onRefresh: $.noop,
    onAddMonitor: $.noop,
    onEditMonitor: $.noop,
    onDeleteMonitor: $.noop,
    onRunMonitor: $.noop
};

/** @class */
jscape.domain.AddDirectoryMonitorController = Class.extend(
    /** @lends {jscape.domain.AddDirectoryMonitorController.prototype} */
{
    /** @const */
    DEFAULT_TIMEOUT: 600 * 1000,
    DEFAULT_LATENCY: 5 * 1000,

    deferred: null,

    initialize: function(protocols) {
        this.protocols = protocols || [];
    },

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

    onSubmit: function(dialog) {
        var monitor = this._createMonitor(dialog);
        dialog.destroy();

        this.managementService.addDirectoryMonitor(this.domainName, monitor)
                .done($.proxy(function(monitor) { this.deferred.resolve(monitor); 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;
    },

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

    _setupDialog: function() {
        var dialog = new jscape.domain.AddDirectoryMonitorDialog();
        dialog.setRecursive(true);
        dialog.setTimeout(this.DEFAULT_TIMEOUT);
        dialog.setLatency(this.DEFAULT_LATENCY);
        dialog.setMonitorAdding(true);
        dialog.setMonitorChanging(true);
        dialog.setMonitorDeleting(true);
        this.managementService.getTradingPartnerNames(this.domainName, this.protocols).done(function (names) { dialog.setTradingPartners(names.sort()); });
        this.managementService.getAccountNames(this.domainName).done(function (owners) { dialog.setOwners(owners.sort()); });
        this.managementService.getDomainTags(this.domainName).done(function (tags) { dialog.setAvailableTags(tags); });
        return dialog;
    },

    _createMonitor: function (dialog) {
        return new jscape.DirectoryMonitor(dialog.getName(),
                                           dialog.getTradingPartner(),
                                           dialog.getPath(),
                                           dialog.getRecursive(),
                                           dialog.getTimeout(),
                                           dialog.getLatency(),
                                           dialog.getOwner(),
                                           this._createQuota(dialog.getQuotaType(), dialog.getQuota()),
                                           this._createEvents(dialog),
                                           dialog.getTags());
    },

    _createQuota: function(type, value) {
        return type != null && value != null ? new jscape.DirectoryQuota(type, value) : null;
    },

    _createEvents: function(dialog) {
        return new jscape.DirectoryMonitor.Event(dialog.getMonitorAdding(),
                                                 dialog.getMonitorChanging(),
                                                 dialog.getMonitorDeleting(),
                                                 dialog.getMaxFileAge());
    }
});

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

    initialize: function(protocols) {
        this.protocols = protocols || [];
    },

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

        this.managementService.getDirectoryMonitor(this.domainName, this.monitorName)
                .done($.proxy(function(monitor) { this._setupDialog(monitor).show(this); }, this))
                .fail($.proxy(function() { this.deferred.reject(); this.deferred = null; }, this));

        return this.deferred.promise();
    },

    onSubmit: function(dialog) {
        var monitor = this._createMonitor(dialog);
        dialog.destroy();

        this.managementService.setDirectoryMonitor(this.domainName, monitor.name, monitor)
                .done($.proxy(function() { this.deferred.resolve(monitor); }, this))
                .fail($.proxy(function() { this.deferred.reject(); this.deferred = null; }, this));
    },

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

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

    _setupDialog: function(monitor) {
        var dialog = new jscape.domain.EditDirectoryMonitorDialog();
        if (monitor) {
            dialog.setName(monitor.name);
            dialog.setPath(monitor.path);
            dialog.setRecursive(monitor.recursive);
            dialog.setTimeout(monitor.timeout);
            dialog.setLatency(monitor.latency);
            if (monitor.quota) {
                dialog.setQuota(monitor.quota.value);
                dialog.setQuotaType(monitor.quota.type);
            }
            dialog.setMonitorAdding(monitor.events.monitorAdd());
            dialog.setMonitorChanging(monitor.events.monitorChange());
            dialog.setMonitorDeleting(monitor.events.monitorDelete());
            dialog.setMaxFileAge(monitor.events.maxFileAge);
        }
        this.managementService.getTradingPartnerNames(this.domainName, this.protocols)
                .done(function(names) {
                                 dialog.setTradingPartners(names.sort());
                                 monitor && dialog.setTradingPartner(monitor.tradingPartner);
                              });
        this.managementService.getAccountNames(this.domainName)
                .done(function (owners) {
                          dialog.setOwners(owners.sort());
                          monitor && dialog.setOwner(monitor.owner);
                      });
        this.managementService.getDomainTags(this.domainName)
                .done(function (tags) {
                          dialog.setAvailableTags(tags);
                          monitor && dialog.setTags(monitor.tags);
                      });
        return dialog;
    },

    _createMonitor: function (dialog) {
        return new jscape.DirectoryMonitor(this.monitorName,
                                           dialog.getTradingPartner(),
                                           dialog.getPath(),
                                           dialog.getRecursive(),
                                           dialog.getTimeout(),
                                           dialog.getLatency(),
                                           dialog.getOwner(),
                                           this._createQuota(dialog.getQuotaType(), dialog.getQuota()),
                                           this._createEvents(dialog),
                                           dialog.getTags());
    },

    _createQuota: function(type, value) {
        return type != null && value != null ? new jscape.DirectoryQuota(type, value) : null;
    },

    _createEvents: function(dialog) {
        return new jscape.DirectoryMonitor.Event(dialog.getMonitorAdding(),
                                                 dialog.getMonitorChanging(),
                                                 dialog.getMonitorDeleting(),
                                                 dialog.getMaxFileAge());
    }
});

/** @class */
jscape.domain.DirectoryMonitorDialog = Class.extend(
    /** @lends {jscape.domain.DirectoryMonitor.prototype} */
{
    /** @const */
    TIMEOUT_FACTOR: 1000,
    LATENCY_FACTOR: 1000,
    QUOTA_FACTOR: 1024 * 1024,
    AGE_FACTOR: 24 * 60 * 60 * 1000,

    /** @constructor */
    initialize: function(dialog) {
        this.dialog = dialog.clone().attr("id", "");
        this.dialog.dialog({
            width: "60%", 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=dirmonitorsfields]", this.dialog);

        this.usePartner = $("input[name=usepartner]:checkbox", this.fieldset).change($.proxy(function() {
            var enabled = this.usePartner.is(":checked");
            this.partner.combobox(enabled ? "enable" : "disable");
            this.browseButton.linkbutton(!enabled ? "enable" : "disable");
        }, this));
        this.partner = $("select[name=partner]", this.fieldset).combobox({required: true, disabled: true, editable: true, limitToList: true, validType: "non_empty", missingMessage: window.R.string.DIR_MONITOR_ERROR_BAD_PARTNER, invalidMessage: window.R.string.DIR_MONITOR_ERROR_BAD_PARTNER, width: "40%", panelHeight: "auto", panelMaxHeight: 150});
        this.path = $("input[name=path]", this.fieldset).textbox({required: true, validType: ["dirmonitor_path_nonempty", "dirmonitor_filename"], missingMessage: window.R.string.DIR_MONITOR_ERROR_BAD_PATH, width: "60%"});
        this.browseButton = $("a[role=button][name=browse]", this.fieldset).linkbutton({onClick: $.proxy(this._onClick$BrowseButton, this)});

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

        this.timeoutEnabled = $("input[name=timeoutenabled]:checkbox", this.fieldset).change($.proxy(function() {
            var enable = this.timeoutEnabled.is(":checked");
            this.timeout.numberspinner(enable ? "enable" : "disable").numberspinner(enable ? "enableValidation" : "disableValidation");
        }, this));
        this.timeout = $("input[name=timeout]", this.fieldset).numberspinner({min: 1, max: 3600, value: 600, increment: 600, required: true, disabled: true, width: 60});

        this.latencyEnabled = $("input[name=latencyenabled]:checkbox", this.fieldset).change($.proxy(function() {
            var enable = this.latencyEnabled.is(":checked");
            this.latency.numberspinner(enable ? "enable" : "disable").numberspinner(enable ? "enableValidation" : "disableValidation");
        }, this));
        this.latency = $("input[name=latency]", this.fieldset).numberspinner({min: 1, max: 3600, value: 5, increment: 5, required: true, disabled: true, width: 60});

        this.ownedBy = $("input[name=ownedby]:checkbox", this.fieldset);
        this.ownedBy.change($.proxy(function() { this.owner.combobox(this.ownedBy.is(":checked:not(:disabled)") ? "enable" : "disable"); }, this));
        this.owner = $("select[name=owner]", this.fieldset).combobox({editable: true, limitToList: true, disabled: true, width: 120, panelHeight: "auto", panelMaxHeight: 150});

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

        this.quotaEnabled = $("input[name=quotaenabled]:checkbox", this.fieldset).change($.proxy(function() {
            var enable = this.quotaEnabled.is(":checked");
            this.quota.numberspinner(enable ? "enable" : "disable").numberspinner(enable ? "enableValidation" : "disableValidation");
            this.quotaType.combobox(enable ? "enable" : "disable").combobox(enable ? "enableValidation" : "disableValidation");
            this.quotaUnit.combobox(enable ? "enable" : "disable").combobox(enable ? "enableValidation" : "disableValidation");
        }, this));
        this.quota = $("input[name=quota]", this.fieldset).numberspinner({min: 1, max: 9999, value: 100, increment: 10, required: true, disabled: true, width: 90});
        this.quotaType = $("select[name=quotatype]", this.fieldset).combobox({required: true, editable: false, disabled: true, width: 60, panelHeight: "auto"});
        this.quotaUnit = $("select[name=quotaunit]", this.fieldset).combobox({required: true, editable: false, disabled: true, width: 60, panelHeight: "auto"});

        this.eventAdd = $("input[name=monitoradd]:checkbox", this.fieldset);
        this.eventChange = $("input[name=monitorchange]:checkbox", this.fieldset);
        this.eventDelete = $("input[name=monitordelete]:checkbox", this.fieldset);

        this.eventAge = $("input[name=maxfileageenabled]:checkbox", this.fieldset).change($.proxy(function() {
            var enable = this.eventAge.is(":checked");
            this.maxFileAge.numberspinner(enable ? "enable" : "disable").numberspinner(enable ? "enableValidation" : "disableValidation");
        }, this));
        this.maxFileAge = $("input[name=maxfileage]", this.fieldset).numberspinner({min: 1, max: 10000, value: 10, required: true, disabled: true, width: 60});
    },

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

        this.fieldset.form("validate");
        this.fieldset.find("input:first").focus();
        this.usePartner.change();
    },

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

    getTradingPartner: function() {
        return this.usePartner.is(":checked") ? this.partner.combobox("getValue") :  null;
    },

    setTradingPartner: function(value) {
        if (value) {
            this.partner.combobox("select", value);
        }
        this.usePartner.prop("checked", !!value).change();
    },

    setTradingPartners: function(values) {
        this.partner.combobox("loadData", values);
    },

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

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

    getRecursive: function() {
        return this.recursive.is(":checked");
    },

    setRecursive: function(value) {
        this.recursive.prop("checked", !!value);
    },

    getTimeout: function() {
        return this.timeoutEnabled.is(":checked") ? parseInt(this.timeout.numberspinner("getValue")) * this.TIMEOUT_FACTOR : null;
    },

    setTimeout: function(value) {
        this.timeoutEnabled.prop("checked", value != null).change();
        if (value != null) {
            this.timeout.numberspinner("setValue", value / this.TIMEOUT_FACTOR);
        }
    },

    getLatency: function() {
        return this.latencyEnabled.is(":checked") ? parseInt(this.latency.numberspinner("getValue")) * this.LATENCY_FACTOR : null;
    },

    setLatency: function(value) {
        this.latencyEnabled.prop("checked", value != null).change();
        if (value != null) {
            this.latency.numberspinner("setValue", value / this.LATENCY_FACTOR);
        }
    },

    getOwner: function () {
        return this.ownedBy.is(":checked:not(:disabled)") ? this.owner.combobox("getValue") : null;
    },

    setOwner: function (value) {
        var empty = this.owner.combobox("getData").length == 0;
        if (value != null && !empty) {
            this.owner.combobox("select", value);
        }
        this.ownedBy.prop("checked", value != null && !empty).change();
    },

    setOwners: function (values) {
        this.owner.combobox("loadData", values);
        this.ownedBy.prop("disabled", values.length == 0);
    },

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

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

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

    getQuota: function() {
        if (this.quotaEnabled.is(":checked")) {
            var factor = parseInt(this.quotaUnit.combobox("getValue"));
            return parseInt(this.quota.numberspinner("getValue")) * factor;
        }
    },

    setQuota: function(value) {
        value = parseInt(value);
        if (isNaN(value)) {
            this.quotaEnabled.prop("checked", false).change();
        } else {
            this.quotaEnabled.prop("checked", true).change();

            var factor = $.fn._unitValueFor(this.quotaUnit, value);
            this.quota.numberspinner("setValue", value / factor);
            this.quotaUnit.combobox("select", factor + "");
        }
    },

    getQuotaType: function() {
        return this.quotaType.combobox("getValue");
    },

    setQuotaType: function(value) {
        this.quotaType.combobox("select", value);
    },

    getMonitorAdding: function() {
        return this.eventAdd.is(":checked");
    },

    setMonitorAdding: function(value) {
        this.eventAdd.prop("checked", !!value);
    },

    getMonitorChanging: function() {
        return this.eventChange.is(":checked");
    },

    setMonitorChanging: function(value) {
        this.eventChange.prop("checked", !!value);
    },

    getMonitorDeleting: function() {
        return this.eventDelete.is(":checked");
    },

    setMonitorDeleting: function(value) {
        this.eventDelete.prop("checked", !!value);
    },

    getMaxFileAge: function() {
        return this.eventAge.is(":checked") ? this.maxFileAge.numberspinner("getValue") * this.AGE_FACTOR : null;
    },

    setMaxFileAge: function(value) {
        this.eventAge.prop("checked", value != null).change();
        if (value != null) {
            this.maxFileAge.numberspinner("setValue", value / this.AGE_FACTOR);
        }
    },

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

    _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;
    }
});
jscape.domain.DirectoryMonitorDialog.LISTENER = {
    onSubmit: $.noop,
    onCancel: $.noop,
    onSelectPath: $.noop
};

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

        this.name = $("input[name=name]", this.fieldset).textbox({required: true, validType: ["dirmonitor_name_nonempty", "dirmonitor_unique"], missingMessage: window.R.string.DIR_MONITOR_ERROR_BAD_NAME, width: "70%"});
    },

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

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

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

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

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

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

    _confirmDelete: function(monitors) {
        var text = $.map(monitors, function(monitor) { return monitor.name; }).join(", ");
        return jscape.ConfirmDialog.confirm(
                window.R.string.DIR_MONITOR_CONFIRM_DELETE_TITLE,
                window.R.string.DIR_MONITOR_CONFIRM_DELETE_MESSAGE.supplant({0: text}));
    },

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

/** @class */
jscape.domain.DirectoryMonitorsConfigurationController = Class.extend(
    /** @lends {jscape.domain.DirectoryMonitorsConfigurationController.prototype} */
{
    DEFAULT_CONFIG: new jscape.DirectoryMonitorServiceConfiguration(10),

    view: null,
    config: null,

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

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

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

    onResume: function() {
        return this.managementService.getDirectoryMonitorServiceConfiguration(this.domainName)
                .done($.proxy(function (config) { this.config = config; }, this))
                .fail($.proxy(function () { this.config = this._copyConfiguration(this.DEFAULT_CONFIG); }, this))
                .always($.proxy(function () { this._setupView(this.config); }, this));
    },

    onApply: function() {
        var config = this._createConfiguration();
        return this.managementService.setDirectoryMonitorServiceConfiguration(this.domainName, config)
                .done($.proxy(function () {
                          this.config = this._copyConfiguration(config);
                          this._fireApplySuccess();
                      }, this));
    },

    onDiscard: function() {
        var config = this.config;
        this.config = this._copyConfiguration(config);
        this._setupView(this.config);
    },

    _createConfiguration: function () {
        return new jscape.DirectoryMonitorServiceConfiguration(this.view.getMaxThreads());
    },

    _copyConfiguration: function(config) {
        return config != null ? $.extend(new jscape.DirectoryMonitorServiceConfiguration(), config) : null;
    },

    _setupView: function(config) {
        if (config && this.view) {
            this.view.setMaxThreads(config.maxThreadCount);
        }
    },

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

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

        this.maxThreads = $("input[name=maxthreads]", this.fieldset).numberspinner({min: 10, max: 100, editable: false, required: true, width: 60});

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

    getMaxThreads: function() {
        return parseInt(this.maxThreads.numberspinner("getValue"));
    },

    setMaxThreads: function(value) {
        if (parseInt(value)) {
            this.maxThreads.numberspinner("setValue", value).numberspinner("validate");
        }
    },

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

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

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