"use strict";
var command_run_1 = require("./command.run");
var reporter_resolve_1 = require("./reporter.resolve");
var task_resolve_1 = require("./task.resolve");
var task_runner_1 = require("./task.runner");
var fs_1 = require("fs");
var path_1 = require("path");
var Rx = require('rx');
var seq = require("./task.sequence");
var command_run_context_1 = require("./command.run.context");
var debug = require('debug')('cb:command.run.execute');
(function (RunCommandReportTypes) {
    RunCommandReportTypes[RunCommandReportTypes["InvalidTasks"] = "InvalidTasks"] = "InvalidTasks";
    RunCommandReportTypes[RunCommandReportTypes["Complete"] = "Complete"] = "Complete";
})(exports.RunCommandReportTypes || (exports.RunCommandReportTypes = {}));
var RunCommandReportTypes = exports.RunCommandReportTypes;
function executeRunCommand(trigger) {
    var cli = trigger.cli, input = trigger.input, config = trigger.config, reporter = trigger.reporter;
    var _a = command_run_1.getRunCommandSetup(trigger), tasks = _a.tasks, sequence = _a.sequence, runner = _a.runner;
    if (trigger.config.dump) {
        fs_1.writeFileSync(path_1.join(trigger.config.cwd, "_tasks.json"), JSON.stringify(tasks, null, 2));
        fs_1.writeFileSync(path_1.join(trigger.config.cwd, "_sequence.json"), JSON.stringify(sequence, null, 2));
        fs_1.writeFileSync(path_1.join(trigger.config.cwd, "_config.json"), JSON.stringify(trigger.config, null, 2));
    }
    /**
     * Never continue if any tasks were flagged as invalid and we've not handed
     * off
     */
    if (tasks.invalid.length) {
        reporter(reporter_resolve_1.ReportNames.TaskErrors, tasks.all, cli.input.slice(1), input, config);
        return Rx.Observable.concat(Rx.Observable.just({
            type: RunCommandReportTypes.InvalidTasks,
            tasks: tasks,
            sequence: sequence,
            runner: runner
        }), Rx.Observable.throw(new Error("RunCommandErrorTypes.InvalidTasks")));
    }
    debug("~ run mode from config in mode: '" + config.runMode + "'");
    /**
     * Report task list that's about to run
     */
    reporter(reporter_resolve_1.ReportNames.TaskList, sequence, cli, '', config);
    /**
     * Get a run context for this execution.
     * note: This could take some time as it may need
     * to hash directories etc. A run context is just a key=>value
     * map of read-only values.
     */
    var outgoing = command_run_context_1.default(tasks.all, trigger)
        .timestamp()
        .flatMap(function (x) { return run(x.value, x.timestamp); })
        .share();
    /**
     * Start the process
     */
    outgoing.subscribe();
    /**
     * Return the stream so a consumer can receive the RunCompletionReport
     */
    return outgoing;
    /**
     * Now actually execute the tasks.
     */
    function run(runContext, startTime) {
        /**
         * series/parallel running have VERY different characteristics
         * @type {Rx.Observable<TaskReport>|Rx.Observable<TaskReport>}
         */
        var mode = (function () {
            if (trigger.config.runMode === task_resolve_1.TaskRunModes.parallel) {
                return runner.parallel(runContext);
            }
            return runner.series(runContext);
        })();
        /**
         * Now add side effects
         */
        return mode
            .do(function (report) { return trigger.tracker.onNext(report); }) // propagate reports into tracker
            .do(function (report) {
            reporter(reporter_resolve_1.ReportNames.TaskReport, report, trigger);
        })
            .toArray()
            .timestamp()
            .flatMap(function (completion) { return handleCompletion(completion.value, completion.timestamp - startTime); });
    }
    /**
     * Because errors are handled by reports, task executions ALWAYS complete
     * and we handle that here.
     */
    function handleCompletion(reports, runtime) {
        /**
         * Merge sequence tree with Task Reports
         */
        var decoratedSequence = seq.decorateSequenceWithReports(sequence, reports);
        /**
         * Did any errors occur in this run?
         * @type {TaskReport[]}
         */
        var errors = reports.filter(function (x) { return x.type === task_runner_1.TaskReportType.error; });
        /**
         * Main summary report
         */
        reporter(reporter_resolve_1.ReportNames.Summary, decoratedSequence, cli, 'Total: ', config, runtime);
        /**
         * If an error occurred, we need to exit the process
         * with any error codes if given
         */
        if (errors.length > 0 && config.fail) {
            var lastError = errors[errors.length - 1];
            var stats = lastError.stats;
            if (stats.cbExitCode !== undefined) {
                process.exit(stats.cbExitCode);
            }
            process.exit(1);
        }
        /**
         * Push a 'Completion report' onto the $complete Observable.
         * This means consumers will get everything when they call
         */
        return Rx.Observable.just({
            type: RunCommandReportTypes.Complete,
            reports: reports,
            tasks: tasks,
            sequence: sequence,
            runner: runner,
            decoratedSequence: decoratedSequence,
            runtime: runtime
        });
    }
}
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = executeRunCommand;
//# sourceMappingURL=command.run.execute.js.map