"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.BindingService = exports.OneToManyBindingMapStar = void 0;
const OneToManyMapStar_1 = require("../../common/models/OneToManyMapStar");
const buildInstanceBinding_1 = require("../calculations/buildInstanceBinding");
const cloneBinding_1 = require("../calculations/cloneBinding");
var BindingRelationKind;
(function (BindingRelationKind) {
    BindingRelationKind["id"] = "id";
    BindingRelationKind["moduleId"] = "moduleId";
    BindingRelationKind["serviceId"] = "serviceId";
})(BindingRelationKind || (BindingRelationKind = {}));
class OneToManyBindingMapStar extends OneToManyMapStar_1.OneToManyMapStar {
    _buildNewInstance(spec) {
        return new OneToManyBindingMapStar(spec);
    }
    _cloneModel(model) {
        return (0, cloneBinding_1.cloneBinding)(model);
    }
}
exports.OneToManyBindingMapStar = OneToManyBindingMapStar;
class BindingService {
    #autobindOptions;
    #bindingMaps;
    #getParent;
    constructor(getParent, autobindOptions, bindingMaps) {
        this.#bindingMaps =
            bindingMaps ??
                new OneToManyBindingMapStar({
                    id: {
                        isOptional: false,
                    },
                    moduleId: {
                        isOptional: true,
                    },
                    serviceId: {
                        isOptional: false,
                    },
                });
        this.#getParent = getParent;
        this.#autobindOptions = autobindOptions;
    }
    static build(getParent, autobindOptions) {
        return new BindingService(getParent, autobindOptions);
    }
    clone() {
        const clone = new BindingService(this.#getParent, this.#autobindOptions, this.#bindingMaps.clone());
        return clone;
    }
    get(serviceIdentifier) {
        const bindings = this.getNonParentBindings(serviceIdentifier) ??
            this.#getParent()?.get(serviceIdentifier);
        if (bindings !== undefined) {
            return bindings;
        }
        const autoBoundBinding = this.#tryAutobind(serviceIdentifier);
        return autoBoundBinding === undefined
            ? autoBoundBinding
            : [autoBoundBinding];
    }
    *getChained(serviceIdentifier) {
        const currentBindings = this.getNonParentBindings(serviceIdentifier);
        if (currentBindings !== undefined) {
            yield* currentBindings;
        }
        const parent = this.#getParent();
        if (parent === undefined) {
            if (currentBindings === undefined) {
                const autobindBindings = this.#tryAutobind(serviceIdentifier);
                if (autobindBindings !== undefined) {
                    yield autobindBindings;
                }
            }
        }
        else {
            yield* parent.getChained(serviceIdentifier);
        }
    }
    getBoundServices() {
        const serviceIdentifierSet = new Set(this.#bindingMaps.getAllKeys(BindingRelationKind.serviceId));
        const parent = this.#getParent();
        if (parent !== undefined) {
            for (const serviceIdentifier of parent.getBoundServices()) {
                serviceIdentifierSet.add(serviceIdentifier);
            }
        }
        return serviceIdentifierSet;
    }
    getById(id) {
        return (this.#bindingMaps.get(BindingRelationKind.id, id) ?? this.#getParent()?.getById(id));
    }
    getByModuleId(moduleId) {
        return (this.#bindingMaps.get(BindingRelationKind.moduleId, moduleId) ?? this.#getParent()?.getByModuleId(moduleId));
    }
    getNonParentBindings(serviceId) {
        return this.#bindingMaps.get(BindingRelationKind.serviceId, serviceId);
    }
    getNonParentBoundServices() {
        return this.#bindingMaps.getAllKeys(BindingRelationKind.serviceId);
    }
    removeById(id) {
        this.#bindingMaps.removeByRelation(BindingRelationKind.id, id);
    }
    removeAllByModuleId(moduleId) {
        this.#bindingMaps.removeByRelation(BindingRelationKind.moduleId, moduleId);
    }
    removeAllByServiceId(serviceId) {
        this.#bindingMaps.removeByRelation(BindingRelationKind.serviceId, serviceId);
    }
    set(binding) {
        const relation = {
            [BindingRelationKind.id]: binding.id,
            [BindingRelationKind.serviceId]: binding.serviceIdentifier,
        };
        if (binding.moduleId !== undefined) {
            relation[BindingRelationKind.moduleId] = binding.moduleId;
        }
        this.#bindingMaps.add(binding, relation);
    }
    #tryAutobind(serviceIdentifier) {
        if (this.#autobindOptions === undefined ||
            typeof serviceIdentifier !== 'function') {
            return undefined;
        }
        const binding = (0, buildInstanceBinding_1.buildInstanceBinding)(this.#autobindOptions, serviceIdentifier);
        this.set(binding);
        return binding;
    }
}
exports.BindingService = BindingService;
//# sourceMappingURL=BindingService.js.map