"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ObjectNodeDefinitionService = exports.OBJECT_NODE_SCHEMA = void 0;
const tslib_1 = require("tslib");
const core_1 = require("@loopback/core");
const lodash_1 = require("lodash");
const entity_name_1 = require("./../../models/entity-name");
const application_service_1 = require("./../application.service");
const object_node_service_1 = require("./../object-node/object-node.service");
const object_type_service_1 = require("./../object-type.service");
const entity_definition_cont_1 = require("./entity-definition.cont");
const entity_definition_service_1 = require("./entity-definition.service");
exports.OBJECT_NODE_SCHEMA = {
    properties: {
        title: {
            type: 'string',
            title: 'Displayed name',
            default: '',
            description: 'The displayed name is the default label to display this object.',
        },
        name: {
            type: 'string',
            // tslint:disable-next-line: object-literal-sort-keys
            title: 'Name',
            description: 'The name is used as an identifier, it is not recommended t change its value. All none allowed characters will be replaced (others than alphanumeric, -, _ or .).',
            default: '',
        },
    },
};
let ObjectNodeDefinitionService = class ObjectNodeDefinitionService {
    constructor(objectTypeService, objectNodeService, entityDefinitionService) {
        this.objectTypeService = objectTypeService;
        this.objectNodeService = objectNodeService;
        this.entityDefinitionService = entityDefinitionService;
        this.providerId = entity_definition_cont_1.ENTITY_DEFINITION_PROVIDER;
        this.serviceId = ObjectNodeDefinitionService.name;
        this.entityDefinitionService.registerEntityDefinitionService(entity_name_1.EntityName.objectNode, this);
    }
    async completeReturnedEntity(entity, ctx) {
        var _a;
        const objectNode = entity;
        //this.entityCtx?.entityDefinition
        if (!objectNode.entityCtx) {
            objectNode.entityCtx = { entityType: entity_name_1.EntityName.objectNode };
        }
        // _.merge({}, this.entityDefinition, objectType.definition, this.entityDefinition, objectType.contentDefinition),
        const objectType = await ctx.nodeContext.objectType.getOrSetValue(async () => {
            return this.objectTypeService.searchById(objectNode.objectTypeId);
        });
        objectNode.entityCtx.jsonSchema = await this.getObjectNodeDefinition(objectType, ctx.nodeContext);
        objectNode.entityCtx.implementedTypes = (_a = objectType.entityCtx) === null || _a === void 0 ? void 0 : _a.implementedTypes;
    }
    async getObjectNodeDefinition(objectType, ctx, forCreation = false) {
        const schema = lodash_1.merge({}, exports.OBJECT_NODE_SCHEMA, objectType.contentDefinition, objectType.definition);
        if (forCreation && schema.properties.name) {
            schema.properties.name.description =
                'The name is used to identified the object. By default it will be generated by transformation from the displayed name keeping allowed characters (alphanumeric, -, _ or .).';
        }
        await this.completeProperties(schema === null || schema === void 0 ? void 0 : schema.properties, ctx);
        return schema;
    }
    async completeProperties(properties, ctx) {
        if (properties) {
            for (const key of Object.keys(properties)) {
                for (const option of Object.keys(properties[key])) {
                    switch (option) {
                        case 'oneOfNode':
                            properties[key].oneOf = await this.oneOfNode(properties[key].oneOfNode, ctx);
                            delete properties[key].oneOfNode;
                            if (!properties[key].oneOf ||
                                0 === properties[key].oneOf.length) {
                                delete properties[key].oneOf;
                                lodash_1.merge(properties[key], {
                                    required: false,
                                    'x-schema-form': {
                                        condition: 'false',
                                    },
                                });
                            }
                            break;
                        case 'oneOfTree':
                            properties[key].oneOf = await this.oneOfTree(properties[key].oneOfTree, ctx);
                            delete properties[key].oneOfTree;
                            if (!properties[key].oneOf ||
                                0 === properties[key].oneOf.length) {
                                delete properties[key].oneOf;
                                lodash_1.merge(properties[key], {
                                    required: false,
                                    'x-schema-form': {
                                        condition: 'false',
                                    },
                                });
                            }
                            break;
                        case 'enumOfTree':
                            {
                                const enumOfTree = await this.oneOfTree(properties[key].enumOfTree, ctx);
                                delete properties[key].enumOfTree;
                                if (!!enumOfTree && 0 < enumOfTree.length) {
                                    properties[key].enum = enumOfTree.map((item) => item.enum[0]);
                                    properties[key].enumNames = enumOfTree.map((item) => item.title);
                                }
                                else {
                                    properties[key].enum = [];
                                    properties[key].enumNames = [];
                                    lodash_1.merge(properties[key], {
                                        required: false,
                                        'x-schema-form': {
                                            condition: 'false',
                                        },
                                    });
                                }
                            }
                            break;
                        case 'enumOfNode':
                            {
                                const enumOfNode = await this.oneOfNode(properties[key].enumOfNode, ctx);
                                delete properties[key].enumOfNode;
                                if (!!enumOfNode && 0 < enumOfNode.length) {
                                    properties[key].enum = enumOfNode.map((item) => item.enum[0]);
                                    properties[key].enumNames = enumOfNode.map((item) => item.title);
                                }
                                else {
                                    properties[key].enum = [];
                                    properties[key].enumNames = [];
                                    lodash_1.merge(properties[key], {
                                        required: false,
                                        'x-schema-form': {
                                            condition: 'false',
                                        },
                                    });
                                }
                            }
                            break;
                        case 'type':
                            switch (properties[key].type) {
                                case 'object':
                                    await this.completeProperties(properties[key].properties, ctx);
                                    break;
                                case 'array':
                                    await this.completeProperties({ items: properties[key].items }, ctx);
                                    break;
                            }
                            break;
                    }
                }
            }
        }
    }
    async oneOfTree(oneOfTreeOptions, ctx) {
        const result = [];
        const objectNode = ctx.node.value
            ? ctx.node.value
            : ctx.parent.value
                ? ctx.parent.value
                : undefined;
        for (const oneOfTreeOption of oneOfTreeOptions) {
            try {
                let owner = undefined;
                if (oneOfTreeOption.ownerType && oneOfTreeOption.ownerName) {
                    owner = await this.objectNodeService.searchOwner(oneOfTreeOption.ownerType, oneOfTreeOption.ownerName);
                }
                else if (objectNode) {
                    owner = await ctx.owner.getOrSetValue(async () => this.objectNodeService.searchById(objectNode.parentOwnerId));
                }
                if (!owner) {
                    continue;
                }
                let namespace = undefined;
                if (oneOfTreeOption.namespaceType && oneOfTreeOption.namespaceName) {
                    namespace = await this.objectNodeService.searchNamespaceOfOwnerId(owner.id, oneOfTreeOption.namespaceType, oneOfTreeOption.namespaceName);
                }
                else if (objectNode &&
                    !(oneOfTreeOption.ownerType && oneOfTreeOption.ownerName)) {
                    namespace = await ctx.namespace.getOrSetValue(async () => this.objectNodeService.searchById(objectNode.parentNamespaceId));
                }
                if (!namespace) {
                    continue;
                }
                const implementingTreeTypes = await this.objectTypeService.getImplementingTypes(oneOfTreeOption.treeType);
                if (-1 < lodash_1.indexOf(implementingTreeTypes, namespace.objectTypeId)) {
                    this.addTreeOption(oneOfTreeOption, owner, namespace, namespace, result, ctx);
                }
                const trees = await this.objectNodeService.searchTreesOfNamespaceId(namespace.id, oneOfTreeOption.treeType);
                for (const tree of trees) {
                    this.addTreeOption(oneOfTreeOption, owner, namespace, tree, result, ctx);
                }
                // eslint-disable-next-line no-empty
            }
            catch (error) { }
        }
        return result;
    }
    getTreeIdFromTreeOption(oneOfTreeOption, owner, namespace, tree) {
        return ((tree.id === namespace.id ? 'namespace/' : 'tree/') +
            encodeURIComponent(oneOfTreeOption.ownerType
                ? oneOfTreeOption.ownerType
                : owner.objectTypeId) +
            '/' +
            encodeURIComponent(oneOfTreeOption.ownerName ? oneOfTreeOption.ownerName : owner.name) +
            '/' +
            encodeURIComponent(oneOfTreeOption.namespaceType
                ? oneOfTreeOption.namespaceType
                : namespace.objectTypeId) +
            '/' +
            encodeURIComponent(oneOfTreeOption.namespaceName
                ? oneOfTreeOption.namespaceName
                : namespace.name) +
            (tree.id === namespace.id
                ? ''
                : '/' +
                    encodeURIComponent(oneOfTreeOption.treeType) +
                    '/' +
                    encodeURIComponent(tree.name)));
    }
    addTreeOption(oneOfTreeOption, owner, namespace, tree, result, ctx) {
        const treeId = this.getTreeIdFromTreeOption(oneOfTreeOption, owner, namespace, tree);
        if (!lodash_1.some(result, (choice) => choice.enum[0] === treeId)) {
            ctx.references[treeId] = new application_service_1.ExpectedValue(tree);
            result.push({
                enum: [treeId],
                title: (owner.title ? owner.title : owner.name) +
                    ' - ' +
                    (namespace.title ? namespace.title : namespace.name) +
                    (tree.id === namespace.id
                        ? ''
                        : ' - ' + (tree.title ? tree.title : tree.name)),
            });
        }
    }
    async oneOfNode(oneOfNodeOptions, ctx) {
        const result = [];
        const objectNode = ctx.node.value
            ? ctx.node.value
            : ctx.parent.value
                ? ctx.parent.value
                : undefined;
        for (const oneOfNodeOption of oneOfNodeOptions) {
            try {
                let owner = undefined;
                if (oneOfNodeOption.ownerType && oneOfNodeOption.ownerName) {
                    owner = await this.objectNodeService.searchOwner(oneOfNodeOption.ownerType, oneOfNodeOption.ownerName);
                }
                else if (objectNode) {
                    owner = await ctx.owner.getOrSetValue(async () => this.objectNodeService.searchById(objectNode.parentOwnerId));
                }
                if (!owner) {
                    continue;
                }
                let namespace = undefined;
                if (oneOfNodeOption.namespaceType && oneOfNodeOption.namespaceName) {
                    namespace = await this.objectNodeService.searchNamespaceOfOwnerId(owner.id, oneOfNodeOption.namespaceType, oneOfNodeOption.namespaceName);
                }
                else if (objectNode &&
                    !(oneOfNodeOption.ownerType && oneOfNodeOption.ownerName)) {
                    namespace = await ctx.namespace.getOrSetValue(async () => this.objectNodeService.searchById(objectNode.parentNamespaceId));
                }
                if (!namespace) {
                    continue;
                }
                let tree = undefined;
                if (oneOfNodeOption.treeType && oneOfNodeOption.treeName) {
                    tree = await this.objectNodeService.searchTreeOfNamespaceId(namespace.id, oneOfNodeOption.treeType, oneOfNodeOption.treeName);
                }
                else if (objectNode &&
                    !(oneOfNodeOption.ownerType &&
                        oneOfNodeOption.ownerName &&
                        oneOfNodeOption.namespaceType &&
                        oneOfNodeOption.namespaceName)) {
                    tree = await ctx.namespace.getOrSetValue(async () => this.objectNodeService.searchById(objectNode.parentTreeId));
                }
                if (!tree) {
                    continue;
                }
                const nodes = await this.objectNodeService.searchByParentTreeId(tree.id, {
                    objectTypeIds: await this.objectTypeService.getImplementingTypes(oneOfNodeOption.nodeType),
                });
                for (const node of nodes) {
                    const nodeId = 'node/' +
                        encodeURIComponent(oneOfNodeOption.ownerType
                            ? oneOfNodeOption.ownerType
                            : owner.objectTypeId) +
                        '/' +
                        encodeURIComponent(oneOfNodeOption.ownerName
                            ? oneOfNodeOption.ownerName
                            : owner.name) +
                        '/' +
                        encodeURIComponent(oneOfNodeOption.namespaceType
                            ? oneOfNodeOption.namespaceType
                            : namespace.objectTypeId) +
                        '/' +
                        encodeURIComponent(oneOfNodeOption.namespaceName
                            ? oneOfNodeOption.namespaceName
                            : namespace.name) +
                        '/' +
                        encodeURIComponent(oneOfNodeOption.treeType
                            ? oneOfNodeOption.treeType
                            : tree.objectTypeId) +
                        '/' +
                        encodeURIComponent(oneOfNodeOption.treeName ? oneOfNodeOption.treeName : tree.name) +
                        '/' +
                        encodeURIComponent(oneOfNodeOption.nodeType) +
                        '/' +
                        encodeURIComponent(node.name);
                    if (!lodash_1.some(result, (choice) => choice.enum[0] === nodeId)) {
                        ctx.references[nodeId] = new application_service_1.ExpectedValue(node);
                        result.push({
                            enum: [nodeId],
                            title: (owner.title ? owner.title : owner.name) +
                                ' - ' +
                                (namespace.title ? namespace.title : namespace.name) +
                                ' - ' +
                                (tree.title ? tree.title : tree.name) +
                                ' - ' +
                                (node.title ? node.title : node.name),
                        });
                    }
                }
                // eslint-disable-next-line no-empty
            }
            catch (error) { }
        }
        return result;
    }
};
ObjectNodeDefinitionService = tslib_1.__decorate([
    tslib_1.__param(0, core_1.service(object_type_service_1.ObjectTypeService)),
    tslib_1.__param(1, core_1.service(object_node_service_1.ObjectNodeService)),
    tslib_1.__param(2, core_1.service(entity_definition_service_1.EntityDefinitionService)),
    tslib_1.__metadata("design:paramtypes", [object_type_service_1.ObjectTypeService,
        object_node_service_1.ObjectNodeService,
        entity_definition_service_1.EntityDefinitionService])
], ObjectNodeDefinitionService);
exports.ObjectNodeDefinitionService = ObjectNodeDefinitionService;
//# sourceMappingURL=object-node-definition.service.js.map