"use strict";
const path = require("path");
const fiberBootstrap = require("../common/fiber-bootstrap");
const helpers_1 = require("../common/helpers");
const Future = require("fibers/future");
class EmulatorPlatformService {
    constructor($mobileHelper, $childProcess, $devicesService, $devicePlatformsConstants, $dispatcher, $options, $logger) {
        this.$mobileHelper = $mobileHelper;
        this.$childProcess = $childProcess;
        this.$devicesService = $devicesService;
        this.$devicePlatformsConstants = $devicePlatformsConstants;
        this.$dispatcher = $dispatcher;
        this.$options = $options;
        this.$logger = $logger;
    }
    startEmulator(info) {
        if (!info.isRunning) {
            if (this.$mobileHelper.isAndroidPlatform(info.platform)) {
                this.$options.avd = this.$options.device;
                this.$options.device = null;
                let platformsData = $injector.resolve("platformsData");
                let platformData = platformsData.getPlatformData(info.platform);
                let emulatorServices = platformData.emulatorServices;
                emulatorServices.checkAvailability();
                emulatorServices.checkDependencies().wait();
                emulatorServices.startEmulator().wait();
                this.$options.avd = null;
                return Future.fromResult();
            }
            if (this.$mobileHelper.isiOSPlatform(info.platform)) {
                this.stopEmulator(info.platform).wait();
                let future = new Future();
                this.$childProcess.exec(`open -a Simulator --args -CurrentDeviceUDID ${info.id}`).wait();
                let timeoutFunc = () => {
                    fiberBootstrap.run(() => {
                        info = this.getEmulatorInfo("ios", info.id).wait();
                        if (info.isRunning) {
                            this.$devicesService.initialize({ platform: info.platform, deviceId: info.id }).wait();
                            let device = this.$devicesService.getDeviceByIdentifier(info.id);
                            device.applicationManager.checkForApplicationUpdates().wait();
                            future.return();
                            return;
                        }
                        setTimeout(timeoutFunc, 2000);
                    });
                };
                timeoutFunc();
                return future;
            }
        }
        return Future.fromResult();
    }
    stopEmulator(platform) {
        if (this.$mobileHelper.isiOSPlatform(platform)) {
            return this.$childProcess.exec("pkill -9 -f Simulator");
        }
        return Future.fromResult();
    }
    getEmulatorInfo(platform, idOrName) {
        return (() => {
            if (this.$mobileHelper.isAndroidPlatform(platform)) {
                let androidEmulators = this.getAndroidEmulators().wait();
                let found = androidEmulators.filter((info) => info.id === idOrName);
                if (found.length > 0) {
                    return found[0];
                }
                this.$devicesService.initialize({ platform: platform, deviceId: null, skipInferPlatform: true }).wait();
                let info = null;
                let action = (device) => {
                    return (() => {
                        if (device.deviceInfo.identifier === idOrName) {
                            info = {
                                id: device.deviceInfo.identifier,
                                name: device.deviceInfo.displayName,
                                version: device.deviceInfo.version,
                                platform: "Android",
                                type: "emulator",
                                isRunning: true
                            };
                        }
                    }).future()();
                };
                this.$devicesService.execute(action, undefined, { allowNoDevices: true }).wait();
                return info;
            }
            if (this.$mobileHelper.isiOSPlatform(platform)) {
                let emulators = this.getiOSEmulators().wait();
                let sdk = null;
                let versionStart = idOrName.indexOf("(");
                if (versionStart > 0) {
                    sdk = idOrName.substring(versionStart + 1, idOrName.indexOf(")", versionStart)).trim();
                    idOrName = idOrName.substring(0, versionStart - 1).trim();
                }
                let found = emulators.filter((info) => {
                    let sdkMatch = sdk ? info.version === sdk : true;
                    return sdkMatch && info.id === idOrName || info.name === idOrName;
                });
                return found.length > 0 ? found[0] : null;
            }
            return null;
        }).future()();
    }
    listAvailableEmulators(platform) {
        return (() => {
            let emulators = [];
            if (!platform || this.$mobileHelper.isiOSPlatform(platform)) {
                let iosEmulators = this.getiOSEmulators().wait();
                if (iosEmulators) {
                    emulators = emulators.concat(iosEmulators);
                }
            }
            if (!platform || this.$mobileHelper.isAndroidPlatform(platform)) {
                let androidEmulators = this.getAndroidEmulators().wait();
                if (androidEmulators) {
                    emulators = emulators.concat(androidEmulators);
                }
            }
            this.outputEmulators("\nAvailable emulators", emulators);
            this.$logger.out("\nConnected devices & emulators");
            $injector.resolveCommand("device").execute(platform ? [platform] : []).wait();
        }).future()();
    }
    getiOSEmulators() {
        return (() => {
            let output = this.$childProcess.exec("xcrun simctl list --json").wait();
            let list = JSON.parse(output);
            let emulators = [];
            for (let osName in list["devices"]) {
                if (osName.indexOf("iOS") === -1) {
                    continue;
                }
                let os = list["devices"][osName];
                let version = this.parseiOSVersion(osName);
                for (let device of os) {
                    if (device["availability"] !== "(available)") {
                        continue;
                    }
                    let emulatorInfo = {
                        id: device["udid"],
                        name: device["name"],
                        isRunning: device["state"] === "Booted",
                        type: "simulator",
                        version: version,
                        platform: "iOS"
                    };
                    emulators.push(emulatorInfo);
                }
            }
            return emulators;
        }).future()();
    }
    getAndroidEmulators() {
        return (() => {
            let androidPath = path.join(process.env.ANDROID_HOME, "tools", "android");
            let text = this.$childProcess.exec(`${androidPath} list avd`).wait();
            let notLoadedIndex = text.indexOf("The following");
            if (notLoadedIndex > 0) {
                text = text.substring(0, notLoadedIndex);
            }
            let textBlocks = text.split("---------");
            let emulators = [];
            for (let block of textBlocks) {
                let lines = block.split("\n");
                let info = { name: "", version: "", id: "", platform: "Android", type: "Emulator" };
                for (let line of lines) {
                    if (line.indexOf("Target") >= 0) {
                        info.version = line.substring(line.indexOf(":") + 1).replace("Android", "").trim();
                    }
                    if (line.indexOf("Name") >= 0) {
                        info.id = line.substring(line.indexOf(":") + 1).trim();
                    }
                    if (line.indexOf("Device") >= 0) {
                        info.name = line.substring(line.indexOf(":") + 1).trim();
                    }
                    info.isRunning = false;
                }
                emulators.push(info);
            }
            return emulators;
        }).future()();
    }
    parseiOSVersion(osName) {
        osName = osName.replace("com.apple.CoreSimulator.SimRuntime.iOS-", "");
        osName = osName.replace(/-/g, ".");
        osName = osName.replace("iOS", "");
        osName = osName.trim();
        return osName;
    }
    outputEmulators(title, emulators) {
        this.$logger.out(title);
        let table = helpers_1.createTable(["Device Name", "Platform", "Version", "Device Identifier"], []);
        for (let info of emulators) {
            table.push([info.name, info.platform, info.version, info.id]);
        }
        this.$logger.out(table.toString());
    }
}
exports.EmulatorPlatformService = EmulatorPlatformService;
$injector.register("emulatorPlatformService", EmulatorPlatformService);
