/**
 * job-dep.js
 * Copyright (c) 2000 - 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 _ = require('underscore');
var dibs = require('../../core/dibs');
var Package = require('../org.tizen.common/package.js');
var Utils = require('../../lib/utils.js');


module.exports.analyzeDependencies = analyzeDependencies;
module.exports.hasSamePackages = hasSamePackages;
module.exports.hasBuildDependency = hasBuildDependency;
module.exports.hasInstallDependency = hasInstallDependency;
module.exports.getReverseBuildDepPkgs = getReverseBuildDepPkgs;
module.exports.isCompatible = isCompatible;


function analyzeDependencies(jobs) {
    var result = {};
    var installDepTable = {};

    // update dependency using build-dependency
    for (var i = 0; i < jobs.length; i++) {
        var srcJob = jobs[i];

        result[srcJob.id] = [];
        for (var j = 0; j < jobs.length; j++) {
            var tarJob = jobs[j];

            if (srcJob.id === tarJob.id) {
                continue;
            }

            if (hasBuildDependency(srcJob, tarJob)) {
                result[srcJob.id].push(tarJob.id);
            }
            if (!srcJob.compatJob && srcJob.id > tarJob.id &&
                isCompatible(srcJob, tarJob)) {

                result[srcJob.id].push(tarJob.id);
                srcJob.compatJob = tarJob.id;
            }

            if (hasInstallDependency(srcJob, tarJob)) {
                if (installDepTable[srcJob.id] === undefined) {
                    installDepTable[srcJob.id] = {};
                }
                installDepTable[srcJob.id][tarJob.id] = true;
            }
        }
    }

    // using install-dependency
    for (var i0 = 0; i0 < jobs.length; i0++) {
        var srcJob1 = jobs[i0];
        getInstallDependency(srcJob1.id, result[srcJob1.id], installDepTable);
    }

    return result;
}


function getInstallDependency(myId, depIds, table) {
    var found = false;
    for (var i = 0; i < depIds.length; i++) {
        var depId = depIds[i];
        for (var newId in table[depId]) {
            var newId1 = parseInt(newId, 10);
            if (newId1 === myId) continue;
            if (depIds.indexOf(newId1) === -1) {
                depIds.push(newId1);
                found = true;
            }
        }
    }

    if (found) {
        getInstallDependency(myId, depIds, table);
    }
}


function hasSamePackages(srcJob, tarJob) {
    if (!srcJob.options.packages || !tarJob.options.packages) {
        return false;
    }

    return srcJob.options.packages.filter(function (e1) {
            return tarJob.options.packages.filter(function (e2) {
                    return (e2.name === e1.name &&
                        _.intersection(e1.osList, e2.osList).length > 0 &&
                        e2.version === e1.version);
                }).length > 0;
        }).length > 0;
}


function hasBuildDependency(srcJob, tarJob) {

    // must have same distribution
    if (!srcJob.distName || !tarJob.distName || srcJob.distName !== tarJob.distName) {
        return false;
    }

    // check build dep
    if (srcJob.projectType === 'Tizen-Source' ||
        srcJob.projectType === 'Tizen-Binary') {

        var srcOS = srcJob.options.TARGET_OS;
        var deps = Package.getBuildDepsOfPackages(srcJob.options.packages, srcOS);
        var result = [];

        // check build dependency
        if (tarJob.projectType === 'Tizen-Source' ||
            tarJob.projectType === 'Tizen-Binary' ||
            tarJob.projectType === 'Tizen-Multi') {

            result = getBuildDepPkgsMatched(deps, tarJob.options.packages);
        }
        if (result.length > 0) {
            return true;
        }

        // check source dependency
        deps = Package.getSourceDepsOfPackages(srcJob.options.packages);
        if (tarJob.projectType === 'Tizen-Archive') {
            result = deps.filter(function (dep) {
                var matches = tarJob.options.packages.filter(function (pkg) {
                    return (dep.name === pkg);
                });
                return matches.length > 0;
            });
        }
        if (result.length > 0) {
            return true;
        }

    } else if (srcJob.projectType === 'Tizen-Multi') {
        for (var i = 0; i < srcJob.subJobs.length; i++) {
            if (hasBuildDependency(srcJob.subJobs[i], tarJob)) {
                return true;
            }
        }
    }

    return false;
}


function getBuildDepPkgsMatched(deps, pkgs) {
    if (deps && pkgs) {
        return deps.filter(function (dep) {
            var matches = pkgs.filter(function (pkg) {
                return (dep.name === pkg.name &&
                    pkg.osList.indexOf(dep.os) !== -1);
            });
            return matches.length > 0;
        });
    } else {
        return [];
    }
}


function hasInstallDependency(srcJob, tarJob) {

    // must have same distribution
    if (srcJob.distName !== tarJob.distName) {
        return false;
    }

    // check install dep
    if (srcJob.projectType === 'Tizen-Source') {
        var srcOS = srcJob.options.TARGET_OS;
        var deps = Package.getInstallDepsOfPackages(srcJob.options.packages, srcOS);
        var result = deps.filter(function (dep) {
            if (tarJob.projectType === 'Tizen-Source' || tarJob.projectType === 'Tizen-Binary') {
                var matches = tarJob.options.packages.filter(function (pkg) {
                    return (dep.name === pkg.name && dep.os === pkg.os);
                });
                return matches.length > 0;
            } else {
                return false;
            }
        });
        if (result.length > 0) {
            return true;
        }

    }

    return false;
}


function getReverseBuildDepPkgs(srcPkgs, snapshot) {
    var result = [];

    if (!snapshot) {
        return result;
    }

    // for all pkgs in snapshots
    for (var osName in snapshot.osPackages) {
        for (var pkgName in snapshot.osPackages[osName]) {
            var pkg = snapshot.osPackages[osName][pkgName];

            // ignore if pkg already exists in src pkgs
            if (srcPkgs.filter(function (p) {
                    return (p.name === pkg.name && p.osList.indexOf(osName) !== -1);
                }).length > 0) {

                continue;
            }

            // check if pkg's build-dependency
            var deps = Package.getBuildDepsOfPackages([pkg], osName);
            var matched = getBuildDepPkgsMatched(deps, srcPkgs);
            if (matched.length > 0) {
                pkg.os = osName;
                result.push(pkg);
            }
        }
    }

    return result;
}


function isCompatible(srcJob, tarJob) {
    if (!srcJob.options.packages || !tarJob.options.packages) {
        return false;
    }

    return srcJob.options.packages.filter(function (e1) {
            return tarJob.options.packages.filter(function (e2) {
                    return (e2.name === e1.name && e2.osList.indexOf(e1.os) !== -1 &&
                        e2.version === e1.version);
                }).length > 0;
        }).length === srcJob.options.packages.length;
}
