/*jslint node: true */
'use strict';

var lodash = require('lodash'),
    request = require('./request'),
    save = require('./save'),
    schema = require('./schema'),
    validate = require('./validate'),
    yaml = require('yamljs'),
    tasks = {
        standard: [
            'loadPlan',
            'validatePlan',
            'loadSchemas',
            'loadRequestList',
            'preValidateRequests',
            'prepareRequest',
            'validateRequests',
            'request',
            'save',
            'validate'
        ]
    },

ATask = {
    run: function (F, cb) {
        ATask.reduce(F, ATask.list().concat([cb]));
    },
    list: function (N) {
        return lodash.map(tasks[N || 'standard'], function (T) {
            ATask[T].taskname = T;
            return ATask[T];
        });
    },
    loadSchemas: function (C, next) {
        var I = 0;
        if (C.schemaDir) {
            lodash.map(schema.loadRelativeFile(C.schemaDir), function (S, N) {
                C.schemas[N] = S;
                I++;
            });
            if (C.verbose > 1) {
                console.warn(' ' + I + ' JSON schema loaded from ' + C.schemaDir);
            }
        } else {
            if (C.verbose > 1) {
                console.warn(' (No schemaDir in the plan)');
            }
        }

        C.selfVerify = validate.selfVerify(C.schemas);
        lodash.map(C.selfVerify, function () {
            C.abort = true;
        });

        next(C);
    },
    loadPlan: function (F, next) {
        yaml.load(F, function (D) {
            if (D) {
                D.schemas = schema.loadCoreSchemas();
                D.planName = F;
            } else {
                D = {
                    error: 'Can not load plan yaml file: "' + F + '"',
                    abort: true,
                    pass: false,
                    planName: F
                };
            }
            if (!D.requestConfig) {
                D.requestConfig = {};
            }
            if (!D.requestConfig.yqlConfig) {
                D.requestConfig.yqlConfig = {};
            }
            if (!D.requestConfig.yqlConfig.endpoint) {
                D.requestConfig.yqlConfig.endpoint  = 'https://query.yahooapis.com/v1/public/yql';
            }
            if (!D.requestConfig.yqlConfig.qs) {
                D.requestConfig.yqlConfig.qs = {};
            }
            D.requestConfig.yqlConfig.json = true;
            D.requestConfig.yqlConfig.qs.format = 'json';
            D.requestConfig.yqlConfig.qs.diagnostics = true;

            D.tasks = {};
            next(D);
        });
    },
    validatePlan: function (C, next) {
        var E = validate.one({
            data: C,
            schemas: C.schemas,
            schema: schema.coreURL + 'plan.json#'
        }, {useDefault: true});

        if (E) {
            C.error = E;
            C.abort = true;
        }

        next(C);
    },
    prepareRequest: function (C, next) {
        var helper = require(C.requestHelper);

        C.requests = lodash.map(C.requests, function (R) {
            return helper(R, C);
        });
        next(C);
    },
    validateRequestsTask: function (C, schema) {
        var E = validate.one({
            data: C.requests,
            schemas: C.schemas,
            schema: schema
        });

        if (E) {
            C.error = E;
            C.abort = true;
        }

        return C;
    },
    validateRequests: function (C, next) {
        next(ATask.validateRequestsTask(C, schema.coreURL + 'requests.json#/definitions/processed'));
    },
    preValidateRequests: function (C, next) {
        next(ATask.validateRequestsTask(C, schema.coreURL + 'requests.json#'));
    },
    reduce: function (D, tasks) {
        var task = tasks.shift();

        if (D.verbose) {
            process.stderr.write('.');
        }
        if (D.abort) {
            console.warn('Abort!');
            task = tasks.pop();
            lodash.map(tasks, function (F) {
                D.tasks[F.taskname] = false;
            });
            tasks = [];
        }
        if (lodash.isFunction(task)) {
            if (task.taskname) {
                if (D.tasks) {
                    D.tasks[task.taskname] = D.abort ? false : true;
                }
                if (D.verbose > 1) {
                    process.stderr.write('[Task] ' + task.taskname + ' .');
                }
            }
            task(D, function (R) {
                if (D.verbose > 1) {
                    console.warn('...done');
                }
                ATask.reduce(R, tasks);
            });
        }
    },
    loadRequestList: function (C, next) {
        yaml.load(C.requestYaml, function (D) {
            C.requests = [];
            lodash.map(D, function (R) {
                var RR;
                if (C.requestConfig) {
                    RR = lodash.cloneDeep(C.requestConfig);
                    lodash.map(R, function (V, K) {
                        RR[K] = V;
                    });
                    C.requests.push(RR);
                } else {
                    C.requests.push(R);
                }
            });
            if (C.verbose > 1) {
                console.warn('All ' + C.requests.length + ' requests loaded.');
            }
            next(C);
        });
    },
    request: function (C, next) {
        request.all(C.requests, {
            concurrency: C.concurrency,
            verbose: C.verbose
        }, function (D) {
            C.results = D;
            next(C);
        });
    },
    save: function (C, next) {
        var O = C.saveSpace ? C[C.saveSpace] : C;

        O.saveError = save.all(O.results, C);
        O.savedFiles = O.saveError._filenames;
        delete O.saveError._filenames;
        next(C);
    },
    validate: function (C, next) {
        C.validates = {};
        C.passed = 0;
        C.failed = 0;
        lodash.map(C.results, function (R, I) {
            var E = validate.one({
                data: R,
                schemas: C.schemas,
                schema: (R.body && R.body.schema) ? R.body.schema : R.input.schema
            });
            if (E) {
                C.validates[C.savedFiles[I]] = E;
                C.failed++;
            } else {
                C.passed++;
            }
        });
        C.pass = (C.failed === 0);
        if (C.verbose > 1) {
            if (C.pass) {
                console.warn(' :) All ' + C.passed + ' requests passed JSON Schema validation!');
            } else {
                console.warn(' :( ' + C.failed + ' requests failed JSON Schema validation!!');
            }
        }
        next(C);
    }
};

module.exports = ATask;

@@ -5664,16 +5664,41 @@
 %5D : C;%0A%0A
+console.warn(O.results);%0A
         

add console.warn to debug on travis