/// <reference path="../../js/knockout.d.ts" />
/// <reference path="../../js/jquery.d.ts" />
/// <reference path="../../js/jqueryui.d.ts" />
/// <reference path="../../js/lodash-3.10.d.ts" />
/// <reference path="../../modules/actor-selector/actor-selector.ts" />
/// <reference path="../../ajax-wrapper/ajax-action-wrapper.d.ts" />
var AmePluginVisibilityModule = /** @class */ (function () {
    function AmePluginVisibilityModule(scriptData) {
        var _this = this;
        var _ = AmePluginVisibilityModule._;
        this.actorSelector = new AmeActorSelector(AmeActors, scriptData.isProVersion);
        //Wrap the selected actor in a computed observable so that it can be used with Knockout.
        var _selectedActor = ko.observable(this.actorSelector.selectedActor);
        this.selectedActor = ko.computed({
            read: function () {
                return _selectedActor();
            },
            write: function (newActor) {
                _this.actorSelector.setSelectedActor(newActor);
            }
        });
        this.actorSelector.onChange(function (newSelectedActor) {
            _selectedActor(newSelectedActor);
        });
        //Re-select the previously selected actor, or select "All" (null) by default.
        this.selectedActor(scriptData.selectedActor);
        this.canRoleManagePlugins = scriptData.canManagePlugins;
        this.isMultisite = scriptData.isMultisite;
        this.grantAccessByDefault = {};
        _.forEach(this.actorSelector.getVisibleActors(), function (actor) {
            _this.grantAccessByDefault[actor.id] = ko.observable(_.get(scriptData.settings.grantAccessByDefault, actor.id, _this.canManagePlugins(actor)));
        });
        this.plugins = _.map(scriptData.installedPlugins, function (plugin) {
            return new AmePlugin(plugin, _.get(scriptData.settings.plugins, plugin.fileName, {}), _this);
        });
        //Normally, the plugin list is sorted by the (real) plugin name. Re-sort taking custom names into account.
        this.plugins.sort(function (a, b) {
            return a.name().localeCompare(b.name());
        });
        this.privilegedActors = [this.actorSelector.getCurrentUserActor()];
        if (this.isMultisite) {
            this.privilegedActors.push(AmeActors.getSuperAdmin());
        }
        this.areNewPluginsVisible = ko.computed({
            read: function () {
                if (_this.selectedActor() !== null) {
                    var canSeePluginsByDefault = _this.getGrantAccessByDefault(_this.selectedActor());
                    return canSeePluginsByDefault();
                }
                return _.every(_this.actorSelector.getVisibleActors(), function (actor) {
                    //Only consider roles than can manage plugins.
                    if (!_this.canManagePlugins(actor)) {
                        return true;
                    }
                    var canSeePluginsByDefault = _this.getGrantAccessByDefault(actor.getId());
                    return canSeePluginsByDefault();
                });
            },
            write: function (isChecked) {
                if (_this.selectedActor() !== null) {
                    var canSeePluginsByDefault = _this.getGrantAccessByDefault(_this.selectedActor());
                    canSeePluginsByDefault(isChecked);
                    return;
                }
                //Update everyone except the current user and Super Admin.
                _.forEach(_this.actorSelector.getVisibleActors(), function (actor) {
                    var isAllowed = _this.getGrantAccessByDefault(actor.getId());
                    if (!_this.canManagePlugins(actor)) {
                        isAllowed(false);
                    }
                    else if (_.includes(_this.privilegedActors, actor)) {
                        isAllowed(true);
                    }
                    else {
                        isAllowed(isChecked);
                    }
                });
            }
        });
        this.areAllPluginsChecked = ko.computed({
            read: function () {
                return _.every(_this.plugins, function (plugin) {
                    return _this.isPluginVisible(plugin);
                }) && _this.areNewPluginsVisible();
            },
            write: function (isChecked) {
                _this.areNewPluginsVisible(isChecked);
                _.forEach(_this.plugins, function (plugin) {
                    _this.setPluginVisibility(plugin, isChecked);
                });
            }
        });
        //This observable will be populated when saving changes.
        this.settingsData = ko.observable('');
    }
    AmePluginVisibilityModule.prototype.isPluginVisible = function (plugin) {
        var actorId = this.selectedActor();
        if (actorId === null) {
            return plugin.isVisibleByDefault();
        }
        else {
            var canSeePluginsByDefault = this.getGrantAccessByDefault(actorId), isVisible = plugin.getGrantObservable(actorId, plugin.isVisibleByDefault() && canSeePluginsByDefault());
            return isVisible();
        }
    };
    AmePluginVisibilityModule.prototype.setPluginVisibility = function (plugin, isVisible) {
        var _this = this;
        var selectedActor = this.selectedActor();
        if (selectedActor === null) {
            plugin.isVisibleByDefault(isVisible);
            //Show/hide from everyone except the current user and Super Admin.
            //However, don't enable plugins for roles that can't access the "Plugins" page in the first place.
            var _1 = AmePluginVisibilityModule._;
            _1.forEach(this.actorSelector.getVisibleActors(), function (actor) {
                var allowAccess = plugin.getGrantObservable(actor.id, isVisible);
                if (!_this.canManagePlugins(actor)) {
                    allowAccess(false);
                }
                else if (_1.includes(_this.privilegedActors, actor)) {
                    allowAccess(true);
                }
                else {
                    allowAccess(isVisible);
                }
            });
        }
        else {
            //Show/hide from the selected role or user.
            var allowAccess = plugin.getGrantObservable(selectedActor, isVisible);
            allowAccess(isVisible);
        }
    };
    AmePluginVisibilityModule.prototype.canManagePlugins = function (actor) {
        var _this = this;
        var _ = AmePluginVisibilityModule._;
        if ((actor instanceof AmeRole) && _.has(this.canRoleManagePlugins, actor.name)) {
            return this.canRoleManagePlugins[actor.name];
        }
        if (actor instanceof AmeSuperAdmin) {
            return true;
        }
        if (actor instanceof AmeUser) {
            //Can any of the user's roles manage plugins?
            var result_1 = false;
            _.forEach(actor.roles, function (roleId) {
                if (_.get(_this.canRoleManagePlugins, roleId, false)) {
                    result_1 = true;
                    return false;
                }
            });
            return (result_1 || AmeActors.hasCap(actor.id, 'activate_plugins'));
        }
        return false;
    };
    AmePluginVisibilityModule.prototype.getGrantAccessByDefault = function (actorId) {
        if (!this.grantAccessByDefault.hasOwnProperty(actorId)) {
            this.grantAccessByDefault[actorId] = ko.observable(this.canManagePlugins(AmeActors.getActor(actorId)));
        }
        return this.grantAccessByDefault[actorId];
    };
    AmePluginVisibilityModule.prototype.getSettings = function () {
        var _this = this;
        var _ = AmePluginVisibilityModule._;
        var result = {};
        result.grantAccessByDefault = _.mapValues(this.grantAccessByDefault, function (allow) {
            return allow();
        });
        result.plugins = {};
        _.forEach(this.plugins, function (plugin) {
            result.plugins[plugin.fileName] = {
                isVisibleByDefault: plugin.isVisibleByDefault(),
                grantAccess: _.mapValues(plugin.grantAccess, function (allow) {
                    return allow();
                })
            };
            //Filter out grants that match the default settings.
            result.plugins[plugin.fileName].grantAccess = _.pick(result.plugins[plugin.fileName].grantAccess, function (allowed, actorId) {
                var defaultState = _this.getGrantAccessByDefault(actorId)() && plugin.isVisibleByDefault();
                return (allowed !== defaultState);
            });
            //Don't store the "grantAccess" map if it's empty.
            if (_.isEmpty(result.plugins[plugin.fileName].grantAccess)) {
                delete result.plugins[plugin.fileName].grantAccess;
            }
            //All plugins are visible by default, so it's not necessary to store this flag if it's TRUE.
            if (result.plugins[plugin.fileName].isVisibleByDefault) {
                delete result.plugins[plugin.fileName].isVisibleByDefault;
            }
            for (var i = 0; i < AmePlugin.editablePropertyNames.length; i++) {
                var key = AmePlugin.editablePropertyNames[i], upperKey = key.substring(0, 1).toUpperCase() + key.substring(1), value = plugin.customProperties[key]();
                if (value !== '') {
                    result.plugins[plugin.fileName]['custom' + upperKey] = value;
                }
            }
        });
        return result;
    };
    //noinspection JSUnusedGlobalSymbols Used in KO template.
    AmePluginVisibilityModule.prototype.saveChanges = function () {
        var settings = this.getSettings();
        //Remove settings associated with roles and users that no longer exist or are not visible.
        var _ = AmePluginVisibilityModule._, visibleActorIds = _.pluck(this.actorSelector.getVisibleActors(), 'id');
        _.forEach(settings.plugins, function (plugin) {
            if (plugin.grantAccess) {
                plugin.grantAccess = _.pick(plugin.grantAccess, visibleActorIds);
            }
        });
        //Remove plugins that don't have any custom settings.
        settings.plugins = _.pick(settings.plugins, function (value) {
            return !_.isEmpty(value);
        });
        //Populate form field(s).
        this.settingsData(jQuery.toJSON(settings));
        return true;
    };
    AmePluginVisibilityModule._ = wsAmeLodash;
    return AmePluginVisibilityModule;
}());
var AmePlugin = /** @class */ (function () {
    function AmePlugin(details, settings, module) {
        var _this = this;
        this.defaultProperties = {};
        this.customProperties = {};
        this.editableProperties = {};
        var _ = AmePluginVisibilityModule._;
        for (var i = 0; i < AmePlugin.editablePropertyNames.length; i++) {
            var key = AmePlugin.editablePropertyNames[i], upperKey = key.substring(0, 1).toUpperCase() + key.substring(1);
            this.defaultProperties[key] = ko.observable(_.get(details, key, ''));
            this.customProperties[key] = ko.observable(_.get(settings, 'custom' + upperKey, ''));
            this.editableProperties[key] = ko.observable(this.defaultProperties[key]());
        }
        this.name = ko.computed(function () {
            var value = _this.customProperties['name']();
            if (value === '') {
                value = _this.defaultProperties['name']();
            }
            return AmePlugin.stripAllTags(value);
        });
        this.description = ko.computed(function () {
            var value = _this.customProperties['description']();
            if (value === '') {
                value = _this.defaultProperties['description']();
            }
            return AmePlugin.stripAllTags(value);
        });
        this.fileName = details.fileName;
        this.isActive = details.isActive;
        this.isBeingEdited = ko.observable(false);
        this.isVisibleByDefault = ko.observable(_.get(settings, 'isVisibleByDefault', true));
        var emptyGrant = {};
        this.grantAccess = _.mapValues(_.get(settings, 'grantAccess', emptyGrant), function (hasAccess) {
            return ko.observable(hasAccess);
        });
        this.isChecked = ko.computed({
            read: function () {
                return module.isPluginVisible(_this);
            },
            write: function (isVisible) {
                return module.setPluginVisibility(_this, isVisible);
            }
        });
    }
    AmePlugin.prototype.getGrantObservable = function (actorId, defaultValue) {
        if (defaultValue === void 0) { defaultValue = true; }
        if (!this.grantAccess.hasOwnProperty(actorId)) {
            this.grantAccess[actorId] = ko.observable(defaultValue);
        }
        return this.grantAccess[actorId];
    };
    //noinspection JSUnusedGlobalSymbols Used in KO template.
    AmePlugin.prototype.openInlineEditor = function () {
        for (var i = 0; i < AmePlugin.editablePropertyNames.length; i++) {
            var key = AmePlugin.editablePropertyNames[i], customValue = this.customProperties[key]();
            this.editableProperties[key](customValue === '' ? this.defaultProperties[key]() : customValue);
        }
        this.isBeingEdited(true);
    };
    //noinspection JSUnusedGlobalSymbols Used in KO template.
    AmePlugin.prototype.cancelEdit = function () {
        this.isBeingEdited(false);
    };
    //noinspection JSUnusedGlobalSymbols Used in KO template.
    AmePlugin.prototype.confirmEdit = function () {
        for (var i = 0; i < AmePlugin.editablePropertyNames.length; i++) {
            var key = AmePlugin.editablePropertyNames[i], customValue = this.editableProperties[key]();
            if (customValue === this.defaultProperties[key]()) {
                customValue = '';
            }
            this.customProperties[key](customValue);
        }
        this.isBeingEdited(false);
    };
    //noinspection JSUnusedGlobalSymbols Used in KO template.
    AmePlugin.prototype.resetNameAndDescription = function () {
        for (var i = 0; i < AmePlugin.editablePropertyNames.length; i++) {
            var key = AmePlugin.editablePropertyNames[i];
            this.customProperties[key]('');
        }
        this.isBeingEdited(false);
    };
    AmePlugin.stripAllTags = function (input) {
        //Based on: http://phpjs.org/functions/strip_tags/
        var tags = /<\/?([a-z][a-z0-9]*)\b[^>]*>/gi, commentsAndPhpTags = /<!--[\s\S]*?-->|<\?(?:php)?[\s\S]*?\?>/gi;
        return input.replace(commentsAndPhpTags, '').replace(tags, '');
    };
    AmePlugin.editablePropertyNames = ['name', 'description', 'author', 'siteUrl', 'version'];
    return AmePlugin;
}());
jQuery(function ($) {
    amePluginVisibility = new AmePluginVisibilityModule(wsPluginVisibilityData);
    ko.applyBindings(amePluginVisibility, document.getElementById('ame-plugin-visibility-editor'));
    //Permanently dismiss the usage hint via AJAX.
    $('#ame-pv-usage-notice').on('click', '.notice-dismiss', function () {
        AjawV1.getAction('ws_ame_dismiss_pv_usage_notice').request();
    });
});
