"use strict";
/*
 * Copyright © 2019 Atomist, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.any = exports.all = exports.whenNot = void 0;
const logger_1 = require("@atomist/automation-client/lib/util/logger");
const PredicateMapping_1 = require("../PredicateMapping");
const defaultPredicateMappingCostAnalyzer_1 = require("./defaultPredicateMappingCostAnalyzer");
const PredicateMappingCostAnalyzer_1 = require("./PredicateMappingCostAnalyzer");
/**
 * Return the opposite of this predicate mapping
 */
function whenNot(t) {
    return {
        name: `not (${t.name})`,
        mapping: async (pi) => !(await t.mapping(pi)),
        structure: {
            components: [t],
            compositionStyle: PredicateMapping_1.PredicateMappingCompositionStyle.Not,
        },
    };
}
exports.whenNot = whenNot;
/**
 * Wrap all these predicates in a single predicate
 * AND: Return true if all are satisfied
 * @param {PredicateMapping} predicates
 * @param analyzer analyzer to use for performance optimization
 * @return {PredicateMapping}
 */
function all(predicates, analyzer = defaultPredicateMappingCostAnalyzer_1.DefaultPredicateMappingCostAnalyzer) {
    return {
        name: predicates.map(g => g.name).join(" && "),
        mapping: async (pci) => optimizedAndEvaluation(predicates, analyzer)(pci),
        structure: {
            components: predicates,
            compositionStyle: PredicateMapping_1.PredicateMappingCompositionStyle.And,
        },
    };
}
exports.all = all;
/**
 * Wrap all these predicates in a single predicate
 * OR: Return true if any is satisfied
 * @param {PredicateMapping} predicates
 * @param analyzer analyzer to use for performance optimization
 * @return {PredicateMapping}
 */
function any(predicates, analyzer = defaultPredicateMappingCostAnalyzer_1.DefaultPredicateMappingCostAnalyzer) {
    return {
        name: predicates.map(g => g.name).join(" || "),
        mapping: async (pci) => {
            // Cannot short-circuit this
            const allResults = await gatherResults(predicates)(pci);
            return allResults.includes(true);
        },
        structure: {
            components: predicates,
            compositionStyle: PredicateMapping_1.PredicateMappingCompositionStyle.Or,
        },
    };
}
exports.any = any;
/**
 * Evaluate predicates for an AND, running non-expensive ones first
 * @param {Array<PredicateMapping<F>>} predicates
 * @param {PredicateMappingCostAnalyzer<F>} analyzer
 * @return {(f: F) => Promise<boolean>}
 */
function optimizedAndEvaluation(predicates, analyzer) {
    const cheap = [];
    const remaining = [];
    for (const p of predicates) {
        const cost = analyzer(p);
        if (cost !== PredicateMappingCostAnalyzer_1.ExpectedPredicateMappingCost.expensive) {
            cheap.push(p);
        }
        else {
            remaining.push(p);
        }
    }
    logger_1.logger.debug("Cheap: [%j], remaining: [%j]", cheap, remaining);
    return async (pci) => {
        const cheapResults = await gatherResults(cheap)(pci);
        if (cheapResults.includes(false)) {
            return false;
        }
        const remainingResults = await gatherResults(remaining)(pci);
        return !remainingResults.includes(false);
    };
}
function gatherResults(predicates) {
    return pci => {
        return Promise.all(predicates.map(async (pt) => {
            const result = await pt.mapping(pci);
            logger_1.logger.debug(`Result of PushTest '${pt.name}' was ${result}`);
            return result;
        }));
    };
}
//# sourceMappingURL=predicateUtils.js.map