/**
 * execute-test-automation.js
 * Copyright (c) 2000 - 2015 Samsung Electronics Co., Ltd. All rights reserved.
 *
 * Contact:
 * Sungmin Kim <sm.art.kim@samsung.com>
 * Jonghwan Park <iwin100.park@samsung.com>
 * Kitae Kim <kt920.kim@samsung.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Contributors:
 * - S-Core Co., Ltd
**/


var async = require('async');
var _ = require('underscore');

var dibs = require('../../../core/dibs.js');


module.exports.getIntegrationRunsList = getIntegrationRunsList;
module.exports.executeEvent = executeEvent;


function getIntegrationRunsList(eventType, subJobs) {
    // get all sub-job's post-evnets
    var subJobsPostEvents = _.map(subJobs, function (subJob) {
        return subJob.options.POST_BUILD || [];
    });

    // flatten
    subJobsPostEvents = _.flatten(subJobsPostEvents);

    // find matched event objects
    var events = _.where(subJobsPostEvents, { eventType: eventType });

    // merge project_names value
    var projectNameList = [];
    _.each(events, function (value) {
        projectNameList = _.union(projectNameList, value.property.PROJECT_NAMES.split(','));
    });

    if (projectNameList.length === 0) {
        return [];
    } else {
        // set return value & return
        var output = _.clone(events[0]);
        output.property.PROJECT_NAMES = _.uniq(projectNameList).toString();
        return output;
    }
}


/**
 * Execute evnet
 *  - execute test-automation proejct
 * @function executeEventForServer
 * @param {object} property - property
 * @param {module:models/job~Job} job - job
 * @param {object} monitor - monitor
 * @param {object} options - options
 * @param {module:lib/utils.callback_error} callback - callback(error)
 * @memberOf module:models/tizen-project/post-build/execute-test-automation
 */
function executeEvent(property, job, monitor, options, callback) {
    // validate
    if (job.parentId) {
        return callback(null);
    }

    var projectNameList = property.PROJECT_NAMES.replace(/(\s*)/g, '').split(',') || null;
    if (!projectNameList) {
        return callback(new Error('project name is not exists'));
    }

    var distributionName = job.distName || null;
    var snapshotName = job.snapshotName || null;
    var userEmail = job.userEmail || null;
    var resultFiles = job.resultFiles || null;
    if (!distributionName || !snapshotName || !userEmail || !resultFiles) {
        return callback(new Error('Can not find the input value'));
    }

    var parentJobId = job.id;
    var jenkinsArg = {};

    // main
    async.waterfall([
        function (cb) {
            monitor.updateProgress('*Execute Tizen Test-Automation Project*', cb);
        }, function (cb) {
            monitor.updateProgress(' - generate jenkins project\'s arguments:', cb);
        }, function (cb) {
            jenkinsArg.DISTRIBUTION = distributionName;
            jenkinsArg.SNAPSHOT = snapshotName;
            jenkinsArg.USER_EMAIL = userEmail;
            jenkinsArg.PACKAGE_LIST = _.map(resultFiles, function (file) {
                return file.split(/[/]+/).pop();
            }).toString();
            monitor.updateProgress('  -- ' + JSON.stringify(jenkinsArg), cb);
        }, function (cb) {
            monitor.updateProgress(' - add test-automation job', cb);
        }, function (cb) {
            var buildOpts = {
                JENKINS_ARG: jenkinsArg
            };
            async.mapSeries(_.uniq(projectNameList), function (projectName, cb1) {
                dibs.rpc.jobmgr.addSubJob(parentJobId, projectName, 'ubuntu-32', buildOpts, function (err1, jobId) {
                    if (err1) {
                        monitor.updateProgress(' -- failed add job: ' + err1.message);
                    } else {
                        monitor.updateProgress(' -- added Job #' + jobId);
                    }
                    cb1(null, jobId || '');
                });
            }, cb);
        }, function (results, cb) {
            var subJobIds = _.filter(results, function (result) {
                return result !== '';
            });
            updateSubJobs(job, subJobIds, cb);
        }, function (cb) {
            monitor.updateProgress(' - wait for test-automation job(s) finished', cb);
        }, function (cb) {
            waitForSubJobsFinished(job, monitor, cb);
        }, function (cb) {
            var subJobIds = job.subJobs.map(function (subJob) {
                return subJob.id;
            });
            updateSubJobs(job, subJobIds, cb);
        }], callback);
}

function updateSubJobs(parentJob, subJobIds, callback) {
    async.mapLimit(subJobIds, 5,
        function (jobId, cb) {
            dibs.rpc.jobmgr.queryJob(jobId, cb);
        },
        function (err, sjobs) {
            if (!err) {
                parentJob.subJobs = sjobs;
                parentJob.options.packages = [];
                // update result pkgs
                for (var i = 0; i < sjobs.length; i++) {
                    parentJob.options.packages = parentJob.options.packages.concat(sjobs[i].options.packages);
                }
            }
            callback(err);
        });
}

function waitForSubJobsFinished(job, monitor, callback) {
    if (job.subJobs.length === 0) {
        return callback(null);
    }
    async.each(job.subJobs, function (subJob, cb) {
        dibs.rpc.jobmgr.waitForJobStatus(subJob.id, 'FINISHED', function (err, status) {
            if (err) {
                if (status && status !== 'FINISHED') {
                    monitor.updateProgress(' - failed with status \'' + status + '\' ...' + subJob.id, cb);
                } else {
                    monitor.updateProgress(' - failed with error \'' + err.errno + '\' ...' + subJob.id, cb);
                }
            } else {
                monitor.updateProgress(' - succeeded ...' + subJob.id, cb);
            }
        });
    }, callback);
}
