"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());
    });
};
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 __awaiter(this, void 0, void 0, function* () {
            if (!this.javaVerCache) {
                try {
                    let 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) {
                let 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) {
                let javaCompileExecutableName = "javac";
                let javaHome = process.env.JAVA_HOME;
                let pathToJavaCompilerExecutable = javaHome ? path.join(javaHome, "bin", javaCompileExecutableName) : javaCompileExecutableName;
                try {
                    let 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) {
                try {
                    this.xCodeVerCache = this.$hostInfo.isDarwin ? yield this.exec("xcodebuild -version") : null;
                }
                catch (e) {
                    this.$logger.trace(`Command "xcodebuild -version" failed: ${e}`);
                    this.xCodeVerCache = 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) {
                            let 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) {
                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 ? 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();
                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 = yield this.exec(`${helpers_1.quoteString(pathToAdb)} version`);
                res.adbVer = procOutput ? procOutput.split(os.EOL)[0] : null;
                res.androidInstalled = yield this.checkAndroid(pathToAndroid);
                procOutput = yield this.exec("mono --version");
                if (!!procOutput) {
                    let 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) {
            }
            return null;
        });
    }
    checkAndroid(pathToAndroid) {
        return __awaiter(this, void 0, void 0, function* () {
            let result = false;
            try {
                if (pathToAndroid) {
                    let androidChildProcess = yield this.$childProcess.spawnFromEvent(pathToAndroid, ["-h"], "close", {}, { throwError: false });
                    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;
        });
    }
    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);
