"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
    for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Filter = void 0;
const ConstantFilter_1 = require("./ConstantFilter");
const IntersectionFilter_1 = require("./IntersectionFilter");
const UnionFilter_1 = require("./UnionFilter");
const ComplementFilter_1 = require("./ComplementFilter");
const PatientByHcPartyAndActiveFilter_1 = require("./PatientByHcPartyAndActiveFilter");
const PatientByHcPartyAndAddressFilter_1 = require("./PatientByHcPartyAndAddressFilter");
const PatientByHcPartyAndExternalIdFilter_1 = require("./PatientByHcPartyAndExternalIdFilter");
const PatientByHcPartyAndSsinsFilter_1 = require("./PatientByHcPartyAndSsinsFilter");
const PatientByHcPartyDateOfBirthBetweenFilter_1 = require("./PatientByHcPartyDateOfBirthBetweenFilter");
const PatientByHcPartyDateOfBirthFilter_1 = require("./PatientByHcPartyDateOfBirthFilter");
const date_fns_1 = require("date-fns");
const PatientByHcPartyFilter_1 = require("./PatientByHcPartyFilter");
const PatientByHcPartyGenderEducationProfessionFilter_1 = require("./PatientByHcPartyGenderEducationProfessionFilter");
const PatientByIdsFilter_1 = require("./PatientByIdsFilter");
const PatientByHcPartyNameContainsFuzzyFilter_1 = require("./PatientByHcPartyNameContainsFuzzyFilter");
const ContactByHcPartyFilter_1 = require("./ContactByHcPartyFilter");
__exportStar(require("./AllCodesFilter"), exports);
__exportStar(require("./AllDevicesFilter"), exports);
__exportStar(require("./AllDocumentsFilter"), exports);
__exportStar(require("./AllHealthcarePartiesFilter"), exports);
__exportStar(require("./AllInsurancesFilter"), exports);
__exportStar(require("./AllUsersFilter"), exports);
__exportStar(require("./AllPricingFilter"), exports);
__exportStar(require("./CodeByIdsFilter"), exports);
__exportStar(require("./CodeByRegionTypeCodeVersionFilter"), exports);
__exportStar(require("./CodeByRegionTypeLabelLanguageFilter"), exports);
__exportStar(require("./ComplementFilter"), exports);
__exportStar(require("./ConstantFilter"), exports);
__exportStar(require("./ContactByHcPartyFilter"), exports);
__exportStar(require("./ContactByHcPartyPatientTagCodeDateFilter"), exports);
__exportStar(require("./ContactByHcPartyTagCodeDateFilter"), exports);
__exportStar(require("./ContactByServiceIdsFilter"), exports);
__exportStar(require("./DeviceByHcPartyFilter"), exports);
__exportStar(require("./DeviceByIdsFilter"), exports);
__exportStar(require("./HealthElementByHcPartyCodeFilter"), exports);
__exportStar(require("./HealthElementByHcPartyFilter"), exports);
__exportStar(require("./HealthElementByHcPartyIdentifiersFilter"), exports);
__exportStar(require("./HealthElementByHcPartyIdentifiersVersioningFilter"), exports);
__exportStar(require("./HealthElementByHcPartySecretForeignKeysFilter"), exports);
__exportStar(require("./HealthElementByHcPartyStatusVersioningFilter"), exports);
__exportStar(require("./HealthElementByHcPartyTagCodeFilter"), exports);
__exportStar(require("./HealthElementByHcPartyTagFilter"), exports);
__exportStar(require("./HealthElementByIdsFilter"), exports);
__exportStar(require("./HealthcarePartyByIdsFilter"), exports);
__exportStar(require("./HealthcarePartyByNameFilter"), exports);
__exportStar(require("./HealthcarePartyByTagCodeFilter"), exports);
__exportStar(require("./HealthcarePartyByIdentifiersFilter"), exports);
__exportStar(require("./HealthcarePartyByIdsFilter"), exports);
__exportStar(require("./IntersectionFilter"), exports);
__exportStar(require("./InvoiceByHcPartyCodeDateFilter"), exports);
__exportStar(require("./PatientByHcPartyAndActiveFilter"), exports);
__exportStar(require("./PatientByHcPartyAndAddressFilter"), exports);
__exportStar(require("./PatientByHcPartyAndExternalIdFilter"), exports);
__exportStar(require("./PatientByHcPartyAndIdentifiersFilter"), exports);
__exportStar(require("./PatientByHcPartyAndSsinFilter"), exports);
__exportStar(require("./PatientByHcPartyAndSsinsFilter"), exports);
__exportStar(require("./PatientByHcPartyDateOfBirthBetweenFilter"), exports);
__exportStar(require("./PatientByHcPartyDateOfBirthFilter"), exports);
__exportStar(require("./PatientByHcPartyFilter"), exports);
__exportStar(require("./PatientByHcPartyGenderEducationProfessionFilter"), exports);
__exportStar(require("./PatientByHcPartyNameContainsFuzzyFilter"), exports);
__exportStar(require("./PatientByHcPartyNameFilter"), exports);
__exportStar(require("./PatientByIdsFilter"), exports);
__exportStar(require("./ServiceByContactsAndSubcontactsFilter"), exports);
__exportStar(require("./ServiceByHcPartyFilter"), exports);
__exportStar(require("./ServiceByHcPartyIdentifiersFilter"), exports);
__exportStar(require("./ServiceByHcPartyHealthElementIdsFilter"), exports);
__exportStar(require("./ServiceByHcPartyTagCodeDateFilter"), exports);
__exportStar(require("./ServiceByHcPartyCodePrefixFilter"), exports);
__exportStar(require("./ServiceByHcPartyTagPrefixFilter"), exports);
__exportStar(require("./ServiceByHcPartyMonthCodePrefixFilter"), exports);
__exportStar(require("./ServiceByHcPartyMonthTagPrefixFilter"), exports);
__exportStar(require("./ServiceByHcPartyPatientCodePrefixFilter"), exports);
__exportStar(require("./ServiceByHcPartyPatientTagPrefixFilter"), exports);
__exportStar(require("./ServiceByHcPartyCodesFilter"), exports);
__exportStar(require("./ServiceByHcPartyTagCodesFilter"), exports);
__exportStar(require("./ServiceByHcPartyPatientCodesFilter"), exports);
__exportStar(require("./ServiceByHcPartyPatientTagCodesFilter"), exports);
__exportStar(require("./ServiceByIdsFilter"), exports);
__exportStar(require("./ServiceBySecretForeignKeys"), exports);
__exportStar(require("./UnionFilter"), exports);
__exportStar(require("./UserByIdsFilter"), exports);
__exportStar(require("./MaintenanceTaskByHcPartyAndIdentifiersFilter"), exports);
__exportStar(require("./MaintenanceTaskByHcPartyAndTypeFilter"), exports);
__exportStar(require("./MaintenanceTaskByIdsFilter"), exports);
__exportStar(require("./MaintenanceTaskAfterDateFilter"), exports);
__exportStar(require("./TopicByHcPartyFilter"), exports);
__exportStar(require("./TopicByParticipantFilter"), exports);
__exportStar(require("./MessageByHcPartyFilter"), exports);
__exportStar(require("./MessageByHcPartyTransportGuidFilter"), exports);
__exportStar(require("./LatestMessageByHcPartyTransportGuidFilter"), exports);
class Filter {
    static patient() {
        return new PatientFilterBuilder();
    }
}
exports.Filter = Filter;
const f = new ComplementFilter_1.ComplementFilter(new ContactByHcPartyFilter_1.ContactByHcPartyFilter({}), new ContactByHcPartyFilter_1.ContactByHcPartyFilter({}));
class FilterBuilder {
    // This is the method that is called each time we chain a filter to another filter. The default behaviour is to
    // return a FilterBuilder with the provider set to the last element in the chain, except when we use combination
    // operators like or()/and()/… . After one of those, the composer is set to a function that will return a FilterBuilder
    constructor(filterProvider, composer) {
        // that combines the existing filterBuilder with the filter definition we just added.
        this.composer = (thisFilterBuilder, otherFilterBuilder) => otherFilterBuilder;
        this.filterProvider = filterProvider;
        composer && (this.composer = composer);
    }
    listOf(elements) {
        return this.clone(() => new ConstantFilter_1.ConstantFilter(elements));
    }
    /**
     * There are two ways of doing and, or, …
     *
     * 1) for (...) or (...) we use the syntax ... .or((builder) => builder...)
     * ex: youngerThan(65).or((b) => b.olderThan(18).and().gender(M)) means any gender < 65 or male > 18
     * 2) for ((...) or ...) we use the syntax ... .or().…
     * ex: youngerThan(65).or().olderThan(18).and().gender(M) means males between 18 and 65
     *
     * When 1) is used we do not have to wait for anything to provide a resolved builder that can later be combined with extra elements in the chain.
     * In other words, we can build the current filter chain up to the or/and/… and we can build what is inside the or/and/… brackets and we can set
     * the filterProvider of the returned Builder to () => UnionFilter([leftHand.build(), innerBrackets.build()]).
     *
     * When 2) is used, things get more tricky because we will have to do an or/and/… between what we have on the leftHand and with what we do not have
     * yet on the right hand. What we do in that situation is to set the filterProvider() to undefined because calling build() without having provided a
     * rightHand doesn't make sense. We set a composer that is going to be called the next time we chain a filter.
     *
     * @param filterBuilderFactory
     */
    and(filterBuilderFactory) {
        const combiner = (leftHandFilter, rightHandFilter) => () => new IntersectionFilter_1.IntersectionFilter([leftHandFilter, rightHandFilter]);
        return filterBuilderFactory ? this.makeEagerLeftRightFilterBuilder(filterBuilderFactory, combiner) : this.makeLazyLeftRightFilterBuilder(combiner);
    }
    or(filterBuilderFactory) {
        const combiner = (leftHandFilter, rightHandFilter) => () => new UnionFilter_1.UnionFilter([leftHandFilter, rightHandFilter]);
        return filterBuilderFactory ? this.makeEagerLeftRightFilterBuilder(filterBuilderFactory, combiner) : this.makeLazyLeftRightFilterBuilder(combiner);
    }
    minus(filterBuilderFactory) {
        const combiner = (leftHandFilter, rightHandFilter) => () => new ComplementFilter_1.ComplementFilter(leftHandFilter, rightHandFilter);
        return filterBuilderFactory ? this.makeEagerLeftRightFilterBuilder(filterBuilderFactory, combiner) : this.makeLazyLeftRightFilterBuilder(combiner);
    }
    makeLazyLeftRightFilterBuilder(leftHandRightHandFiltersCombiner) {
        // eslint-disable-next-line @typescript-eslint/no-this-alias
        const leftHandFilterBuilder = this;
        const leftHandFilter = leftHandFilterBuilder.build(); // Freeze the leftHand filter
        return leftHandFilterBuilder.filterProvider
            ? this.clone(undefined, //filter provider is indeterminate until we have performed a composition
            (unused, rightHandFilterBuilder) => {
                // because we freeze the leftHand in the state it is right now, we are not going to use its value when the composition occurs
                const rightHandFilter = rightHandFilterBuilder.build();
                return rightHandFilter
                    ? this.clone(leftHandRightHandFiltersCombiner(leftHandFilter, rightHandFilter), rightHandFilterBuilder.composer)
                    : rightHandFilterBuilder; //Can this happen ?
            })
            : this;
    }
    makeEagerLeftRightFilterBuilder(rightHandFilterBuilderFactory, leftHandRightHandFiltersCombiner) {
        const rightHandFilterBuilder = rightHandFilterBuilderFactory(this);
        return this.filterProvider ? this.clone(leftHandRightHandFiltersCombiner(this.build(), rightHandFilterBuilder.build())) : this;
    }
}
class PatientFilterBuilder extends FilterBuilder {
    constructor(filterProvider, hcpId, composer) {
        super(filterProvider, composer);
        this.hcpId = hcpId;
    }
    clone(filterProvider, composer) {
        return new PatientFilterBuilder(filterProvider, this.hcpId, composer);
    }
    listOf(elements) {
        return new PatientFilterBuilder(() => new ConstantFilter_1.ConstantFilter(elements));
    }
    and(filterBuilderFactory) {
        return super.and(filterBuilderFactory);
    }
    or(filterBuilderFactory) {
        return super.or(filterBuilderFactory);
    }
    minus(filterBuilderFactory) {
        return super.minus(filterBuilderFactory);
    }
    forHcp(hcpId) {
        return this.composer(this, new PatientFilterBuilder(this.filterProvider, hcpId));
    }
    all() {
        return this.composer(this, new PatientFilterBuilder(() => new PatientByHcPartyFilter_1.PatientByHcPartyFilter({ healthcarePartyId: this.hcpId }), this.hcpId));
    }
    activePatients() {
        return this.composer(this, new PatientFilterBuilder(() => new PatientByHcPartyAndActiveFilter_1.PatientByHcPartyAndActiveFilter({ healthcarePartyId: this.hcpId, active: true }), this.hcpId));
    }
    inactivePatients() {
        return this.composer(this, new PatientFilterBuilder(() => new PatientByHcPartyAndActiveFilter_1.PatientByHcPartyAndActiveFilter({ healthcarePartyId: this.hcpId, active: false }), this.hcpId));
    }
    byAddress(searchString, postalCode, houseNumber) {
        return this.composer(this, new PatientFilterBuilder(() => new PatientByHcPartyAndAddressFilter_1.PatientByHcPartyAndAddressFilter({
            healthcarePartyId: this.hcpId,
            searchString,
            postalCode,
            houseNumber,
        }), this.hcpId));
    }
    withExternalId(externalId) {
        return this.composer(this, new PatientFilterBuilder(() => new PatientByHcPartyAndExternalIdFilter_1.PatientByHcPartyAndExternalIdFilter({
            healthcarePartyId: this.hcpId,
            externalId: externalId,
        }), this.hcpId));
    }
    withSsins(ssins) {
        return this.composer(this, new PatientFilterBuilder(() => new PatientByHcPartyAndSsinsFilter_1.PatientByHcPartyAndSsinsFilter({ healthcarePartyId: this.hcpId, ssins: ssins }), this.hcpId));
    }
    withDateOfBirthBetween(from, to) {
        return this.composer(this, this.clone(() => new PatientByHcPartyDateOfBirthBetweenFilter_1.PatientByHcPartyDateOfBirthBetweenFilter({
            healthcarePartyId: this.hcpId,
            minDateOfBirth: from,
            maxDateOfBirth: to,
        })));
    }
    byDateOfBirth(dateOfBirth) {
        return this.composer(this, new PatientFilterBuilder(() => new PatientByHcPartyDateOfBirthFilter_1.PatientByHcPartyDateOfBirthFilter({
            healthcarePartyId: this.hcpId,
            dateOfBirth: dateOfBirth,
        }), this.hcpId));
    }
    olderThan(age) {
        return this.withDateOfBirthBetween(10000101, parseInt((0, date_fns_1.format)((0, date_fns_1.add)(new Date(), { years: -age }), 'yyyyMMdd')));
    }
    youngerThan(age) {
        return this.withDateOfBirthBetween(parseInt((0, date_fns_1.format)((0, date_fns_1.add)(new Date(), { years: -age }), 'yyyyMMdd')), 99991231);
    }
    byGenderEducationProfession(gender, education, profession) {
        return this.composer(this, new PatientFilterBuilder(() => new PatientByHcPartyGenderEducationProfessionFilter_1.PatientByHcPartyGenderEducationProfessionFilter({
            healthcarePartyId: this.hcpId,
            gender: gender,
            education: education,
            profession: profession,
        }), this.hcpId));
    }
    byIds(ids) {
        return this.composer(this, new PatientFilterBuilder(() => new PatientByIdsFilter_1.PatientByIdsFilter({ ids: ids }), this.hcpId));
    }
    searchByName(name) {
        return this.composer(this, new PatientFilterBuilder(() => new PatientByHcPartyNameContainsFuzzyFilter_1.PatientByHcPartyNameContainsFuzzyFilter({
            healthcarePartyId: this.hcpId,
            searchString: name,
        }), this.hcpId));
    }
    build() {
        var _a;
        return ((_a = this.filterProvider) === null || _a === void 0 ? void 0 : _a.call(this)) || this.all().build();
    }
}
//# sourceMappingURL=filters.js.map