"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
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 path = require("path");
const debug_service_base_1 = require("./debug-service-base");
const constants_1 = require("../constants");
const inspectorAppName = "NativeScript Inspector.app";
const inspectorNpmPackageName = "tns-ios-inspector";
const inspectorUiDir = "WebInspectorUI/";
const decorators_1 = require("../common/decorators");
const os_1 = require("os");
class IOSDeviceDebugService extends debug_service_base_1.DebugServiceBase {
    constructor(device, $devicesService, $childProcess, $hostInfo, $logger, $errors, $packageInstallationManager, $appDebugSocketProxyFactory, $projectDataService) {
        super(device, $devicesService);
        this.device = device;
        this.$devicesService = $devicesService;
        this.$childProcess = $childProcess;
        this.$hostInfo = $hostInfo;
        this.$logger = $logger;
        this.$errors = $errors;
        this.$packageInstallationManager = $packageInstallationManager;
        this.$appDebugSocketProxyFactory = $appDebugSocketProxyFactory;
        this.$projectDataService = $projectDataService;
        this.$appDebugSocketProxyFactory.on(constants_1.CONNECTION_ERROR_EVENT_NAME, (e) => this.emit(constants_1.CONNECTION_ERROR_EVENT_NAME, e));
        this.deviceIdentifier = this.device.deviceInfo.identifier;
    }
    get platform() {
        return "ios";
    }
    debug(debugData, debugOptions) {
        return __awaiter(this, void 0, void 0, function* () {
            const result = { debugUrl: null };
            this.validateOptions(debugOptions);
            result.debugUrl = yield this.wireDebuggerClient(debugData, debugOptions);
            return result;
        });
    }
    debugStop() {
        return __awaiter(this, void 0, void 0, function* () {
            this.$appDebugSocketProxyFactory.removeAllProxies();
        });
    }
    validateOptions(debugOptions) {
        if (!this.$hostInfo.isWindows && !this.$hostInfo.isDarwin) {
            this.$errors.fail(`Debugging on iOS devices is not supported for ${os_1.platform()} yet.`);
        }
        if (debugOptions.debugBrk && debugOptions.start) {
            this.$errors.fail("Expected exactly one of the --debug-brk or --start options.");
        }
    }
    getProjectName(debugData) {
        let projectName = debugData.projectName;
        if (!projectName && debugData.projectDir) {
            const projectData = this.$projectDataService.getProjectData(debugData.projectDir);
            projectName = projectData.projectName;
        }
        return projectName;
    }
    killProcess(childProcess) {
        return __awaiter(this, void 0, void 0, function* () {
            if (childProcess) {
                return new Promise((resolve, reject) => {
                    childProcess.on("close", resolve);
                    childProcess.kill();
                });
            }
        });
    }
    wireDebuggerClient(debugData, debugOptions) {
        return __awaiter(this, void 0, void 0, function* () {
            if ((debugOptions.inspector || !debugOptions.client) && this.$hostInfo.isDarwin) {
                return yield this.setupTcpAppDebugProxy(debugData, debugOptions);
            }
            else {
                return yield this.setupWebAppDebugProxy(debugOptions, debugData);
            }
        });
    }
    setupWebAppDebugProxy(debugOptions, debugData) {
        return __awaiter(this, void 0, void 0, function* () {
            if (debugOptions.chrome) {
                this.$logger.info("'--chrome' is the default behavior. Use --inspector to debug iOS applications using the Safari Web Inspector.");
            }
            const projectName = this.getProjectName(debugData);
            const webSocketProxy = yield this.$appDebugSocketProxyFactory.ensureWebSocketProxy(this.device, debugData.applicationIdentifier, projectName, debugData.projectDir);
            return this.getChromeDebugUrl(debugOptions, webSocketProxy.options.port);
        });
    }
    setupTcpAppDebugProxy(debugData, debugOptions) {
        return __awaiter(this, void 0, void 0, function* () {
            const projectName = this.getProjectName(debugData);
            const existingTcpProxy = this.$appDebugSocketProxyFactory.getTCPSocketProxy(this.deviceIdentifier, debugData.applicationIdentifier);
            const tcpSocketProxy = existingTcpProxy || (yield this.$appDebugSocketProxyFactory.addTCPSocketProxy(this.device, debugData.applicationIdentifier, projectName, debugData.projectDir));
            if (!existingTcpProxy) {
                const inspectorProcess = yield this.openAppInspector(tcpSocketProxy.address(), debugData, debugOptions);
                if (inspectorProcess) {
                    tcpSocketProxy.on("close", () => __awaiter(this, void 0, void 0, function* () {
                        yield this.killProcess(inspectorProcess);
                    }));
                }
            }
            return null;
        });
    }
    openAppInspector(fileDescriptor, debugData, debugOptions) {
        return __awaiter(this, void 0, void 0, function* () {
            if (debugOptions.client) {
                const inspectorPath = yield this.$packageInstallationManager.getInspectorFromCache(inspectorNpmPackageName, debugData.projectDir);
                const inspectorSourceLocation = path.join(inspectorPath, inspectorUiDir, "Main.html");
                const inspectorApplicationPath = path.join(inspectorPath, inspectorAppName, "Contents", "MacOS", inspectorAppName, "Contents", "MacOS", "NativeScript Inspector");
                const inspectorProcess = this.$childProcess.spawn(inspectorApplicationPath, [inspectorSourceLocation, debugData.projectName, fileDescriptor]);
                inspectorProcess.on("error", (e) => this.$logger.trace(e));
                return inspectorProcess;
            }
            else {
                this.$logger.info("Suppressing debugging client.");
                return null;
            }
        });
    }
}
__decorate([
    decorators_1.performanceLog()
], IOSDeviceDebugService.prototype, "debug", null);
__decorate([
    decorators_1.performanceLog()
], IOSDeviceDebugService.prototype, "wireDebuggerClient", null);
__decorate([
    decorators_1.performanceLog()
], IOSDeviceDebugService.prototype, "openAppInspector", null);
exports.IOSDeviceDebugService = IOSDeviceDebugService;
$injector.register("iOSDeviceDebugService", IOSDeviceDebugService, false);
