/**
 * upload-project.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 path = require('path');
var async = require('async');
var _ = require('underscore');

var dibs = require('../../core/dibs.js');
var DError = require('../../core/exception.js');
var utils = require('../../lib/utils.js');
var Job = require('../dibs.model.common/job.js');
var Package = require('../dibs.core.server/package.js');


module.exports.createJob = createJob;
module.exports.initializeJob = initializeJob;
module.exports.executeJob = executeJob;
module.exports.checkMutualExclusiveJob = checkMutualExclusiveJob;


function PluginUploadJob(baseJob) {
    Job.copy(this, baseJob);

    this.compatJob = null;
    this.snapshot = null;
    this.options.packages = [];
    var self = this;

    // NOTE. Initializing/Executing on windows is very slow
    self.initEnvironments = dibs.projectTypes['DIBS-Plugin-Upload'].environments
        .filter(function (e) {
            return (e.indexOf('windows') === -1);
        });
    self.execEnvironments = dibs.projectTypes['DIBS-Plugin-Upload'].environments
        .filter(function (e) {
            return (e.indexOf('windows') === -1);
        });
}


function createJob(userEmail, distName, prjName, prjType, environmentName, parentId, distType, options, callback) {
    Job.create(userEmail, distName, distType, prjName, prjType, environmentName, parentId, null, options,
        function (err, newJob) {
            callback(err, new PluginUploadJob(newJob));
        });
}


function initializeJob(job, options, callback) {
    var jobWorkPath = options.jobWorkPath;
    var monitor = options.monitor;
    console.log(options.parentServerId);
    var parentServer = dibs.getServer(options.parentServerId);
    console.log(parentServer);

    if (job.status === 'INITIALIZED') {
        callback(null); return;
    }

    var fileName = path.basename(job.options.FILEPATH);
    var pkgPath = path.join(jobWorkPath, fileName);

    // check the format of file name
    var pInfo = Package.getInfoFromPackageFileName(fileName);
    if (!pInfo) {
        callback(new DError('DUJOB002', {
            name: fileName
        })); return;
    }
    // check package name
    if (pInfo.name !== job.options.PLUGIN_NAME) {
        callback(new DError('DUJOB003', {
            name: pInfo.name
        })); return;
    }

    async.waterfall([
        // get plugin file
        function (cb) {
            monitor.updateProgress('Getting plugin file...' + pkgPath);
            parentServer.dfsGetFile(pkgPath, job.options.FILEPATH, cb);
        },
        function (cb) {
            monitor.updateProgress('Getting plugin file done!', cb);
        },
        // check pkginfo.manifest
        function (cb) {
            monitor.updateProgress('Reading plugin information from file...' + pkgPath);
            Package.readPackageInfoFromFile(pkgPath, cb);
        },
        // check
        function (pkgInfo, isPlugin, cb) {
            job.options.packages.push(pkgInfo);
            monitor.updateProgress('Checking plugin information...');
            checkPackageInfo(job, pkgInfo, function (err) {
                cb(err);
            });
        },
        function (cb) {
            monitor.updateProgress('Checking plugin information done!', cb);
        }
    ], function (err) {
        callback(err, job);
    });
}


function executeJob(job, options, callback) {
    var jobWorkPath = options.jobWorkPath;
    var monitor = options.monitor;

    async.series([
        // get latest snapshots of repository
        function (cb) {
            dibs.rpc.repo.searchSnapshots({
                name: null,
                repoType: 'dibs',
                distName: job.distName
            },
                function (err, snapshots) {
                    if (!err && snapshots.length > 0) {
                        job.snapshot = snapshots[0];
                        job.snapshot.distName = job.distName;
                    }
                    cb(err);
                });
        },
        function (cb) {
            monitor.updateProgress('Getting latest snapshot of repository is done!', cb);
        },
        function (cb) {
            monitor.updateProgress('Checking plugin info...');
            checkPackageInfo(job, job.options.packages[0], cb);
        },
        function (cb) {
            job.resultFiles = [job.options.FILEPATH];
            monitor.updateProgress('Checking uploading...', cb);
        },
        // upload
        function (cb) {
            if (job.options.UPLOAD) {
                upload(job, jobWorkPath, monitor, false, cb);
            } else {
                monitor.updateProgress('Skipped uploading');
                cb(null);
            }
        },
        function (wcb) {
            monitor.updateProgress('Uploading is done!', wcb);
        },
        function (cb) {
            monitor.updateProgress('Terminating job...', cb);
        }], function (err) {
        callback(err, job);
    });
}


function checkPackageInfo(job, pkg, callback) {

    async.waterfall([
        // get latest snapshot
        function (cb) {
            getLatestSnapshot(job.distName, cb);
        },
        // check package version
        function (snapshot, cb) {
            // if no latest snapshot yet, it's ok
            if (snapshot === null) {
                cb(null); return;
            }

            var oldPkg = snapshot.packages[pkg.name];

            if (oldPkg && utils.compareVersion(pkg.version, oldPkg.version) <= 0) {
                cb(new DError('DUJOB001', {
                    name: pkg.name,
                    version: pkg.version,
                    oldVersion: oldPkg.version
                }));
            } else {
                cb(null);
            }
        }], function (err) {
        callback(err);
    });
}


function getLatestSnapshot(distName, callback) {

    dibs.rpc.repo.searchSnapshots({
        repoType: 'dibs',
        distName: distName,
        name: null
    },
        function (err, snapshots) {
            if (!err) {
                if (snapshots.length > 0) {
                    callback(null, snapshots[0]);
                } else {
                    callback(null, null);
                }
            } else {
                callback(err, null);
            }
        });
}


function upload(job, jobWorkPath, monitor, force, callback) {
    monitor.updateProgress('Uploading... ');

    // register files
    dibs.rpc.repo.registerRemotePackages(job.resultFiles, {
        repoType: 'dibs',
        distName: job.distName,
        forceUpload: force
    },
        function (err) {
            if (!err) {
                monitor.updateProgress('Uploading package succeeded! ');
            } else {
                monitor.updateProgress({
                    log: 'Uploading package failed! ',
                    logType: 'error'
                });
            }
            callback(err);
        });
}


function checkMutualExclusiveJob(srcJob, tarJob) {
    if (srcJob.distName !== tarJob.distName) {
        return false;
    } else {
        return true;
    }
}
