/**
 * package-pull-trigger-snapshotGenerate.js
 * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
 *
 * Contact:
 * DongHee Yang <donghee.yang@samsung.com>
 * Sungmin Kim <sm.art.kim@samsung.com>
 * Jiil Hyoun <jiil.hyoun@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');
var DError = require('../../core/exception.js');


module.exports.addTrigger = addTrigger;
module.exports.searchTrigger = searchTrigger;
module.exports.modifyTrigger = modifyTrigger;
module.exports.removeTrigger = removeTrigger;


function getPackagesFromPackagePullProject(pkgPullProj, callback) {
    var pkgList = [];
    var packages = [];

    if (!pkgPullProj.options || pkgPullProj.options.SOURCE_DIST_NAME === undefined) {
        return callback(new DError('PKGTRGR004'));
    }

    if (pkgPullProj.options.PACKAGES) {
        packages = pkgPullProj.options.PACKAGES;
    }

    if (packages.length === 0) {
        dibs.log.info('no packages for trigger event');
        return callback(null);
    }

    async.each(packages, function (pkg, cb) {
        if (pkg.type === 'project') {
            var condition = { name: pkg.name, distName: pkgPullProj.options.SOURCE_DIST_NAME };
            dibs.rpc.datamgr.searchProjects(condition, function (err, results) {
                if (err) {
                    cb(err);
                } else {
                    if (_.size(results) === 0) {
                        dibs.log.warn('[package trigger] cannot search projects using ' + pkg.name +
                            ' ... ' + pkgPullProj.distName + ':' + pkgPullProj.name);
                    } else {
                        var prj = results[0];
                        if (prj && prj.options.PKG_NAME) {
                            pkgList.push({name: prj.options.PKG_NAME, type: 'package'});
                        } else if (prj && prj.options.LAST_BUILD_INFO) {
                            _.each(prj.options.LAST_BUILD_INFO, function (value, key) {
                                var pkgNames = prj.options.LAST_BUILD_INFO[key].packageNames;

                                _.each(pkgNames, function (pkgName) {
                                    pkgList.push({name: pkgName, type: 'package'});
                                });
                            });
                        }
                    }
                    cb(null);
                }
            });
        } else {
            pkgList.push(pkg);
            cb(null);
        }
    },
    function (err) {
        callback(err, pkgList);
    });
}


function checkDistribution(distName, callback) {
    dibs.rpc.datamgr.searchDistributions({name: distName}, function (err, dists) {
        if (err) {
            callback(err);
        } else {
            if (_.size(dists) === 0) {
                dibs.log.warn('[package trigger] distributions are empty');
                callback(null, true);
            } else if (dists[0] && dists[0].status !== 'OPEN') {
                dibs.log.info('[package trigger] ' + dists[0].name +
                    ' distribution status: ' + dists[0].status);
                callback(null, true);
            } else {
                callback(null, false);
            }
        }
    });
}


function checkProject(projectId, callback) {
    dibs.rpc.datamgr.searchProjects({id: projectId}, function (err, prjs) {
        if (err) {
            callback(err, null);
        } else {
            if (_.size(prjs) === 0) {
                dibs.log.warn('[package trigger] projects are empty');
                callback(null, null);
            } else if (prjs[0] && prjs[0].status !== 'OPEN') {
                dibs.log.info('[package trigger] ' + prjs[0].distName + ':' + prjs[0].name + ' status: ' + prjs[0].status);
                callback(null, null);
            } else {
                dibs.log.info('[package trigger] search projects successfully! ' + prjs[0].distName + ':' + prjs[0].name);
                callback(err, prjs[0]);
            }
        }
    });
}


function addTrigger(trigger, callback) {
    if (!trigger || !trigger.data) {
        return callback(new DError('PKGTRGR001', { argument: 'trigger', value: trigger }));
    }

    async.waterfall([
        function (cb) {
            dibs.rpc.datamgr.searchProjects({id: trigger.data.projectId}, function (err, projects) {
                if (err) {
                    cb(err, null);
                } else {
                    if (_.size(projects) === 0) {
                        cb(new DError('PKGTRGR002', { id: trigger.data.projectId }), null);
                    } else {
                        cb(err, _.clone(projects[0]));
                    }
                }
            });
        },
        function (project, cb) {
            if (!project.options || project.options.SOURCE_DIST_NAME === undefined) {
                return cb(new DError('PKGTRGR004'), null);
            }

            var repoServerList = dibs.getServersByType('repo');
            var repo = repoServerList[0];

            repo.addEventListener('TIZEN_REPO_SNAPSHOT_GENERATED',
                { distributionName: project.options.SOURCE_DIST_NAME },
                function (evtObj, cb1) {
                    var updatedPkgs = [];
                    var projectId = trigger.data.projectId;

                    dibs.log.info('[package trigger] execute trigger routine... ' + project.distName + ',' + project.name);

                    if (evtObj.updatedPackages && evtObj.updatedPackages.length > 0) {
                        updatedPkgs = evtObj.updatedPackages;
                    } else {
                        dibs.log.info('there are no updated packages');
                        return cb1(null);
                    }

                    async.waterfall([
                        function (cb2) {
                            checkDistribution(project.distName, cb2);
                        },
                        function (skippingTrigger, cb2) {
                            if (skippingTrigger) {
                                dibs.log.info('[package trigger] skipping trigger for ' +
                                    project.distName + ':' + project.name);
                                cb2(null, null);
                            } else {
                                checkProject(projectId, cb2);
                            }
                        },
                        function (pkgPullProj, cb2) {
                            if (!pkgPullProj) {
                                cb2(null, []);
                            } else {
                                getPackagesFromPackagePullProject(pkgPullProj, function (err, triggerPackages) {
                                    if (err) {
                                        cb2(err);
                                    } else {
                                        if (_.size(triggerPackages) === 0) {
                                            dibs.log.info('[package trigger] there are no packages for trigger ...' +
                                                pkgPullProj.distName + ':' + pkgPullProj.name);
                                            cb2(null);
                                        } else {
                                            var matchedPkgs = _.map(updatedPkgs, function (pkg) {
                                                return _.findWhere(triggerPackages, {name: pkg.name});
                                            });

                                            if (matchedPkgs && _.size(_.compact(matchedPkgs)) > 0) {
                                                dibs.rpc.jobmgr.addJob('sync-manager@user', pkgPullProj.distName, pkgPullProj.name, '',
                                                    { environment: pkgPullProj.environments }, cb2);
                                            } else {
                                                dibs.log.info('[package trigger] there are no identical packages between updated and package-pull ...' +
                                                    pkgPullProj.distName + ':' + pkgPullProj.name);
                                                dibs.log.info('[package trigger] matching packages');
                                                dibs.log.info(matchedPkgs);
                                                dibs.log.info(_.compact(matchedPkgs));
                                                cb2(null);
                                            }
                                        }
                                    }
                                });
                            }
                        }
                    ],
                    function (err) {
                        if (err) {
                            dibs.log.error(err);
                        }
                        cb1(err);
                    });
                },
                function (err, listener) {
                    if (err) {
                        dibs.log.info(err);
                    }
                    cb(err, listener);
                }
            );
        }
    ],
    function (err, result) {
        if (err) {
            dibs.log.error(err);
        }
        callback(err, result);
    });
}


function removeTrigger(trigger, callback) {
    var eventListener = null;

    if (trigger && trigger.listenerObj) {
        var repoServerList = dibs.getServersByType('repo');
        var repo = repoServerList[0];

        eventListener = trigger.listenerObj;
        repo.removeEventListener(eventListener, callback);
    } else {
        callback(null);
    }
}


function searchTrigger(trigger, callback) {
    var eventListener = null;

    if (trigger && trigger.listenerObj) {
        var repoServerList = dibs.getServersByType('repo');
        var repo = repoServerList[0];

        eventListener = trigger.listenerObj;

        repo.getEventListeners(eventListener, callback);
    } else {
        callback(null);
    }
}


function modifyTrigger(trigger, callback) {
    callback(null);
}
