/**
 * latest-sdk-installed-env.js
 * Copyright (c) 2000 - 2017 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 fs = require('fs');
var extfs = require('fs-extra');
var path = require('path');
var async = require('async');
var os = require('os');

var Snapshot = require('../org.tizen.repository/snapshot');
var RemoteRepo = require('../org.tizen.repository/remote-repo.js');
var ImageGenerator = require('../../plugins/org.tizen.common/image-generator.js');
var TUtils = require('../../plugins/org.tizen.common/tizen_utils.js');
var Zip = require('../dibs.core/zip.js');
var dibs = require('../../core/dibs');
var utils = require('../../lib/utils');
var FileSystem = require('../dibs.core/filesystem.js');
var Process = require('../dibs.core/process.js');

module.exports.setup = setup;
dibs.initialize();

function setup(enviromentId, distName, distBaseURL, workspace, passwd, testDistName, monitor, callback) {
    var baseURL;
    if (distBaseURL.slice(-1) === '/') {
        baseURL = distBaseURL.substring(0, distBaseURL.length - 1);
    } else {
        baseURL = distBaseURL;
    }

    var host = TUtils.getTargetOS(os.platform(), os.arch()).os;
    var installerPath = null;
    var sdkImagePath = null;
    var pServerURL = baseURL + '/' + distName;
    var snapshotName;

    async.waterfall([
        function (cb) {
            removeSDKIfInstalled(monitor, cb);
        },
        function (cb) {
            monitor.updateProgress('get latest Snapshot');
            Snapshot.loadRemote(pServerURL, {
                snapshotName: null
            }, cb);
        }, function (snapshotObj, cb) {
            monitor.updateProgress('snapshot name: ' + snapshotObj[0].name);
            snapshotName = snapshotObj[0].name;

            monitor.updateProgress('download installer');
            downloadInstaller(snapshotName, distName, pServerURL, host, workspace, monitor, cb);
        }, function (downloadedPath, cb) {
            monitor.updateProgress('installer path: ' + downloadedPath);
            if (utils.isLinux) {
                installerPath = path.join(downloadedPath, 'data', 'install-manager', 'InstallManagerV2.jar');
                monitor.updateProgress('installer full path: ' + installerPath);

                fs.writeFileSync(path.join(downloadedPath, 'data', 'install-manager', 'installmanager.conf'),
                    'Repository: http://download.tizen.org/sdk/packages-2.3b/\n' +
                    'InstallManager-Version: 2.3.56\n' +
                    'Distribution: official\n' +
                    'Release-Note: https://developer.tizen.org/downloads/sdk/2.0-release-notes\n'
                );
                cb(null);
            } else {
                installerPath = path.join(downloadedPath, 'inst-manager.exe');
                monitor.updateProgress('installer full path: ' + installerPath);
                cb(null);
            }
        }, function (cb) {
            var imageName = distName + snapshotName + '_' + host + '.zip';
            monitor.updateProgress('image name: ' + imageName);
            prepareSDKImage(snapshotName, distName, pServerURL, host, workspace, imageName, testDistName, monitor, function (err, imagePath) {
                if (err) {
                    cb(err);
                } else {
                    monitor.updateProgress('image path: ' + imagePath);
                    sdkImagePath = imagePath;
                    cb(err);
                }
            });
        }, function (cb) {
            installSDK(sdkImagePath, installerPath, distName, passwd, monitor, cb);
        }, function (cb) {
            cleanUpScreen(monitor, cb);
        }
    ], function (err) {
        callback(err);
    });
}

function downloadInstaller(snapshotName, distName, pServerURL, host, workspace, monitor, callback) {
    var installerWorkspace = path.join(workspace, 'installerDir');
    async.waterfall([
        function (cb) {
            initWorkspace(installerWorkspace, cb);
        }, function (path, cb) {
            downloadRemotePackageUsingURL(pServerURL, distName, snapshotName, host, 'install-manager', cb);
        }, function (rst, cb) {
            Zip.uncompress(rst, installerWorkspace, function (err) {
                if (err) {
                    cb(err);
                } else {
                    fs.unlink(rst, cb);
                }
            });
        }], function (err) {
        if (err) {
            callback(err);
        } else {
            callback(err, installerWorkspace);
        }
    });
}

function prepareSDKImage(snapshotName, distName, pServerURL, host, workspace, imageName, testDistName, monitor, callback) {
    var repo = null;
    var isFileExists = false;
    var repoSnapshotName;
    async.waterfall([
        function (cb) {
            repo = dibs.getServersByType('repo')[0];
            cb(null);
        },
        function (cb) {
            monitor.updateProgress('check if exists');
            repo.searchSnapshots({
                name: null,
                repoType: 'tizen-ta',
                distName: testDistName
            }, function (err, snapshots) {
                if (!err && snapshots.length > 0 && snapshots[0].packages[imageName]) {
                    monitor.updateProgress('exists image');
                    repoSnapshotName = snapshots[0].name;
                    isFileExists = true;
                }
                cb(null);
            });
        }, function (cb) {
            if (isFileExists) {
                cb(null);
            } else {
                monitor.updateProgress('make sdk image');
                ImageGenerator.makeImage({
                    snapshotName: snapshotName,
                    distributionName: distName,
                    pServerURL: pServerURL,
                    workspace: workspace,
                    imgName: imageName,
                    imgInfo: null,
                    os: host,
                    excludeList: []
                }, cb);
            }
        }, function (cb) {
            if (isFileExists) {
                monitor.updateProgress('download sdk image');
                repo.downloadPackage(imageName, {
                    repoType: 'tizen-ta',
                    targetDir: workspace,
                    distName: testDistName,
                    snapshotName: repoSnapshotName
                }, function (err, rst) {
                    if (err) {
                        monitor.updateProgress('download sdk image failed');
                        cb(err);
                    } else {
                        monitor.updateProgress('download sdk image succeeded');
                        cb(err, rst);
                    }
                });
            } else {
                // register image
                monitor.updateProgress('Uploading sdk image...');
                repo.registerPackages([path.join(workspace, imageName)],
                    {
                        repoType: 'tizen-ta',
                        distName: testDistName
                    },
                    function (err) {
                        if (err) {
                            monitor.updateProgress('Uploading sdk image failed!');
                            cb(err);
                        } else {
                            monitor.updateProgress('Uploading sdk image succeeded!');
                            cb(err, path.join(workspace, imageName));
                        }
                    });
            }
        }], function (err, rst) {
        if (err) {
            monitor.updateProgress(JSON.stringify(err));
            callback(err);
        } else {
            callback(err, rst);
        }
    });
}

function installSDK(imagePath, installerPath, testDistName, passwd, monitor, callback) {
    var imageOpt = 'file:/' + imagePath;
    monitor.updateProgress('image path: ' + imageOpt);
    monitor.updateProgress('installer path: ' + installerPath);
    var run = Process.create('java',
        ['-jar', installerPath, '-install', '-f', imageOpt, '-p', 'all', '-accept_license', '-ni', '-passwd', passwd],
        {
            cwd: path.dirname(installerPath)
        },
        {
            onStdout: function (line) {
                monitor.updateProgress('   ' + line);
            },
            onStderr: function (line) {
                monitor.updateProgress({
                    log: '   ' + line,
                    logType: 'error'
                });
            },
            onExit: function (code) {
                if (code !== 0) {
                    var error = new Error('Executing file(' + installerPath + ') process exited with code ' + code);
                    callback(error);
                } else {
                    monitor.updateProgress('install success');
                    callback(null);
                }
            }
        });
    // add process to monitor
    monitor.addProcess(run);
}

function cleanUpScreen(monitor, callback) {
    if (os.platform() === 'linux') {
        cleanUpScreenOnLinux(monitor, callback);
    } else {
        callback(null);
    }
}


function cleanUpScreenOnLinux(monitor, callback) {
    var run = Process.create('wmctrl',
        ['-k', 'on'],
        {},
        {
            onStdout: function (line) {
                monitor.updateProgress('   ' + line);
            },
            onStderr: function (line) {
                monitor.updateProgress({
                    log: '   ' + line,
                    logType: 'error'
                });
            },
            onExit: function (code) {
                if (code !== 0) {
                    var error = new Error('Executing file(wmctrl) process exited with code ' + code);
                    callback(error);
                } else {
                    callback(null);
                }
            }
        });

    // add process to monitor
    monitor.addProcess(run);
}

function downloadRemotePackageUsingURL(url, dist, snap, os, pkgName, callback) {
    var repo;
    async.waterfall([
        function (cb) {
            // open repo
            repo = RemoteRepo.createRemoteRepo(path.dirname(url), {
                distName: dist,
                snapshotName: snap
            });
            repo.open(null, cb);
        }, function (cb) {
            repo.downloadPackage(pkgName, {
                distName: dist,
                snapshotName: snap,
                os: os
            }, cb);
        }], callback);
}

function initWorkspace(inputPath, callback) {
    async.waterfall([
        function (cb) {
            utils.removePathIfExist(inputPath, cb);
        }, function (cb) {
            extfs.mkdirp(inputPath, cb);
        }], callback);
}


function removeSDKIfInstalled(monitor, callback) {
    var configDir = path.join(utils.getHomePath(), '.installmanager');
    var installDir = path.join(utils.getHomePath(), 'tizen-sdk');
    var dataDir = path.join(utils.getHomePath(), 'tizen-sdk-data');

    async.series([
        function (cb) {
            if (fs.existsSync(configDir)) {
                FileSystem.remove(configDir, cb);
            } else {
                cb(null);
            }
        },
        function (cb) {
            if (fs.existsSync(installDir)) {
                FileSystem.remove(installDir, cb);
            } else {
                cb(null);
            }
        },
        function (cb) {
            if (fs.existsSync(dataDir)) {
                FileSystem.remove(dataDir, cb);
            } else {
                cb(null);
            }
        }
    ], function (err) {
        callback(err);
    });
}
