"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.EntityMapper = void 0;
const entity_1 = require("../contracts/base/entity");
const entity_construction_args_1 = require("../contracts/base/entity-construction-args");
const guard_1 = __importDefault(require("../guard"));
const entity_resource_1 = require("../models/entity-resource");
const property_mapper_1 = require("./property-mapper");
const related_path_mapper_1 = require("./related-path-mapper");
const relation_mapper_1 = require("./relation-mapper");
const rendition_mapper_1 = require("./rendition-mapper");
const typed_entity_creator_1 = require("./typed-entity-creator");
class EntityMapper {
    constructor(client) {
        guard_1.default.notNullOrUndefined(client);
        this._client = client;
        this._propertyMapper = new property_mapper_1.PropertyMapper(client);
        this._relationMapper = new relation_mapper_1.RelationMapper(client);
        this._renditionMapper = new rendition_mapper_1.RenditionMapper(client);
        this._relatedPathMapper = new related_path_mapper_1.RelatedPathMapper();
        this._creator = new typed_entity_creator_1.TypedEntityCreator(client);
    }
    mapEntityAsync(resource, schema) {
        return __awaiter(this, void 0, void 0, function* () {
            var _a;
            guard_1.default.notNullOrUndefined(resource);
            // The minimal schema is optional, but we should at least have a definition name.
            const definitionName = (_a = schema === null || schema === void 0 ? void 0 : schema.definitionName) !== null && _a !== void 0 ? _a : (yield this._client.linkHelper.nameFromDefinitionAsync(resource.entityDefinition));
            guard_1.default.notNullOrUndefined(definitionName);
            guard_1.default.stringNotNullOrEmpty(definitionName);
            const cultures = new Set(resource.cultures || []); //? Revisit usage of set
            const properties = yield this._propertyMapper.mapPropertiesAsync(resource, [...cultures], schema);
            const relations = yield this._relationMapper.mapRelationsAsync(resource, schema);
            const renditions = this._renditionMapper.mapRenditions(resource.id, resource); //TODO: Extract extension data?
            const relatedPaths = this._relatedPathMapper.mapRelatedPaths(resource);
            const args = new entity_construction_args_1.EntityConstructionArgs(definitionName, {
                id: resource.id || 0,
                identifier: resource.identifier,
                cultures: [...cultures],
                properties: properties,
                relations: relations,
                renditions: renditions,
                relatedPaths: relatedPaths,
            });
            const entity = new entity_1.Entity(this._client, args);
            yield this.mapBasePropertiesToSdkEntityAsync(resource, entity);
            entity.startTracking();
            //TODO: Extension data
            return entity;
        });
    }
    mapEntitiesAsync(collection, schemas) {
        return __awaiter(this, void 0, void 0, function* () {
            guard_1.default.notNullOrUndefined(collection, "collection");
            guard_1.default.notNullOrUndefined(schemas, "schemas");
            const list = [];
            for (const resource of collection) {
                if (resource == null)
                    continue;
                const definitionName = (yield this._client.linkHelper.nameFromDefinitionAsync(resource.entityDefinition));
                if (!schemas[definitionName]) {
                    throw Error(`Cannot map entity, missing minimal schema for definition '${definitionName}'.`);
                }
                const schema = schemas[definitionName];
                const entity = yield this.mapEntityAsync(resource, schema);
                list.push(entity);
            }
            return list;
        });
    }
    toResourceAsync(entity) {
        return __awaiter(this, void 0, void 0, function* () {
            guard_1.default.notNullOrUndefined(entity);
            const properties = property_mapper_1.PropertyMapper.mapToPropertyResources(entity);
            const relations = yield this._relationMapper.mapToRelationResourcesAsync(entity);
            const renditions = this._renditionMapper.mapToResource(entity.renditions);
            const resource = yield this.createEntityResourceAsync(entity, properties, relations, renditions);
            return resource;
        });
    }
    mapDirtiesToResourceAsync(entity) {
        return __awaiter(this, void 0, void 0, function* () {
            guard_1.default.notNullOrUndefined(entity);
            const properties = property_mapper_1.PropertyMapper.mapDirtyProperties(entity);
            const relations = yield this._relationMapper.mapDirtyRelationsAsync(entity);
            const renditions = this._renditionMapper.mapToResource(entity.renditions);
            const resource = yield this.createEntityResourceAsync(entity, properties, relations, renditions);
            return resource;
        });
    }
    createEntityResourceAsync(entity, properties, relations, renditions) {
        return __awaiter(this, void 0, void 0, function* () {
            const definitionLink = yield this._client.linkHelper.definitionToLinkAsync(entity.definitionName);
            const entityLink = entity.id ? yield this._client.linkHelper.entityToLinkAsync(entity.id) : undefined;
            const createdBy = entity.createdBy
                ? yield this._client.linkHelper.entityToLinkAsync(entity.createdBy)
                : undefined;
            const lockedBy = entity.lockedBy ? yield this._client.linkHelper.entityToLinkAsync(entity.lockedBy) : undefined;
            const modifiedBy = entity.modifiedBy
                ? yield this._client.linkHelper.entityToLinkAsync(entity.modifiedBy)
                : undefined;
            const relatedPaths = this._relatedPathMapper.mapToResource(entity);
            const resource = new entity_resource_1.EntityResource({
                entityDefinition: definitionLink,
                id: entity.id || 0,
                identifier: entity.identifier,
                cultures: entity.cultures.map(x => x),
                isRootTaxonomyItem: entity.isRootTaxonomyItem,
                isPathRoot: entity.isPathRoot,
                inheritsSecurity: entity.inheritsSecurity,
                isSystemOwned: entity.isSystemOwned,
                properties: properties,
                relations: relations,
                renditions: renditions,
                isCurrentUserDefault: entity.isCurrentUserDefault,
                languageSupportedOotb: entity.languageSupportedOotb,
                hasPublicLink: entity.hasPublicLink,
                masterFileModifiedOn: entity.masterFileModifiedOn,
                savedSelectionPageName: entity.savedSelectionPageName,
                gatewayLinks: entity.gatewayLinks,
                publicLink: entity.publicLink,
                publicCollectionLink: entity.publicCollectionLink,
                isEnabled: entity.isEnabled,
                modules: entity.modules,
                roles: entity.roles,
                permissions: entity.permissions,
                path: entity.path,
                relatedPaths: relatedPaths,
                lockedOn: entity.lockedOn,
                lockedBy: lockedBy,
                createdOn: entity.createdOn,
                createdBy: createdBy,
                modifiedOn: entity.modifiedOn,
                modifiedBy: modifiedBy,
                version: entity.version,
                self: entityLink,
                combinedPublishStatus: entity.combinedPublishStatus,
                combinedPublishStatusDetails: entity.combinedPublishStatusDetails,
            });
            return resource;
        });
    }
    mapBasePropertiesToSdkEntityAsync(resource, entity) {
        return __awaiter(this, void 0, void 0, function* () {
            const createdBy = resource.createdBy && (yield this._client.linkHelper.idFromEntityAsync(resource.createdBy));
            const lockedBy = resource.lockedBy ? yield this._client.linkHelper.idFromEntityAsync(resource.lockedBy) : null;
            const modifiedBy = resource.modifiedBy && (yield this._client.linkHelper.idFromEntityAsync(resource.modifiedBy));
            //? Create deep copies
            entity.inheritsSecurity = resource.inheritsSecurity;
            entity.isSystemOwned = resource.isSystemOwned;
            entity.lockedOn = resource.lockedOn || null;
            entity.lockedBy = lockedBy;
            entity.createdOn = resource.createdOn;
            entity.createdBy = createdBy || undefined;
            entity.modifiedOn = resource.modifiedOn;
            entity.modifiedBy = modifiedBy || undefined;
            entity.version = resource.version;
            entity.isPathRoot = resource.isPathRoot;
            entity.isRootTaxonomyItem = resource.isRootTaxonomyItem;
            entity.isCurrentUserDefault = resource.isCurrentUserDefault;
            entity.languageSupportedOotb = resource.languageSupportedOotb;
            entity.hasPublicLink = resource.hasPublicLink;
            entity.masterFileModifiedOn = resource.masterFileModifiedOn;
            entity.savedSelectionPageName = resource.savedSelectionPageName;
            entity.gatewayLinks = resource.gatewayLinks;
            entity.publicLink = resource.publicLink;
            entity.publicCollectionLink = resource.publicCollectionLink;
            entity.isEnabled = resource.isEnabled;
            entity.modules = resource.modules;
            entity.roles = resource.roles;
            entity.permissions = resource.permissions;
            entity.path = resource.path;
            entity.combinedPublishStatus = resource.combinedPublishStatus;
            entity.combinedPublishStatusDetails = resource.combinedPublishStatusDetails;
        });
    }
}
exports.EntityMapper = EntityMapper;
//# sourceMappingURL=entity-mapper.js.map