"use strict";
var task_utils_1 = require('./task.utils');
var watch_preprocess_1 = require("./watch.preprocess");
var watch_errors_1 = require("./watch.errors");
var blacklist = ['options', 'bs-config', 'before', 'id'];
var _ = require('../lodash.custom');
exports.defaultWatchOptions = {
    ignoreInitial: true,
    block: false,
    throttle: 0,
    delay: 0,
    debounce: 0
};
/**
 * Create a single watch task item consisting of
 *  - patterns
 *  - tasks
 *  - options
 */
function createOne(name, index, item, itemOptions, globalOptions) {
    if (task_utils_1.isPlainObject(item)) {
        if (item.patterns && item.tasks) {
            return {
                patterns: [].concat(item.patterns).reduce(function (a, x) { return a.concat(x.split(':')); }, []),
                tasks: [].concat(item.tasks),
                options: _.merge({}, exports.defaultWatchOptions, globalOptions, itemOptions),
                watcherUID: name + "-" + index
            };
        }
    }
    return item;
}
/**
 * @param watchTaskParent
 * @param globalOptions
 * @returns {*}
 */
function getFormattedTask(name, watchTaskParent, globalOptions) {
    /**
     * Simple mode is when patterns + tasks given as top-level
     * keys. This means we automatically just into simple mode
     *  eg:
     *      default: {
     *          patterns: ['*.json']
     *          tasks: ['*.json']
     * }
     *
     */
    if (watchTaskParent.patterns && watchTaskParent.tasks) {
        return [createOne(name, 0, watchTaskParent, watchTaskParent.options, globalOptions)];
    }
    /**
     * Look at each key provided to decide if it can
     * be transformed into a watcher obj
     */
    return Object.keys(watchTaskParent)
        .filter(function (x) { return blacklist.indexOf(x) === -1; })
        .reduce(function (all, item, index) {
        /**
         * Here we assume the long-hand version is being
         * used where the watchers property is provided.
         * If it is, that means we can create a watcher
         * object for each item in the 'watchers' array
         * eg:
         *
         * default:
         *   options:
         *     exclude: '*.html'
         *   before: ['bs']
         *   watchers:
         *     - patterns: ['test/fixtures']
         *       tasks:    ['1', '2']
         *     - patterns: ['*.css']
         *       tasks:    '3'
         */
        if (item === 'watchers') {
            /**
             * If the `watcher` property is an Array, it must
             * be an Array of Objects, so process each one individually.
             * eg:
             *  default:
             *      watchers: [
             *          {
             *              patterns: ["scss/**", "css/*.scss"],
             *              tasks:    ["$npm node-sass"],
             *          }
             *      ]
             */
            if (Array.isArray(watchTaskParent.watchers)) {
                return all.concat(watchTaskParent.watchers.map(function (watcher, i) {
                    return createOne(name, i, watcher, watchTaskParent.options, globalOptions);
                }));
            }
            /**
             * If the `watchers` property is a plain object,
             * use it's keys as watch patterns and the values as
             * tasks.
             * eg:
             *  default:
             *      watchers: {
             *          "*.js":   ["$npm eslint"],
             *          "*.scss": ["$npm node-sass"]
             *      }
             */
            if (task_utils_1.isPlainObject(watchTaskParent.watchers)) {
                return Object.keys(watchTaskParent.watchers)
                    .map(function (key, i) { return createOne(name, i, {
                    patterns: key,
                    tasks: watchTaskParent.watchers[key]
                }, watchTaskParent.options, globalOptions); });
            }
        }
        /**
         * At this point assume that the short-hard pattern <pattern>:<tasks>
         *  eg:
         *      "*.js": ['uglify']
         */
        return all.concat(createOne(name, index, {
            patterns: item,
            tasks: watchTaskParent[item] // value as the tasks array
        }, watchTaskParent.options, globalOptions));
    }, []);
}
function createFlattenedWatchTask(taskName, trigger) {
    var globalOptions = _.assign({}, trigger.input.watch.options, {
        block: trigger.config.block
    });
    var incoming = watch_preprocess_1.preprocessWatchTask(taskName);
    var selection = trigger.input.watch[incoming.taskName] || {};
    var watchers = getFormattedTask(incoming.taskName, selection, globalOptions);
    var errors = watch_errors_1.gatherWatchTaskErrors(incoming, trigger.input);
    return {
        name: taskName,
        before: selection.before || [],
        options: selection.options || {},
        watchers: watchers,
        errors: errors
    };
}
function validateTask(task, trigger) {
    return task.errors.length === 0;
}
function resolveWatchTasks(taskNames, trigger) {
    var taskList = taskNames
        .map(function (taskName) {
        return createFlattenedWatchTask(taskName, trigger);
    });
    /**
     * Return both valid & invalid tasks. We want to let consumers
     * handle errors/successes
     * @type {{valid: Array, invalid: Array}}
     */
    var output = {
        valid: taskList.filter(function (x) { return validateTask(x, trigger); }),
        invalid: taskList.filter(function (x) { return !validateTask(x, trigger); }),
        all: taskList
    };
    return output;
}
exports.resolveWatchTasks = resolveWatchTasks;
/**
 * The goal of this function is to produce a flat array containing tasks as strings
 * this allows us to feed that into the task resolution stuff
 */
function resolveBeforeTasks(beforeFlagsFromCliOrConfig, input, watchTasks) {
    var fromTopLevelInput = [].concat(input.watch.before);
    var fromWatchTasks = watchTasks.reduce(function (acc, item) {
        return acc.concat(item.before);
    }, []);
    return beforeFlagsFromCliOrConfig.concat(fromTopLevelInput, fromWatchTasks).filter(Boolean);
}
exports.resolveBeforeTasks = resolveBeforeTasks;
//# sourceMappingURL=watch.resolve.js.map