"use strict";
var Rx = require('rx');
var reporter_resolve_1 = require("./reporter.resolve");
var task_resolve_1 = require('./task.resolve');
var Immutable = require('immutable');
var seq = require("./task.sequence");
var command_run_interactive_1 = require('./command.run.interactive');
var command_run_execute_1 = require("./command.run.execute");
var command_run_execute_2 = require("./command.run.execute");
var debug = require('debug')('cb:command.run');
var merge = require('../lodash.custom').merge;
(function (TriggerTypes) {
    TriggerTypes[TriggerTypes["command"] = "command"] = "command";
    TriggerTypes[TriggerTypes["watcher"] = "watcher"] = "watcher";
})(exports.TriggerTypes || (exports.TriggerTypes = {}));
var TriggerTypes = exports.TriggerTypes;
function getRunCommandSetup(trigger) {
    var cliInput = trigger.cli.input.slice(1);
    /**
     * Task Tracker for external observers
     * @type {Subject<T>}
     */
    trigger.tracker = new Rx.Subject();
    trigger.tracker$ = trigger.tracker.share();
    /**
     * First Resolve the task names given in input.
     */
    var tasks = task_resolve_1.resolveTasks(cliInput, trigger);
    var topLevelParallel = tasks.all.some(function (task) {
        return task.runMode === task_resolve_1.TaskRunModes.parallel;
    });
    /**
     * If only 1 task is being run, check if any sub-tasks
     * are trying to be run in parallel mode and if so, set the runMode
     * This is done to ensure if a child errors, it doesn't affect children.
     * (as it's only a single task via the cli, it wouldn't be expected)
     */
    if (cliInput.length === 1 && topLevelParallel) {
        trigger.config.runMode = task_resolve_1.TaskRunModes.parallel;
    }
    /**
     * All this point, all given task names have been resolved
     * to either modules on disk, or @adaptor tasks, so we can
     * go ahead and create a flattened run-sequence
     */
    var sequence = seq.createFlattenedSequence(tasks.valid, trigger);
    /**
     * With the flattened sequence, we can create nested collections
     * of Rx Observables
     */
    var runner = seq.createRunner(sequence, trigger);
    /**
     * Check if the user intends to handle running the tasks themselves,
     * if thats the case we give them the resolved tasks along with
     * the sequence and the primed runner
     */
    return { tasks: tasks, sequence: sequence, runner: runner };
}
exports.getRunCommandSetup = getRunCommandSetup;
function handleIncomingRunCommand(cli, input, config, reporter) {
    /**
     * Array of top-level task names that are available
     */
    var topLevelTasks = Object.keys(input.tasks);
    /**
     * The shared Map that tasks can read/write to
     */
    var sharedMap = new Rx.BehaviorSubject(Immutable.Map({}));
    var type = TriggerTypes.command;
    debug('top level tasks available', topLevelTasks);
    // if (config.handoff) {
    //     return getRunCommandSetup({
    //         shared: sharedMap,
    //         cli,
    //         input,
    //         config,
    //         reporter,
    //         type
    //     });
    // }
    /**
     * If the interactive flag was given (-i), always try
     * that first.
     */
    if (config.interactive) {
        return enterInteractive();
    }
    /**
     * If the user never provided a task then we either look
     * for a `default` task or enter interactive mode if possible
     * eg:
     *  $ crossbow run
     */
    if (cli.input.length === 1) {
        /**
         * First look if there's a 'default' task defined
         */
        if (hasDefaultTask()) {
            var cliMerged = merge({}, cli, { input: ['run', 'default'] });
            return Rx.Observable.just(command_run_execute_1.default({
                shared: sharedMap,
                cli: cliMerged,
                input: input,
                config: config,
                reporter: reporter,
                type: TriggerTypes.command
            }));
        }
        /**
         * If no default task was found above, enter interactive mode
         */
        return enterInteractive();
    }
    /**
     * Check if the provided input contains either
     * 'default' or 'default@p' etc
     */
    function hasDefaultTask() {
        if (task_resolve_1.maybeTaskNames(input.tasks, 'default').length) {
            return true;
        }
        if (input.tasks['default'] !== undefined) {
            return true;
        }
    }
    /**
     * If no task given, or if user has selected interactive mode,
     * show the UI for task selection
     */
    function enterInteractive() {
        /**
         * No top level tasks, so exit with the correct error
         */
        if (!topLevelTasks.length) {
            reporter({ type: reporter_resolve_1.ReportTypes.NoTasksAvailable });
            return Rx.Observable.just({
                setup: {
                    sequence: [],
                    tasks: { all: [], valid: [], invalid: [] },
                    errors: [{ type: command_run_execute_2.RunCommandReportTypes.NoTasks }]
                },
                update$: Rx.Observable.empty()
            });
        }
        /**
         * Log that no tasks were provided
         */
        reporter({ type: reporter_resolve_1.ReportTypes.NoTasksProvided });
        /**
         * Now prompt for input
         */
        return command_run_interactive_1.default(cli, input, config, reporter)
            .flatMap(function (answers) {
            var cliMerged = merge({}, cli, { input: ['run'].concat(answers.tasks) });
            var configMerged = merge({}, config, { runMode: task_resolve_1.TaskRunModes.parallel });
            return Rx.Observable.just(command_run_execute_1.default({
                shared: sharedMap,
                cli: cliMerged,
                input: input,
                reporter: reporter,
                config: configMerged,
                type: type
            }));
        });
    }
    /**
     * If we reach here we're dealing with the default case
     * where we are simply executing the command as normal
     * eg:
     *  $ crossbow run task1 task2@p etc ...
     */
    return Rx.Observable.just(command_run_execute_1.default({
        shared: sharedMap,
        cli: cli,
        input: input,
        config: config,
        reporter: reporter,
        type: type
    }));
}
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = handleIncomingRunCommand;
//# sourceMappingURL=command.run.js.map