"use strict";
/*
 * Copyright © 2020 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.universalGenerator = void 0;
const _ = require("lodash");
const generatorCommand_1 = require("../../api-helper/command/generator/generatorCommand");
const projectLoaderRepoLoader_1 = require("../../api-helper/machine/projectLoaderRepoLoader");
const toMachineOptions_1 = require("../../api-helper/machine/toMachineOptions");
const CachingProjectLoader_1 = require("../../api-helper/project/CachingProjectLoader");
const array_1 = require("../../core/util/misc/array");
/**
 * Wrap provided generator to execute additional transformsAndParameters
 */
function universalGenerator(sdm, generator, transforms) {
    return Object.assign(Object.assign({}, generator), { startingPoint: async (pi) => {
            const repoLoader = (p) => projectLoaderRepoLoader_1.projectLoaderRepoLoader(sdm.configuration.sdm.projectLoader || new CachingProjectLoader_1.CachingProjectLoader(), p.target.credentials, true);
            const project = await generatorCommand_1.computeStartingPoint(pi.parameters, pi.context, repoLoader(pi.parameters), Object.assign(Object.assign({}, generator), { redirecter: () => undefined }), generator.startingPoint, generator, toMachineOptions_1.toMachineOptions(sdm));
            const transformsToApply = [];
            for (const transform of transforms) {
                if (!!transform.test) {
                    if (await transform.test(project)) {
                        transformsToApply.push(transform);
                    }
                }
                else {
                    transformsToApply.push(transform);
                }
            }
            await enhanceWithSpecificParameters(transformsToApply, pi);
            // Safe the transformsAndParameters to invoke on the invocation to re-use later
            pi.parameters.__transforms = transformsToApply;
            return project;
        }, transform: async (p, pi) => {
            const universalTransforms = pi.parameters.__transforms;
            const computedTransforms = _.flatten(universalTransforms.map(t => array_1.toArray(t.transforms)));
            const trans = chainTransforms(...array_1.toArray(generator.transform || []), ...computedTransforms);
            return trans(p, pi, pi.parameters);
        } });
}
exports.universalGenerator = universalGenerator;
/**
 * Enrich parameters with the extras if needed
 */
async function enhanceWithSpecificParameters(universalTransforms, ctx) {
    const unsatisfiedParameters = {};
    for (const universalTransform of universalTransforms) {
        let params;
        if (typeof universalTransform.parameters === "function") {
            const paramsValues = await ctx.promptFor(unsatisfiedParameters);
            params = await universalTransform.parameters(Object.assign(Object.assign({}, ctx.parameters), paramsValues));
        }
        else {
            params = universalTransform.parameters;
        }
        _.forEach(params, (v, k) => {
            if (ctx.parameters[k] === undefined) {
                unsatisfiedParameters[k] = v;
            }
        });
    }
    const newParams = await ctx.promptFor(unsatisfiedParameters);
    for (const name of Object.getOwnPropertyNames(newParams)) {
        ctx.parameters[name] = newParams[name];
    }
}
function chainTransforms(...transforms) {
    return async (p, sdmc, params) => {
        let cumulativeResult = {
            target: p,
            success: true,
            edited: false,
        };
        try {
            for (const t of transforms) {
                const lastResult = await t(p, sdmc, params);
                cumulativeResult = combineResults(toTransformResult(p, lastResult), cumulativeResult);
            }
            return cumulativeResult;
        }
        catch (error) {
            return { target: p, edited: cumulativeResult.edited, success: false, error };
        }
    };
}
function toTransformResult(p, tr) {
    const maybe = tr;
    if (maybe && maybe.success !== undefined) {
        return maybe;
    }
    else {
        return { target: p, success: true, edited: undefined };
    }
}
function combineResults(r1, r2) {
    return Object.assign(Object.assign(Object.assign({}, r1), r2), { edited: r1.edited || r2.edited ? true : r1.edited === false && r2.edited === false ? false : undefined, success: r1.success && r2.success });
}
//# sourceMappingURL=generator.js.map