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

/** @class */
jscape.DropZoneData = Class.extend(
    /** @lends {jscape.DropZoneData.prototype} */
{
    /** @constructor */
    initialize: function(name, user, path, createDirectoryIfNotExists, overwriteFileIfNotExists, theme, owner, uri) {
        this.name = name || "";
        this.account = user || "";
        this.path = path || "";
        this.createDirectoryIfNotExists = !!createDirectoryIfNotExists;
        this.overwriteFileIfExists = !!overwriteFileIfNotExists;
        this.theme = theme || null;
        this.owner = owner || null;
        this.uri = uri || "";
    }
});
jscape.DropZoneData.fromJSON = function(data) {
    return data ? new jscape.DropZoneData(data.name, data.account, data.path, data.createDirectoryIfNotExists, data.overwriteFileIfExists, data.theme, data.owner, data.uri) : null;
};


/** @class */
jscape.account.DomainAdministrationModule = jscape.ApplicationModule.extend(
    /** @lends {jscape.account.DomainAdministrationModule.prototype} */
{
    userControlAllowed: false,
    themeControlAllowed: false,
    zoneControlAllowed: false,

    /** @constructor */
    initialize: function(userControlAllowed, themeControlAllowed, zoneControlAllowed) {
        this.userControlAllowed = !!userControlAllowed;
        this.themeControlAllowed = !!themeControlAllowed;
        this.zoneControlAllowed = !!zoneControlAllowed;
    },

    onCreate: function(username) {
        this._super.apply(this, arguments);

        if (this.userControlAllowed) {
            this.usersController = new jscape.account.UsersController(username);
        }
        if (this.themeControlAllowed) {
            this.themeController = new jscape.account.UrlBrandingController();
        }
        if (this.zoneControlAllowed) {
            this.zoneController = new jscape.account.DropZonesController();
        }
    },

    onStart: function() {
        this.usersController && this.usersController.start();
        this.themeController && this.themeController.start();
        this.zoneController && this.zoneController.start();
    },

    onResume: function() {
        this.usersController && this.usersController.onResume();
        this.themeController && this.themeController.onResume();
        this.zoneController && this.zoneController.onResume();
    }
});

/** @class */
jscape.account.DropZonesController = jscape.ui.DatagridController.extend(
    /** @lends {jscape.account.DropZonesController.prototype} */
{
    /** @constructor */
    initialize: function() {
        this.view = new jscape.account.DropZonesView();

        this.addController = new jscape.account.AddDropZoneController();
        this.editController = new jscape.account.EditDropZoneController();
        this.deleteController = new jscape.account.DeleteDropZoneController();

        this._initValidators();
    },

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

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

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

    onAddZone: function() {
        this.addController.start()
                .done($.proxy(this._dropZoneAdded, this));
    },

    onEditZone: function (zone) {
        this.editController.start(zone)
                .done($.proxy(this._dropZoneEdited, this));
    },

    onDeleteZone: function(zones) {
        this.deleteController.start(zones)
                .done($.proxy(this._dropZoneDeleted, this));
    },

    _dropZoneAdded: function() {
        this._recordAdded();
    },

    _dropZoneEdited: function(zone) {
        this._recordEdited(zone);
    },

    _dropZoneDeleted: function(zones) {
        this._recordDeleted(zones);
    },

    _initValidators: function() {
        var v = new jscape.Validator();
        v.rule("dropzone_name", $.proxy(this._dropZoneNameValid, this), window.R.string.DROP_ZONE_ERROR_BAD_NAME);
        v.rule("dropzone_unique", $.proxy(this._dropZoneNotExists, this), window.R.string.DROP_ZONE_ERROR_ALREADY_EXIST);
        v.nonEmptyRule("dropzone_path_nonempty", window.R.string.DROP_ZONE_ERROR_BAD_PATH);
        v.rule("dropzone_path", $.proxy(this._dropZonePathValid, this), window.R.string.DROP_ZONE_ERROR_BAD_PATH);
    },

    _dropZoneNameValid: function(name) {
        return /^\w+$/g.test(name);
    },

    _dropZoneNotExists: function(name) {
        var names = $.map(this.view.getDropZones(), function(zone) { return zone.name; });
        return $.inArray(name, names) == -1;
    },

    _dropZonePathValid: function(value) {
        return value != null && value.length != 0 && value.trim().charAt(0) == '/';
    }
});

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

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

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

        this.data = $("table[role=grid][aria-label=dropzones2]", this.fieldset);
        this.data.datagrid({
            fit: true,
            fitColumns: true,
            ctrlSelect: 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: 50},
                {field: "uri", title: $("thead th:nth-child(2)", this.data).text(), width: 90, searchable: false},
                {field: "theme", title: $("thead th:nth-child(3)", this.data).text(), width: 50},
                {field: "account", title: $("thead th:nth-child(4)", this.data).text(), sortable: true, width: 50},
                {field: "path", title: $("thead th:nth-child(5)", this.data).text(), width: 90},
                {field: "owner", title: $("thead th:nth-child(6)", this.data).text(), sortable: true, width: 50, sorter: function(a, b) { return a == b ? 0 : a == null || a < b ? -1 : 1; }}
            ]],
            onSelect: $.proxy(this._adjustState, this),
            onUnselect: $.proxy(this._adjustState, this),
            onDblClickRow: $.proxy(this._onClick$EditButton, this),
            loader: $.proxy(this._onLoad$Data, this),
            onBeforeLoad: function() { return !initializing; },
            onLoadSuccess: $.proxy(this._adjustState, this)
        });

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

        initializing = false;
    },

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

    show: function(listener) {
        this.listener = listener || jscape.account.DropZonesView.LISTENER;
        this.data.datagrid("resize");
        this._adjustState();
    },

    refresh: function() {
        this.data.datagrid("reload");
    },

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

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

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

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

    _adjustState: function() {
        this.selection = this.data.datagrid("getSelections");
        this.editButton.linkbutton(this.selection.length == 1 ? "enable" : "disable");
        this.deleteButton.linkbutton(this.selection.length != 0 ? "enable" : "disable");
    }
});
jscape.account.DropZonesView.LISTENER = {
    onRefresh: $.noop,
    onAddZone: $.noop,
    onEditZone: $.noop,
    onDeleteZone: $.noop
};

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

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

    onSubmit: function(dialog) {
        var data = this._createData(dialog);
        dialog.destroy();

        jscape.API.addDropZone(data)
                .done($.proxy(function(info) { this.deferred.resolve(info); this.deferred = null; }, this))
                .fail($.proxy(function() { this.deferred.reject(); this.deferred = null; }, this));
    },

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

    dropZoneUriFor: function(zoneName) {
        return zoneName && zoneName.trim().length
                ? jscape.API.dropZoneUri(zoneName)
                : $.Deferred().resolve("").promise();
    },

    _setupDialog: function() {
        var dialog = new jscape.account.AddDropZoneDialog();
        dialog.setCreatePathIfNotExists(true);
        dialog.setOverwriteFileIfExists(true);

        jscape.API.getUsernames()
                .done(function(names) { dialog.setUsers(names); })
                .fail(function() { dialog.setUsers([]); });
        jscape.API.getWebThemeNames()
                .done(function(names) { dialog.setWebThemes(names); })
                .fail(function() { dialog.setWebThemes([]); });

        return dialog;
    },

    _createData: function(dialog) {
        return new jscape.DropZoneData(dialog.getName(),
                                       dialog.getUser(),
                                       dialog.getPath(),
                                       dialog.getCreatePathIfNotExists(),
                                       dialog.getOverwriteFileIfExists(),
                                       dialog.getWebTheme());
    }
});

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

    start: function (zone) {
        this.zoneName = zone.name;
        this.deferred = $.Deferred();

        jscape.API.getDropZone(zone.name)
                .done($.proxy(function(data) { this._setupDialog(data).show(this); }, this))
                .fail($.proxy(function() { this.deferred.reject(); this.deferred = null; }, this));

        return this.deferred.promise();
    },

    onSubmit: function (dialog) {
        var data = this._createData(dialog);
        dialog.destroy();

        jscape.API.updateDropZone(this.zoneName, data)
                .done($.proxy(function(info) { this.deferred.resolve(info); this.deferred = null; }, this))
                .fail($.proxy(function() { this.deferred.reject(); this.deferred = null; }, this));
    },

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

    _setupDialog: function(data) {
        var dialog = new jscape.account.EditDropZoneDialog();
        if (data) {
            dialog.setName(data.name);
            dialog.setPath(data.path);
            dialog.setCreatePathIfNotExists(data.createDirectoryIfNotExists);
            dialog.setOverwriteFileIfExists(data.overwriteFileIfExists);
            dialog.setUri(data.uri);
        }

        jscape.API.getUsernames()
                .done(function (names) {
                          dialog.setUsers(names);
                          data && dialog.setUser(data.account);
                      })
                .fail(function() { dialog.setUsers([]); });
        jscape.API.getWebThemeNames()
                .done(function (names) {
                          dialog.setWebThemes(names);
                          data && dialog.setWebTheme(data.theme);
                      })
                .fail(function() { dialog.setWebThemes([]); });

        return dialog;
    },

    _createData: function(dialog) {
        return new jscape.DropZoneData(this.zoneName,
                                       dialog.getUser(),
                                       dialog.getPath(),
                                       dialog.getCreatePathIfNotExists(),
                                       dialog.getOverwriteFileIfExists(),
                                       dialog.getWebTheme());
    }
});

/** @class */
jscape.account.DropZoneDialog = Class.extend(
    /** @lends {jscape.account.DropZoneDialog.prototype} */
{
    /** @constructor */
    initialize: function(dialog) {
        this.dialog = dialog.clone().attr("id", "");
        this.dialog.dialog({
            width: 530, height: "auto",
            modal: true, resizable: false, closable: true, closed: true,
            buttons: [
                {text: window.R.string.DIALOG_BUTTON_OK, handler: $.proxy(this._onSubmit, this)},
                {text: window.R.string.DIALOG_BUTTON_CANCEL, handler: $.proxy(this._onCancel, this)}
            ],
            onClose: $.proxy(function () {if (!this.closing) { this._onCancel(); }}, this)
        }).show();

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

        this.user = $("select[name=account]", this.fieldset)
                .combobox({required: true, editable: false, missingMessage: window.R.string.DROP_ZONE_ERROR_BAD_ACCOUNT, width: 120})
                .combobox("autocomplete", true);

        this.path = $("input[name=path]", this.fieldset).textbox({required: true, validType: ["dropzone_path_nonempty", "dropzone_path"], missingMessage: window.R.string.DROP_ZONE_ERROR_BAD_PATH, width: "60%"});

        this.brandedBy = $("input[name=brandedby]:checkbox", this.fieldset);
        this.brandedBy.change($.proxy(function() {
            this.theme.combobox(this.brandedBy.is(":checked") ? "enable" : "disable");
        }, this));
        this.theme = $("select[name=theme]", this.fieldset);
        this.theme.combobox({
            editable: false, disabled: true,
            width: 120, panelHeight: "auto",
            onLoadSuccess: $.proxy(function(data) {
                if (data.length == 0) {
                    this.brandedBy.prop("disabled", true).prop("checked", false).change();
                }
            }, this)
        }).combobox("autocomplete", true);

        this.createPath = $("input[name=createpath]:checkbox", this.fieldset);
        this.overwrite = $("input[name=overwritefile]:checkbox", this.fieldset);
        this.uri = $("span[aria-label=zoneuri]", this.fieldset);
    },

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

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

    getUser: function() {
        return this.user.combobox("getValue");
    },

    setUser: function(value) {
        this.user.combobox("select", value);
    },

    setUsers: function(values) {
        this.user.combobox("loadData", values);
    },

    getWebTheme: function () {
        return this.brandedBy.is(":checked:not(:disabled)") ? this.theme.combobox("getValue") : null;
    },

    setWebTheme: function (value) {
        this.brandedBy.prop("checked", value != null).change();
        if (value != null) {
            this.theme.combobox("select", value);
        }
    },

    setWebThemes: function (values) {
        this.theme.combobox("loadData", values.sort());
    },

    getCreatePathIfNotExists: function() {
        return this.createPath.is(":checked");
    },

    setCreatePathIfNotExists: function(value) {
        this.createPath.prop("checked", !!value);
    },

    getOverwriteFileIfExists: function() {
        return this.overwrite.is(":checked");
    },

    setOverwriteFileIfExists: function(value) {
        this.overwrite.prop("checked", !!value);
    },

    setUri: function(value) {
        this.uri.text(value || "");
    },

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

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

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

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

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

    _closed: function () {
        return !!this.dialog.dialog("options").closed;
    }
});
jscape.account.DropZoneDialog.LISTENER = {
    onSubmit: $.noop,
    onCancel: $.noop
};

/** @class */
jscape.account.AddDropZoneDialog = jscape.account.DropZoneDialog.extend(
    /** @lends {jscape.account.AddDropZoneDialog.prototype} */
{
    /** @constructor */
    initialize: function() {
        this._super($("#d-dropzone-add"));

        this.name = $("input[name=name]", this.fieldset).textbox({required: true, validType: ["dropzone_name", "dropzone_unique"], missingMessage: window.R.string.DROP_ZONE_ERROR_BAD_NAME, onChange: $.proxy(this._adjustZoneUri, this), width: "60%"});
    },

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

    /** @override */
    show: function (listener) {
        this._super(listener || jscape.account.AddDropZoneDialog.LISTENER);
    },

    _adjustZoneUri: function () {
        if (this.name.textbox("isValid")) {
            this.listener.dropZoneUriFor(this.getName())
                    .done($.proxy(function (value) { this.setUri(value); }, this))
                    .fail($.proxy(function () { this.setUri(""); }, this))
        } else {
            this.setUri("");
        }
    }
});
jscape.account.AddDropZoneDialog.LISTENER = $.extend({
    dropZoneUriFor: $.noop
}, jscape.account.DropZoneDialog.LISTENER);

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

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

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

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

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

    _confirmDelete: function(zones) {
        var text = $.map(zones, function(zone) { return zone.name; }).join(", ");
        return jscape.ConfirmDialog.confirm(
                window.R.string.DROP_ZONE_CONFIRM_DELETE_TITLE,
                window.R.string.DROP_ZONE_CONFIRM_DELETE_MESSAGE.supplant({0: text.escapeXml()}),
                false);
    },

    _deleteConfirmed: function (zones) {
        $.when.apply(jQuery, $.map(zones, $.proxy(function(zone) { return jscape.API.deleteDropZone(zone.name); }, this)))
                .done($.proxy(function () { this.deferred.resolve(zones); this.deferred = null; }, this))
                .fail($.proxy(function() { this.deferred.reject(); this.deferred = null; }, this));
    }
});