"use strict";
var seq = require('./task.sequence');
var task_runner_1 = require("./task.runner");
var Rx = require("rx");
var reporter_resolve_1 = require("./reporter.resolve");
var debug = require('debug')('cb:watch.runner');
/**
 * Create a stream that is the combination of all watchers
 */
function createObservablesForWatchers(watchers, trigger) {
    var paused = [];
    var reporter = trigger.reporter;
    return Rx.Observable
        .merge(watchers.map(function (x) { return createObservableForWatcher(x, trigger.reporter); }))
        .filter(function (x) {
        if (x.runner.options.block && paused.indexOf(x.watcherUID) > -1) {
            debug('File change blocked');
            return false;
        }
        return true;
    })
        .do(function (x) {
        if (x.runner.options.block) {
            paused.push(x.watcherUID);
        }
    })
        .flatMap(function (watchEvent, i) {
        /** LOG **/
        reporter(reporter_resolve_1.ReportNames.WatcherTriggeredTasks, i, watchEvent.runner.tasks);
        /** LOG END **/
        var timer = new Date().getTime();
        var upcoming = watchEvent.runner._runner
            .series()
            .do(function (val) {
            // Push reports onto tracker
            // for cross-watcher reports
            trigger.tracker.onNext(val);
        })
            .do(function (x) {
            // todo - simpler/shorter format for task reports on watchers
            if (trigger.config.progress) {
                reporter(reporter_resolve_1.ReportNames.WatchTaskReport, x, trigger); // always log start/end of tasks
            }
            if (x.type === task_runner_1.TaskReportType.error) {
                console.log(x.stats.errors[0].stack);
            }
        })
            .toArray()
            .flatMap(function (reports) {
            var incoming = seq.decorateSequenceWithReports(watchEvent.runner._sequence, reports);
            var errorCount = seq.countSequenceErrors(incoming);
            /** LOG **/
            if (errorCount > 0) {
                reporter(reporter_resolve_1.ReportNames.Summary, incoming, trigger.cli, watchEvent.runner.tasks.join(', '), trigger.config, new Date().getTime() - timer);
            }
            else {
                reporter(reporter_resolve_1.ReportNames.WatcherTriggeredTasksCompleted, i, watchEvent.runner.tasks, new Date().getTime() - timer);
            }
            /** LOG END **/
            return Rx.Observable.just({ sequence: incoming, watchEvent: watchEvent });
        });
        return upcoming;
    })
        .do(function (completion) {
        paused = paused.filter(function (x) { return x !== completion.watchEvent.watcherUID; });
    });
}
exports.createObservablesForWatchers = createObservablesForWatchers;
/**
 * Create a file-system watcher that will emit <WatchEvent>
 */
function createObservableForWatcher(watcher, reporter) {
    /**
     * First create a stream of file-watcher events for this Watcher
     */
    var output$ = getRawOutputStream(watcher, reporter);
    /**
     * Specify a mapping from option name -> Rx.Observable operator name
     */
    var additionalOperators = [
        {
            option: 'debounce',
            fnName: 'debounce'
        },
        {
            option: 'throttle',
            fnName: 'throttle'
        },
        {
            option: 'delay',
            fnName: 'delay'
        }
    ];
    return applyOperators(output$, additionalOperators, watcher.options);
}
exports.createObservableForWatcher = createObservableForWatcher;
function getRawOutputStream(watcher, reporter) {
    /** DEBUG **/
    debug("[id:" + watcher.watcherUID + "] options: " + JSON.stringify(watcher.options, null, 2));
    /** DEBUG END **/
    return Rx.Observable.create(function (observer) {
        /** DEBUG **/
        debug("+ [id:" + watcher.watcherUID + "] " + watcher.patterns.length + " patterns (" + watcher.patterns + ")");
        debug("\u2514\u2500 " + watcher.tasks.length + " tasks (" + watcher.tasks + ")");
        /** DEBUG END **/
        var chokidarWatcher = require('chokidar').watch(watcher.patterns, watcher.options)
            .on('all', function (event, path) {
            observer.onNext({
                event: event,
                path: path,
                runner: watcher,
                watcherUID: watcher.watcherUID,
                duration: 0
            });
        });
        chokidarWatcher.on('ready', function () {
            /** DEBUG **/
            debug("\u221A [id:" + watcher.watcherUID + "] watcher ready (" + watcher.patterns + ")");
            /** DEBUG END **/
            if (Object.keys(chokidarWatcher.getWatched()).length === 0) {
                reporter(reporter_resolve_1.ReportNames.NoFilesMatched, watcher);
            }
        });
        return function () {
            debug("- for " + watcher.patterns);
            chokidarWatcher.close();
        };
    });
}
exports.getRawOutputStream = getRawOutputStream;
/**
 *
 */
function applyOperators(source, items, options) {
    return items.reduce(function (stream$, item) {
        var value = options[item.option];
        if (value !== undefined && value > 0) {
            return stream$[item.fnName].call(stream$, value);
        }
        return stream$;
    }, source);
}
//# sourceMappingURL=watch.file-watcher.js.map