"use strict";
var AdmZip = require("adm-zip");
var child_process = require("child_process");
var fs = require("fs");
var minimist = require("minimist");
var path = require("path");
var q = require("q");
var rimraf = require("rimraf");
var binaries_1 = require("../binaries");
var cli_1 = require("../cli");
var config_1 = require("../config");
var files_1 = require("../files");
var utils_1 = require("../utils");
var Opt = require("./");
var initialize_1 = require("./initialize");
var opts_1 = require("./opts");
var logger = new cli_1.Logger('update');
var prog = new cli_1.Program()
    .command('update', 'install or update selected binaries')
    .action(update)
    .addOption(opts_1.Opts[Opt.OUT_DIR])
    .addOption(opts_1.Opts[Opt.VERBOSE])
    .addOption(opts_1.Opts[Opt.IGNORE_SSL])
    .addOption(opts_1.Opts[Opt.PROXY])
    .addOption(opts_1.Opts[Opt.ALTERNATE_CDN])
    .addOption(opts_1.Opts[Opt.STANDALONE])
    .addOption(opts_1.Opts[Opt.CHROME])
    .addOption(opts_1.Opts[Opt.GECKO])
    .addOption(opts_1.Opts[Opt.ANDROID])
    .addOption(opts_1.Opts[Opt.ANDROID_API_LEVELS])
    .addOption(opts_1.Opts[Opt.ANDROID_ARCHITECTURES])
    .addOption(opts_1.Opts[Opt.ANDROID_PLATFORMS])
    .addOption(opts_1.Opts[Opt.ANDROID_ACCEPT_LICENSES]);
if (config_1.Config.osType() === 'Darwin') {
    prog.addOption(opts_1.Opts[Opt.IOS]);
}
if (config_1.Config.osType() === 'Windows_NT') {
    prog.addOption(opts_1.Opts[Opt.IE]).addOption(opts_1.Opts[Opt.IE32]);
}
prog.addOption(opts_1.Opts[Opt.VERSIONS_STANDALONE])
    .addOption(opts_1.Opts[Opt.VERSIONS_CHROME])
    .addOption(opts_1.Opts[Opt.VERSIONS_APPIUM])
    .addOption(opts_1.Opts[Opt.VERSIONS_ANDROID])
    .addOption(opts_1.Opts[Opt.VERSIONS_GECKO]);
if (config_1.Config.osType() === 'Windows_NT') {
    prog.addOption(opts_1.Opts[Opt.VERSIONS_IE]);
}
exports.program = prog;
// stand alone runner
var argv = minimist(process.argv.slice(2), prog.getMinimistOptions());
if (argv._[0] === 'update-run') {
    prog.run(JSON.parse(JSON.stringify(argv)));
}
else if (argv._[0] === 'update-help') {
    prog.printHelp();
}
/**
 * Parses the options and downloads binaries if they do not exist.
 * @param options
 */
function update(options) {
    var standalone = options[Opt.STANDALONE].getBoolean();
    var chrome = options[Opt.CHROME].getBoolean();
    var gecko = options[Opt.GECKO].getBoolean();
    var ie = false;
    var ie32 = false;
    if (options[Opt.IE]) {
        ie = options[Opt.IE].getBoolean();
    }
    if (options[Opt.IE32]) {
        ie32 = options[Opt.IE32].getBoolean();
    }
    var android = options[Opt.ANDROID].getBoolean();
    var ios = false;
    if (options[Opt.IOS]) {
        ios = options[Opt.IOS].getBoolean();
    }
    var outputDir = config_1.Config.getSeleniumDir();
    var android_api_levels = options[Opt.ANDROID_API_LEVELS].getString().split(',');
    var android_architectures = options[Opt.ANDROID_ARCHITECTURES].getString().split(',');
    var android_platforms = options[Opt.ANDROID_PLATFORMS].getString().split(',');
    var android_accept_licenses = options[Opt.ANDROID_ACCEPT_LICENSES].getBoolean();
    if (options[Opt.OUT_DIR].getString()) {
        if (path.isAbsolute(options[Opt.OUT_DIR].getString())) {
            outputDir = options[Opt.OUT_DIR].getString();
        }
        else {
            outputDir = path.resolve(config_1.Config.getBaseDir(), options[Opt.OUT_DIR].getString());
        }
        files_1.FileManager.makeOutputDirectory(outputDir);
    }
    var ignoreSSL = options[Opt.IGNORE_SSL].getBoolean();
    var proxy = options[Opt.PROXY].getString();
    var verbose = options[Opt.VERBOSE].getBoolean();
    // setup versions for binaries
    var binaries = files_1.FileManager.setupBinaries(options[Opt.ALTERNATE_CDN].getString());
    binaries[binaries_1.StandAlone.id].versionCustom = options[Opt.VERSIONS_STANDALONE].getString();
    binaries[binaries_1.ChromeDriver.id].versionCustom = options[Opt.VERSIONS_CHROME].getString();
    if (options[Opt.VERSIONS_IE]) {
        binaries[binaries_1.IEDriver.id].versionCustom = options[Opt.VERSIONS_IE].getString();
    }
    if (options[Opt.VERSIONS_GECKO]) {
        binaries[binaries_1.GeckoDriver.id].versionCustom = options[Opt.VERSIONS_GECKO].getString();
    }
    binaries[binaries_1.AndroidSDK.id].versionCustom = options[Opt.VERSIONS_ANDROID].getString();
    binaries[binaries_1.Appium.id].versionCustom = options[Opt.VERSIONS_APPIUM].getString();
    // if the file has not been completely downloaded, download it
    // else if the file has already been downloaded, unzip the file, rename it, and give it
    // permissions
    if (standalone) {
        var binary_1 = binaries[binaries_1.StandAlone.id];
        files_1.FileManager.toDownload(binary_1, outputDir, proxy, ignoreSSL).then(function (value) {
            if (value) {
                files_1.Downloader.downloadBinary(binary_1, outputDir, proxy, ignoreSSL);
            }
            else {
                logger.info(binary_1.name + ': file exists ' +
                    path.resolve(outputDir, binary_1.filename(config_1.Config.osType(), config_1.Config.osArch())));
                logger.info(binary_1.name + ': v' + binary_1.versionCustom + ' up to date');
            }
        });
    }
    if (chrome) {
        var binary = binaries[binaries_1.ChromeDriver.id];
        updateBinary(binary, outputDir, proxy, ignoreSSL).done();
    }
    if (gecko) {
        var binary = binaries[binaries_1.GeckoDriver.id];
        updateBinary(binary, outputDir, proxy, ignoreSSL).done();
    }
    if (ie) {
        var binary = binaries[binaries_1.IEDriver.id];
        binary.arch = config_1.Config.osArch(); // Win32 or x64
        updateBinary(binary, outputDir, proxy, ignoreSSL).done();
    }
    if (ie32) {
        var binary = binaries[binaries_1.IEDriver.id];
        binary.arch = 'Win32';
        updateBinary(binary, outputDir, proxy, ignoreSSL).done();
    }
    if (android) {
        var binary_2 = binaries[binaries_1.AndroidSDK.id];
        var sdk_path = path.resolve(outputDir, binary_2.executableFilename(config_1.Config.osType()));
        var oldAVDList_1;
        q.nfcall(fs.readFile, path.resolve(sdk_path, 'available_avds.json'))
            .then(function (oldAVDs) {
            oldAVDList_1 = oldAVDs;
        }, function () {
            oldAVDList_1 = '[]';
        })
            .then(function () {
            return updateBinary(binary_2, outputDir, proxy, ignoreSSL);
        })
            .then(function () {
            initialize_1.android(path.resolve(outputDir, binary_2.executableFilename(config_1.Config.osType())), android_api_levels, android_architectures, android_platforms, android_accept_licenses, binaries[binaries_1.AndroidSDK.id].versionCustom, JSON.parse(oldAVDList_1), logger, verbose);
        })
            .done();
    }
    if (ios) {
        initialize_1.iOS(logger);
    }
    if (android || ios) {
        installAppium(binaries[binaries_1.Appium.id], outputDir);
    }
}
function updateBinary(binary, outputDir, proxy, ignoreSSL) {
    return files_1.FileManager.toDownload(binary, outputDir, proxy, ignoreSSL).then(function (value) {
        if (value) {
            var deferred_1 = q.defer();
            files_1.Downloader.downloadBinary(binary, outputDir, proxy, ignoreSSL, function (binary, outputDir, fileName) {
                unzip(binary, outputDir, fileName);
                deferred_1.resolve();
            });
            return deferred_1.promise;
        }
        else {
            logger.info(binary.name + ': file exists ' +
                path.resolve(outputDir, binary.filename(config_1.Config.osType(), config_1.Config.osArch())));
            var fileName = binary.filename(config_1.Config.osType(), config_1.Config.osArch());
            unzip(binary, outputDir, fileName);
            logger.info(binary.name + ': v' + binary.versionCustom + ' up to date');
        }
    });
}
function unzip(binary, outputDir, fileName) {
    // remove the previously saved file and unzip it
    var osType = config_1.Config.osType();
    var mv = path.resolve(outputDir, binary.executableFilename(osType));
    try {
        fs.unlinkSync(mv);
    }
    catch (err) {
        try {
            rimraf.sync(mv);
        }
        catch (err2) {
        }
    }
    // unzip the file
    logger.info(binary.name + ': unzipping ' + fileName);
    if (fileName.slice(-4) == '.zip') {
        var zip = new AdmZip(path.resolve(outputDir, fileName));
        zip.extractAllTo(outputDir, true);
    }
    else {
        // We will only ever get .tar files on linux
        child_process.spawnSync('tar', ['zxvf', path.resolve(outputDir, fileName), '-C', outputDir]);
    }
    // rename
    fs.renameSync(path.resolve(outputDir, binary.zipContentName(osType)), mv);
    // set permissions
    if (osType !== 'Windows_NT') {
        logger.info(binary.name + ': setting permissions to 0755 for ' + mv);
        if (binary.id() !== binaries_1.AndroidSDK.id) {
            fs.chmodSync(mv, '0755');
        }
        else {
            fs.chmodSync(path.resolve(mv, 'tools', 'android'), '0755');
            fs.chmodSync(path.resolve(mv, 'tools', 'emulator'), '0755');
        }
    }
}
function installAppium(binary, outputDir) {
    logger.info('appium: installing appium');
    var folder = path.resolve(outputDir, binary.filename());
    try {
        rimraf.sync(folder);
    }
    catch (err) {
    }
    var appiumVersion = binary.version();
    fs.mkdirSync(folder);
    fs.writeFileSync(path.resolve(folder, 'package.json'), JSON.stringify({ scripts: { appium: 'appium' } }));
    utils_1.spawn('npm', ['install', 'appium@' + appiumVersion], null, { cwd: folder });
    // Check versions and output warnings/errors
    function checkVersion(actual_semver, minimum_semver) {
        if (actual_semver[0] == 'v') {
            actual_semver = actual_semver.slice(1);
        }
        var actualVersions = actual_semver.toString().split('.');
        var minimumVersions = minimum_semver.toString().split('.');
        for (var i = 0; i < minimumVersions.length; i++) {
            var actual = parseInt(actualVersions[i] || '0');
            var min = parseInt(minimumVersions[i] || '0');
            if (!min) {
                return true;
            }
            else if (!actual || (actual < min)) {
                return false;
            }
            else if (actual > min) {
                return true;
            }
        }
        return true;
    }
    if (!checkVersion(appiumVersion, '1.6')) {
        logger.warn('Intalling appium@' + appiumVersion + ', which is not supported');
        logger.warn('appium < 1.6 cannot run android >= 7, ' +
            'which is required to have chrome bundled with the `google_apis` image');
    }
    else if (!checkVersion(process.version, '6')) {
        var npmVersion = utils_1.spawnSync('npm', ['-v']).stdout;
        if (!checkVersion(npmVersion, '3')) {
            logger.error('Using npm@' + npmVersion + ', which will almost certainly cause the ' +
                'installation of appium@' + appiumVersion + ' to fail silently.' +
                'Please upgrade to npm >= 3');
        }
    }
}
//# sourceMappingURL=update.js.map