"use strict";
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) {
        this.$childProcess = $childProcess;
        this.$hostInfo = $hostInfo;
        this.$iTunesValidator = $iTunesValidator;
        this.$logger = $logger;
        this.$winreg = $winreg;
        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 (() => {
            if (!this.javaVerCache) {
                try {
                    let output = this.$childProcess.spawnFromEvent("java", ["-version"], "exit").wait().stderr;
                    this.javaVerCache = /(?:openjdk|java) version \"((?:\d+\.)+(?:\d+))/i.exec(output)[1];
                }
                catch (e) {
                    this.javaVerCache = null;
                }
            }
            return this.javaVerCache;
        }).future()();
    }
    getNpmVersion() {
        if (!this.npmVerCache) {
            let procOutput = this.exec("npm -v");
            this.npmVerCache = procOutput ? procOutput.split("\n")[0] : null;
        }
        return this.npmVerCache;
    }
    getJavaCompilerVersion() {
        return (() => {
            if (!this.javaCompilerVerCache) {
                try {
                    let javaCompileExecutableName = "javac";
                    let javaHome = process.env.JAVA_HOME;
                    let pathToJavaCompilerExecutable = javaHome ? path.join(javaHome, "bin", javaCompileExecutableName) : javaCompileExecutableName;
                    let output = this.exec(`"${pathToJavaCompilerExecutable}" -version`, { showStderr: true });
                    this.javaCompilerVerCache = output ? /javac (.*)/i.exec(output.stderr)[1] : null;
                }
                catch (e) {
                    this.javaCompilerVerCache = null;
                }
            }
            return this.javaCompilerVerCache;
        }).future()();
    }
    getXCodeVersion() {
        return (() => {
            if (!this.xCodeVerCache) {
                try {
                    this.xCodeVerCache = this.$hostInfo.isDarwin ? this.exec("xcodebuild -version") : null;
                }
                catch (e) {
                    this.xCodeVerCache = null;
                }
            }
            return this.xCodeVerCache;
        }).future()();
    }
    getNodeGypVersion() {
        return (() => {
            if (!this.nodeGypVerCache) {
                try {
                    this.nodeGypVerCache = this.exec("node-gyp -v");
                }
                catch (e) {
                    this.nodeGypVerCache = null;
                }
            }
            return this.nodeGypVerCache;
        }).future()();
    }
    getXCodeProjGemLocation() {
        return (() => {
            if (!this.xcodeprojGemLocationCache) {
                try {
                    this.xcodeprojGemLocationCache = this.$hostInfo.isDarwin ? this.exec("gem which xcodeproj") : null;
                }
                catch (e) {
                    this.xcodeprojGemLocationCache = null;
                }
            }
            return this.xcodeprojGemLocationCache;
        }).future()();
    }
    getITunesInstalled() {
        if (!this.itunesInstalledCache) {
            try {
                this.itunesInstalledCache = this.$iTunesValidator.getError() === null;
            }
            catch (e) {
                this.itunesInstalledCache = null;
            }
        }
        return this.itunesInstalledCache;
    }
    getCocoapodVersion() {
        return (() => {
            if (!this.cocoapodVersionCache) {
                try {
                    if (this.$hostInfo.isDarwin) {
                        let cocoapodVersion = this.exec("pod --version");
                        if (cocoapodVersion) {
                            let cocoapodVersionMatch = cocoapodVersion.match(/^((?:\d+\.){2}\d+.*?)$/gm);
                            if (cocoapodVersionMatch && cocoapodVersionMatch[0]) {
                                cocoapodVersion = cocoapodVersionMatch[0].trim();
                            }
                            this.cocoapodVersionCache = cocoapodVersion;
                        }
                    }
                }
                catch (e) {
                    this.cocoapodVersionCache = null;
                }
            }
            return this.cocoapodVersionCache;
        }).future()();
    }
    getSysInfo(pathToPackageJson, androidToolsInfo) {
        return (() => {
            if (!this.sysInfoCache) {
                let res = Object.create(null);
                let procOutput;
                let packageJson = require(pathToPackageJson);
                res.procInfo = packageJson.name + "/" + packageJson.version;
                res.platform = os.platform();
                res.os = this.$hostInfo.isWindows ? this.winVer() : this.unixVer();
                res.shell = osenv.shell();
                try {
                    res.dotNetVer = this.$hostInfo.dotNetVersion().wait();
                }
                catch (err) {
                    res.dotNetVer = ".Net is not installed.";
                }
                res.procArch = process.arch;
                res.nodeVer = process.version;
                res.npmVer = this.getNpmVersion();
                res.javaVer = this.getJavaVersion().wait();
                res.nodeGypVer = this.getNodeGypVersion().wait();
                res.xcodeVer = this.getXCodeVersion().wait();
                res.xcodeprojGemLocation = this.getXCodeProjGemLocation().wait();
                res.itunesInstalled = this.getITunesInstalled();
                res.cocoapodVer = this.getCocoapodVersion().wait();
                let pathToAdb = androidToolsInfo ? androidToolsInfo.pathToAdb : "adb";
                let pathToAndroid = androidToolsInfo ? androidToolsInfo.pathToAndroid : "android";
                if (!androidToolsInfo) {
                    this.$logger.trace("'adb' and 'android' will be checked from PATH environment variable.");
                }
                procOutput = this.exec(`${helpers_1.quoteString(pathToAdb)} version`);
                res.adbVer = procOutput ? procOutput.split(os.EOL)[0] : null;
                res.androidInstalled = this.checkAndroid(pathToAndroid).wait();
                procOutput = this.exec("mono --version");
                if (!!procOutput) {
                    let match = this.monoVerRegExp.exec(procOutput);
                    res.monoVer = match ? match[1] : null;
                }
                else {
                    res.monoVer = null;
                }
                procOutput = this.exec("git --version");
                res.gitVer = procOutput ? /^git version (.*)/.exec(procOutput)[1] : null;
                procOutput = this.exec("gradle -v");
                res.gradleVer = procOutput ? /Gradle (.*)/i.exec(procOutput)[1] : null;
                res.javacVersion = this.getJavaCompilerVersion().wait();
                this.sysInfoCache = res;
            }
            return this.sysInfoCache;
        }).future()();
    }
    exec(cmd, execOptions) {
        try {
            if (cmd) {
                return this.$childProcess.exec(cmd, null, execOptions).wait();
            }
        }
        catch (e) {
        }
        return null;
    }
    checkAndroid(pathToAndroid) {
        return (() => {
            let result = false;
            try {
                if (pathToAndroid) {
                    let androidChildProcess = this.$childProcess.spawnFromEvent(pathToAndroid, ["-h"], "close", {}, { throwError: false }).wait();
                    result = androidChildProcess && androidChildProcess.stdout && _.includes(androidChildProcess.stdout, "android");
                }
            }
            catch (err) {
                this.$logger.trace(`Error while checking is ${pathToAndroid} installed. Error is: ${err.messge}`);
            }
            return result;
        }).future()();
    }
    winVer() {
        try {
            return this.readRegistryValue("ProductName").wait() + " " +
                this.readRegistryValue("CurrentVersion").wait() + "." +
                this.readRegistryValue("CurrentBuild").wait();
        }
        catch (err) {
            this.$logger.trace(err);
        }
        return null;
    }
    readRegistryValue(valueName) {
        return (() => {
            return this.$winreg.getRegistryValue(valueName, this.$winreg.registryKeys.HKLM, '\\Software\\Microsoft\\Windows NT\\CurrentVersion').wait().value;
        }).future()();
    }
    unixVer() {
        return this.exec("uname -a");
    }
}
exports.SysInfoBase = SysInfoBase;
$injector.register("sysInfoBase", SysInfoBase);
