"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
const os = require("os");
const osenv = require("osenv");
const path = require("path");
const helpers_1 = require("./helpers");
class SysInfoBase {
    constructor($childProcess, $hostInfo, $iTunesValidator, $logger, $winreg, $androidEmulatorServices) {
        this.$childProcess = $childProcess;
        this.$hostInfo = $hostInfo;
        this.$iTunesValidator = $iTunesValidator;
        this.$logger = $logger;
        this.$winreg = $winreg;
        this.$androidEmulatorServices = $androidEmulatorServices;
        this.monoVerRegExp = /version (\d+[.]\d+[.]\d+) /gm;
        this.sysInfoCache = undefined;
        this.javaVerCache = null;
        this.npmVerCache = null;
        this.javaCompilerVerCache = null;
        this.xCodeVerCache = null;
        this.nodeGypVerCache = null;
        this.xcodeprojGemLocationCache = null;
        this.itunesInstalledCache = null;
        this.cocoapodVersionCache = null;
    }
    getJavaVersion() {
        return __awaiter(this, void 0, void 0, function* () {
            if (!this.javaVerCache) {
                try {
                    const output = (yield this.$childProcess.spawnFromEvent("java", ["-version"], "exit")).stderr;
                    this.javaVerCache = /(?:openjdk|java) version \"((?:\d+\.)+(?:\d+))/i.exec(output)[1];
                }
                catch (e) {
                    this.javaVerCache = null;
                }
            }
            return this.javaVerCache;
        });
    }
    getNpmVersion() {
        return __awaiter(this, void 0, void 0, function* () {
            if (!this.npmVerCache) {
                const procOutput = yield this.exec("npm -v");
                this.npmVerCache = procOutput ? procOutput.split("\n")[0] : null;
            }
            return this.npmVerCache;
        });
    }
    getJavaCompilerVersion() {
        return __awaiter(this, void 0, void 0, function* () {
            if (!this.javaCompilerVerCache) {
                const javaCompileExecutableName = "javac";
                const javaHome = process.env.JAVA_HOME;
                const pathToJavaCompilerExecutable = javaHome ? path.join(javaHome, "bin", javaCompileExecutableName) : javaCompileExecutableName;
                try {
                    const output = yield this.exec(`"${pathToJavaCompilerExecutable}" -version`, { showStderr: true });
                    this.javaCompilerVerCache = output ? /javac (.*)/i.exec(output.stderr)[1] : null;
                }
                catch (e) {
                    this.$logger.trace(`Command "${pathToJavaCompilerExecutable} --version" failed: ${e}`);
                    this.javaCompilerVerCache = null;
                }
            }
            return this.javaCompilerVerCache;
        });
    }
    getXCodeVersion() {
        return __awaiter(this, void 0, void 0, function* () {
            if (!this.xCodeVerCache) {
                this.xCodeVerCache = this.$hostInfo.isDarwin ? yield this.exec("xcodebuild -version") : null;
            }
            return this.xCodeVerCache;
        });
    }
    getNodeGypVersion() {
        return __awaiter(this, void 0, void 0, function* () {
            if (!this.nodeGypVerCache) {
                try {
                    this.nodeGypVerCache = yield this.exec("node-gyp -v");
                }
                catch (e) {
                    this.$logger.trace(`Command "node-gyp -v" failed: ${e}`);
                    this.nodeGypVerCache = null;
                }
            }
            return this.nodeGypVerCache;
        });
    }
    getXCodeProjGemLocation() {
        return __awaiter(this, void 0, void 0, function* () {
            if (!this.xcodeprojGemLocationCache) {
                try {
                    this.xcodeprojGemLocationCache = this.$hostInfo.isDarwin ? yield this.exec("gem which xcodeproj") : null;
                }
                catch (e) {
                    this.$logger.trace(`Command "gem which xcodeproj" failed with: ${e}`);
                    this.xcodeprojGemLocationCache = null;
                }
            }
            return this.xcodeprojGemLocationCache;
        });
    }
    getITunesInstalled() {
        if (!this.itunesInstalledCache) {
            try {
                this.itunesInstalledCache = this.$iTunesValidator.getError() === null;
            }
            catch (e) {
                this.itunesInstalledCache = null;
            }
        }
        return this.itunesInstalledCache;
    }
    getCocoapodVersion() {
        return __awaiter(this, void 0, void 0, function* () {
            if (!this.cocoapodVersionCache) {
                try {
                    if (this.$hostInfo.isDarwin) {
                        let cocoapodVersion = yield this.exec("pod --version");
                        if (cocoapodVersion) {
                            const cocoapodVersionMatch = cocoapodVersion.match(/^((?:\d+\.){2}\d+.*?)$/gm);
                            if (cocoapodVersionMatch && cocoapodVersionMatch[0]) {
                                cocoapodVersion = cocoapodVersionMatch[0].trim();
                            }
                            this.cocoapodVersionCache = cocoapodVersion;
                        }
                    }
                }
                catch (e) {
                    this.$logger.trace(e);
                    this.cocoapodVersionCache = null;
                }
            }
            return this.cocoapodVersionCache;
        });
    }
    getSysInfo(pathToPackageJson, androidToolsInfo) {
        return __awaiter(this, void 0, void 0, function* () {
            if (!this.sysInfoCache) {
                const res = Object.create(null);
                let procOutput;
                const packageJson = require(pathToPackageJson);
                res.procInfo = packageJson.name + "/" + packageJson.version;
                res.platform = os.platform();
                res.os = this.$hostInfo.isWindows ? yield this.winVer() : yield this.unixVer();
                res.shell = osenv.shell();
                try {
                    res.dotNetVer = yield this.$hostInfo.dotNetVersion();
                }
                catch (err) {
                    res.dotNetVer = ".Net is not installed.";
                }
                res.procArch = process.arch;
                res.nodeVer = process.version;
                res.npmVer = yield this.getNpmVersion();
                res.javaVer = yield this.getJavaVersion();
                res.nodeGypVer = yield this.getNodeGypVersion();
                res.xcodeVer = yield this.getXCodeVersion();
                res.xcodeprojGemLocation = yield this.getXCodeProjGemLocation();
                res.itunesInstalled = this.getITunesInstalled();
                res.cocoapodVer = yield this.getCocoapodVersion();
                const pathToAdb = androidToolsInfo ? androidToolsInfo.pathToAdb : "adb";
                if (!androidToolsInfo) {
                    this.$logger.trace("'adb' and 'android' will be checked from PATH environment variable.");
                }
                procOutput = yield this.exec(`${helpers_1.quoteString(pathToAdb)} version`);
                res.adbVer = procOutput ? procOutput.split(os.EOL)[0] : null;
                res.emulatorInstalled = yield this.checkEmulator();
                procOutput = yield this.exec("mono --version");
                if (!!procOutput) {
                    const match = this.monoVerRegExp.exec(procOutput);
                    res.monoVer = match ? match[1] : null;
                }
                else {
                    res.monoVer = null;
                }
                procOutput = yield this.exec("git --version");
                res.gitVer = procOutput ? /^git version (.*)/.exec(procOutput)[1] : null;
                procOutput = yield this.exec("gradle -v");
                res.gradleVer = procOutput ? /Gradle (.*)/i.exec(procOutput)[1] : null;
                res.javacVersion = yield this.getJavaCompilerVersion();
                this.sysInfoCache = res;
            }
            return this.sysInfoCache;
        });
    }
    exec(cmd, execOptions) {
        return __awaiter(this, void 0, void 0, function* () {
            try {
                if (cmd) {
                    return yield this.$childProcess.exec(cmd, null, execOptions);
                }
            }
            catch (e) {
                this.$logger.trace(`Error while executing ${cmd}: ${e.message}`);
            }
            return null;
        });
    }
    checkEmulator() {
        return __awaiter(this, void 0, void 0, function* () {
            const emulatorHelp = yield this.$childProcess.spawnFromEvent(this.$androidEmulatorServices.pathToEmulatorExecutable, ["-help"], "close", {}, { throwError: false });
            const result = !!(emulatorHelp && emulatorHelp.stdout && emulatorHelp.stdout.indexOf("usage: emulator") !== -1);
            this.$logger.trace(`The result of checking is Android Emulator installed is:${os.EOL}- stdout: ${emulatorHelp && emulatorHelp.stdout}${os.EOL}- stderr: ${emulatorHelp && emulatorHelp.stderr}`);
            return result;
        });
    }
    winVer() {
        return __awaiter(this, void 0, void 0, function* () {
            try {
                return (yield this.readRegistryValue("ProductName")) + " " +
                    (yield this.readRegistryValue("CurrentVersion")) + "." +
                    (yield this.readRegistryValue("CurrentBuild"));
            }
            catch (err) {
                this.$logger.trace(err);
            }
            return null;
        });
    }
    readRegistryValue(valueName) {
        return __awaiter(this, void 0, void 0, function* () {
            return (yield this.$winreg.getRegistryValue(valueName, this.$winreg.registryKeys.HKLM, '\\Software\\Microsoft\\Windows NT\\CurrentVersion')).value;
        });
    }
    unixVer() {
        return this.exec("uname -a");
    }
}
exports.SysInfoBase = SysInfoBase;
$injector.register("sysInfoBase", SysInfoBase);
