"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ExtensionProvider = exports.NameMigrationOperation = exports.TypeMigrationOperation = void 0;
const tslib_1 = require("tslib");
const core_1 = require("@loopback/core");
const _ = tslib_1.__importStar(require("lodash"));
const lodash_1 = require("lodash");
const application_service_1 = require("../services/application.service");
const object_node_service_1 = require("../services/object-node/object-node.service");
const object_tree_service_1 = require("../services/object-tree/object-tree.service");
const object_type_service_1 = require("../services/object-type.service");
const access_rights_service_1 = require("./../services/access-rights/access-rights.service");
class TypeMigrationOperation {
}
exports.TypeMigrationOperation = TypeMigrationOperation;
class NameMigrationOperation {
}
exports.NameMigrationOperation = NameMigrationOperation;
class ExtensionProvider {
    constructor(name, app) {
        this.name = name;
        this.app = app;
        this.requiredProviders = [];
        this._objectTypes = {};
        this.objectTypes = [];
        this.objectSubTypes = [];
        this.objectTrees = {};
        this.services = [];
        this.models = [];
        this.repositories = [];
        this.interceptorsPrepend = [];
        this.interceptorsAppend = [];
        this.controllers = [];
        this.dataSources = [];
        this.migrations = [];
        this._forcedAccessRightsByObjectType = {};
        console.log('Adding ' + this.name + '.');
    }
    async setContext(appCtx) {
        this.appCtx = appCtx;
        this.objectTreeService = await this.app.getService(object_tree_service_1.ObjectTreeService);
        this.objectNodeService = await this.app.getService(object_node_service_1.ObjectNodeService);
        this.objectTypeService = await this.app.getService(object_type_service_1.ObjectTypeService);
        this.ctx = appCtx.getExtensionContext(this.name);
    }
    async beforeBoot() {
        console.log('Initializing ' + this.name + '.');
        for (const dataSource of this.dataSources) {
            let name = dataSource.name;
            if (name.startsWith('datasources.')) {
                name = name.substr('datasources.'.length);
            }
            this.app
                .dataSource(dataSource.dataSource, name)
                .inScope(core_1.BindingScope.SINGLETON);
        }
        for (const model of this.models) {
            this.app.model(model);
        }
        for (const repository of this.repositories) {
            this.app.repository(repository.repoClass, repository.nameOrOptions);
        }
        for (const serviceProvider of this.services) {
            this.app.service(serviceProvider.cls, serviceProvider.nameOrOptions
                ? serviceProvider.nameOrOptions
                : { defaultScope: core_1.BindingScope.SINGLETON });
            await this.app.getService(serviceProvider.cls);
            console.log(serviceProvider.cls.name + ' started !');
        }
        for (const interceptorProvider of this.interceptorsAppend) {
            this.app.addInterceptor(this.name, interceptorProvider);
            const binding = this.app.getBinding(core_1.ContextBindings.GLOBAL_INTERCEPTOR_ORDERED_GROUPS);
            const interceptor = binding.getValue(this.app);
            interceptor.push(interceptorProvider.id);
            binding.to(interceptor);
            console.log('Interceptors list updated', this.app
                .getBinding(core_1.ContextBindings.GLOBAL_INTERCEPTOR_ORDERED_GROUPS)
                .getValue(this.app));
        }
        for (const interceptorProvider of this.interceptorsPrepend) {
            this.app.addInterceptor(this.name, interceptorProvider);
            const binding = this.app.getBinding(core_1.ContextBindings.GLOBAL_INTERCEPTOR_ORDERED_GROUPS);
            const interceptor = binding.getValue(this.app);
            interceptor.unshift(interceptorProvider.id);
            binding.to(interceptor);
            console.log('Interceptors list updated', this.app
                .getBinding(core_1.ContextBindings.GLOBAL_INTERCEPTOR_ORDERED_GROUPS)
                .getValue(this.app));
        }
        for (const controller of this.controllers) {
            this.app.addController(this.name, controller);
        }
        for (const objectType of this.objectTypes) {
            await this.addType(objectType);
        }
        for (const subType of this.objectSubTypes) {
            await this.addSubType(subType);
        }
    }
    async addType(objectType) {
        const typeField = lodash_1.camelCase(objectType.name);
        if (!this.ctx.types[typeField]) {
            this.ctx.types[typeField] = new application_service_1.ExpectedValue();
        }
        await this.ctx.types[typeField].getOrSetValue(async () => {
            if ('forcedAccessRights' in objectType) {
                this._forcedAccessRightsByObjectType[objectType.name] = objectType.forcedAccessRights;
                delete objectType.forcedAccessRights;
            }
            return this.objectTypeService.registerApplicationType(objectType);
        });
    }
    async addSubType(subType) {
        const typeName = _.isString(subType.typeName)
            ? subType.typeName
            : subType.typeName();
        const subTypeName = _.isString(subType.subTypeName)
            ? subType.subTypeName
            : subType.subTypeName();
        if (!subType.name) {
            subType.name = subTypeName;
        }
        await this.objectTypeService.getOrCreateObjectSubType(typeName, subTypeName, _.pick(subType, [
            'name',
            'title',
            'acl',
            'owner',
            'namespace',
            'tree',
            'min',
            'max',
            'exclusions',
            'mandatories',
        ]));
    }
    async migrateBeforeBoot() {
        for (const migration of this.migrations) {
            if ('newType' in migration) {
                await this.objectNodeService.migrateType(migration.parentType, migration.previousType, migration.newType);
            }
            else if ('newName' in migration) {
                await this.objectNodeService.migrateName(migration.previousName, migration.newName, migration.type, migration.parentType);
            }
        }
    }
    async boot() {
        console.log('Booting ' + this.name + '.');
        const accessRightsService = await this.app.getService(access_rights_service_1.AccessRightsService);
        if (accessRightsService) {
            for (const objectTypeId in this._forcedAccessRightsByObjectType) {
                accessRightsService.addForcedAccessRightsForObjectType(objectTypeId, this._forcedAccessRightsByObjectType[objectTypeId]);
            }
        }
        for (const nodeField in this.objectTrees) {
            if (!this.ctx.nodes[nodeField]) {
                this.ctx.nodes[nodeField] = new application_service_1.ExpectedValue();
            }
            await this.ctx.nodes[nodeField].getOrSetValue(async () => {
                return this.objectTreeService.registerApplicationTree(this.objectTrees[nodeField].parentNode(), this.objectTrees[nodeField].treeNodeName, this.objectTrees[nodeField].treeNodeTypeId, this.objectTrees[nodeField].tree, !!this.objectTrees[nodeField].reset);
            });
        }
        this.ctx.resolve();
    }
}
exports.ExtensionProvider = ExtensionProvider;
//# sourceMappingURL=extension.provider.js.map