#!/usr/bin/env node
"use strict";
var cli_1 = require("./cli");
var fs_1 = require("fs");
var index_1 = require("./index");
var logger_1 = require("./logger");
var Rx = require('rx');
var index_2 = require("./index");
var file = require("./file.utils");
var config_1 = require("./config");
var reporter_resolve_1 = require("./reporter.resolve");
var task_runner_1 = require("./task.runner");
var seq = require("./task.sequence");
var debug = require('debug')('cb:cli');
var parsed = cli_1.default(process.argv.slice(2));
var cliOutputObserver = new Rx.Subject();
cliOutputObserver.subscribe(function (report) {
    report.data.forEach(function (x) {
        logger_1.default.info(x);
    });
});
var cliSignalObserver = new Rx.Subject();
if (parsed.execute) {
    runFromCli(parsed, cliOutputObserver, cliSignalObserver);
}
else {
    if (parsed.cli.flags.version) {
        console.log(parsed.output[0]);
    }
    else {
        if (parsed.output.length) {
            cliOutputObserver.onNext({
                origin: reporter_resolve_1.ReportTypes.CLIParserOutput,
                data: parsed.output
            });
        }
    }
}
function runFromCli(parsed, cliOutputObserver, cliSignalObserver) {
    var prepared = index_2.prepareInput(parsed.cli, null, cliOutputObserver, cliSignalObserver);
    /**
     * Handle file-writes
     * @type {Rx.Observable<CBSignal<FileWriteSignal>>|Rx.Observable<T>}
     */
    cliSignalObserver
        .filter(function (x) { return x.type === config_1.SignalTypes.FileWrite; })
        .do(function (x) {
        if (prepared.config.dryRun) {
        }
        else {
            file.writeFileToDisk(x.data.file, x.data.content);
        }
    }).subscribe();
    /**
     * Any errors found on input preparation
     * will be sent to the output observer and
     * requires no further work other than to exit
     * with a non-zero code
     */
    if (prepared.errors.length) {
        return process.exit(1);
    }
    if (parsed.cli.command === 'run') {
        var setUp$_1 = new Rx.BehaviorSubject({});
        var progress$_1 = new Rx.BehaviorSubject([]);
        var summaryGiven_1 = false; // todo remove the need for this as it breaks the encapsulation
        var exitSignal$ = cliSignalObserver
            .filter(function (x) { return x.type === config_1.SignalTypes.Exit; })
            .do(function (cbSignal) { return prepared.reportFn({ type: reporter_resolve_1.ReportTypes.SignalReceived, data: cbSignal.data }); })
            .withLatestFrom(setUp$_1, progress$_1, function (signal, setup, reports) {
            return { reports: reports, setup: setup, signal: signal };
        });
        var exits$ = Rx.Observable.zip(Rx.Observable.just(true).timestamp(prepared.config.scheduler), exitSignal$.timestamp(prepared.config.scheduler), function (begin, signal) {
            return { begin: begin, signal: signal };
        }).do(function (incoming) {
            var signal = incoming.signal, begin = incoming.begin;
            var setup = signal.value.setup;
            var reports = signal.value.reports;
            var startTime = begin.timestamp;
            var endTime = signal.timestamp;
            /**
             * Main summary report, although here it could be partial
             * (as an exit command could occur at any time)
             */
            if ((setup.tasks.valid.length * 2) !== reports.length) {
                if (!summaryGiven_1) {
                    summaryGiven_1 = true;
                    handleCompletion(reports, setup, endTime - startTime);
                }
            }
            else {
                console.log('Exit signal, but summary given from main handler');
            }
        });
        var reports$ = index_1.handleIncoming(prepared)
            .do(function (x) { return setUp$_1.onNext(x.setup); }) // first item is the setup
            .flatMap(function (x) {
            if (x.setup.errors.length) {
                console.log('Error in setup', x.setup.errors);
                return Rx.Observable.empty();
            }
            return x.update$;
        })
            .do(function (x) { return progress$_1.onNext(progress$_1.getValue().concat(x)); })
            .do(function (report) {
            prepared.reportFn({
                type: reporter_resolve_1.ReportTypes.TaskReport,
                data: {
                    report: report,
                    progress: prepared.config.progress
                }
            });
        })
            .takeUntil(exits$)
            .toArray()
            .filter(function (reports) { return reports.length > 0; })
            .timestamp(prepared.config.scheduler)
            .withLatestFrom(setUp$_1, function (incoming, setup) {
            return {
                setup: setup,
                reports: incoming.value,
                timestamp: incoming.timestamp
            };
        });
        Rx.Observable.zip(Rx.Observable.just(true).timestamp(prepared.config.scheduler), reports$, function (begin, result) {
            return { begin: begin, result: result };
        }).subscribe(function (incoming) {
            if (!summaryGiven_1) {
                summaryGiven_1 = true;
                handleCompletion(incoming.result.reports, incoming.result.setup, incoming.result.timestamp - incoming.begin.timestamp);
            }
        });
    }
    /**
     * Because errors are handled by reports, task executions ALWAYS complete
     * and we handle that here.
     */
    function handleCompletion(reports, setup, runtime) {
        /**
         * Merge sequence tree with Task Reports
         */
        var decoratedSequence = seq.decorateSequenceWithReports(setup.sequence, reports);
        /**
         * Push a 'Completion report' onto the $complete Observable.
         * This means consumers will get everything when they call
         */
        var errors = reports.filter(function (x) { return x.type === task_runner_1.TaskReportType.error; });
        var completeData = {
            errors: errors,
            runtime: runtime,
            taskErrors: errors,
            sequence: decoratedSequence,
            cli: prepared.cli,
            config: prepared.config
        };
        /**
         * Main summary report
         */
        prepared.reportFn({
            type: reporter_resolve_1.ReportTypes.Summary,
            data: completeData
        });
        require('./command.run.post-execution').postCliExecution(completeData);
    }
    if (parsed.cli.command === 'tasks' || parsed.cli.command === 'ls') {
        index_1.handleIncoming(prepared)
            .subscribe();
    }
    if (parsed.cli.command === 'docs') {
        index_1.handleIncoming(prepared)
            .pluck('setup')
            .subscribe(function (setup) {
            if (setup.errors.length) {
                return process.exit(1);
            }
            setup.output.forEach(function (outputItem) {
                file.writeFileToDisk(outputItem.file, outputItem.content);
            });
        });
    }
    if (parsed.cli.command === 'init') {
        index_1.handleIncoming(prepared)
            .pluck('setup')
            .subscribe(function (setup) {
            if (setup.errors.length) {
                return process.exit(1);
            }
            fs_1.writeFileSync(setup.outputFilePath, fs_1.readFileSync(setup.templateFilePath));
        });
    }
    if (parsed.cli.command === 'watchers') {
        index_1.handleIncoming(prepared)
            .pluck('setup')
            .subscribe(function (setup) {
            if (setup.errors.length) {
                return process.exit(1);
            }
        });
    }
    if (parsed.cli.command === 'watch') {
        index_1.handleIncoming(prepared)
            .flatMap(function (x) {
            if (x.setup.errors.length) {
                process.exit(1);
                return Rx.Observable.empty();
            }
            return x.update$;
        })
            .subscribe();
    }
}
//# sourceMappingURL=cb.js.map