"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var lang_1 = require("@dojo/core/lang");
var Environment_1 = require("./Environment");
function resolveEnvironments(capabilities, environments, available) {
    environments = environments.map(function (environment) {
        var serialized = JSON.stringify(environment);
        return JSON.parse(serialized.replace(/{pwd}/g, process.cwd()));
    });
    var flatEnvironments = createPermutations(capabilities, environments);
    var expandedEnvironments = flatEnvironments.map(function (environment) {
        return lang_1.mixin({}, environment, {
            version: resolveVersions(environment, available)
        });
    });
    return createPermutations({}, expandedEnvironments).map(function (environment) {
        return new Environment_1.default(environment);
    });
}
exports.default = resolveEnvironments;
function ascendingNumbers(a, b) {
    var na = Number(a);
    var nb = Number(b);
    if (!isNaN(na) && !isNaN(nb)) {
        return na - nb;
    }
    if (a < b) {
        return -1;
    }
    if (a > b) {
        return 1;
    }
    return 0;
}
function expandVersionRange(left, right, availableVersions) {
    if (availableVersions.indexOf(left) === -1 || availableVersions.indexOf(right) === -1) {
        throw new Error('The version range ' + left + '..' + right + ' is unavailable');
    }
    return availableVersions.filter(function (version) {
        return version >= left && version <= right;
    });
}
function resolveVersionAlias(version, availableVersions) {
    var pieces = version.split('-');
    if (pieces.length > 2) {
        throw new Error('Invalid alias syntax "' + version + '"');
    }
    pieces = pieces.map(function (piece) {
        return piece.trim();
    });
    if ((pieces.length === 2 && (pieces[0] !== 'latest' || isNaN(Number(pieces[1])))) ||
        (pieces.length === 1 && isNaN(Number(pieces[0])) && pieces[0] !== 'latest')) {
        throw new Error('invalid alias syntax "' + version + '"');
    }
    if (pieces[0] === 'latest') {
        var offset = pieces.length === 2 ? Number(pieces[1]) : 0;
        if (offset > availableVersions.length) {
            var message = 'Can\'t get ' + version + '; ' + availableVersions.length + ' version';
            message += (availableVersions.length !== 1 ? 's are' : ' is') + ' available';
            throw new Error(message);
        }
        return availableVersions[availableVersions.length - 1 - offset];
    }
    else {
        return pieces[0];
    }
}
function splitVersions(versionSpec) {
    var versions = versionSpec.split('..');
    if (versions.length > 2) {
        throw new Error('Invalid version syntax');
    }
    return versions.map(function (version) {
        return version.trim();
    });
}
function getVersions(environment, available) {
    var versions = {};
    available.filter(function (availableEnvironment) {
        return !Object.keys(environment).filter(function (key) {
            return key !== 'version';
        }).some(function (key) {
            return (key in availableEnvironment) && availableEnvironment[key] !== environment[key];
        });
    }).forEach(function (availableEnvironment) {
        versions[availableEnvironment.version] = true;
    });
    return Object.keys(versions).sort(ascendingNumbers);
}
function resolveVersions(environment, available) {
    var versionSpec = environment.version;
    var versions;
    available = available || [];
    if (versionSpec && isNaN(Number(versionSpec))) {
        var availableVersions_1 = getVersions(environment, available);
        versions = splitVersions(versionSpec).map(function (version) {
            return resolveVersionAlias(version, availableVersions_1);
        });
        if (versions.length === 2) {
            if (versions[0] > versions[1]) {
                throw new Error('Invalid range [' + versions + '], must be in ascending order');
            }
            versions = expandVersionRange(versions[0], versions[1], availableVersions_1);
        }
        return versions;
    }
    return versionSpec;
}
function createPermutations(base, sources) {
    if (!sources || sources.length === 0) {
        return [lang_1.mixin({}, base)];
    }
    return sources.map(function (source) {
        return Object.keys(source).reduce(function (permutations, key) {
            if (Array.isArray(source[key])) {
                permutations = source[key].map(function (value) {
                    return permutations.map(function (permutation) {
                        return lang_1.mixin({}, permutation, (_a = {}, _a[key] = value, _a));
                        var _a;
                    });
                }).reduce(function (newPermutations, keyPermutations) {
                    return newPermutations.concat(keyPermutations);
                }, []);
            }
            else {
                permutations.forEach(function (permutation) {
                    permutation[key] = source[key];
                });
            }
            return permutations;
        }, [lang_1.mixin({}, base)]);
    }).reduce(function (newPermutations, sourcePermutations) { return newPermutations.concat(sourcePermutations); }, []);
}
//# sourceMappingURL=resolveEnvironments.js.map