"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 decorators_1 = require("../../decorators");
class IOSDeviceBase {
    constructor() {
        this.cachedSockets = {};
    }
    getDebugSocket(appId, projectName, projectDir, ensureAppStarted = false) {
        return __awaiter(this, void 0, void 0, function* () {
            return this.$lockService.executeActionWithLock(() => __awaiter(this, void 0, void 0, function* () {
                if (this.cachedSockets[appId]) {
                    return this.cachedSockets[appId];
                }
                yield this.attachToDebuggerFoundEvent(appId, projectName, projectDir);
                if (ensureAppStarted) {
                    yield this.applicationManager.startApplication({ appId, projectName, projectDir });
                }
                this.cachedSockets[appId] = yield this.getDebugSocketCore(appId);
                if (this.cachedSockets[appId]) {
                    this.cachedSockets[appId].on("close", () => __awaiter(this, void 0, void 0, function* () {
                        yield this.destroyDebugSocket(appId);
                    }));
                }
                return this.cachedSockets[appId];
            }), `ios-debug-socket-${this.deviceInfo.identifier}-${appId}.lock`);
        });
    }
    attachToDebuggerFoundEvent(appId, projectName, projectDir) {
        return __awaiter(this, void 0, void 0, function* () {
            yield this.startDeviceLogProcess(projectName, projectDir);
            yield this.$iOSDebuggerPortService.attachToDebuggerPortFoundEvent(appId);
        });
    }
    getDebuggerPort(appId) {
        return __awaiter(this, void 0, void 0, function* () {
            const port = yield this.$iOSDebuggerPortService.getPort({ deviceId: this.deviceInfo.identifier, appId });
            if (!port) {
                this.$errors.failWithoutHelp("Device socket port cannot be found.");
            }
            return port;
        });
    }
    destroyAllSockets() {
        return __awaiter(this, void 0, void 0, function* () {
            for (const appId in this.cachedSockets) {
                yield this.destroySocketSafe(this.cachedSockets[appId]);
            }
            this.cachedSockets = {};
        });
    }
    destroyDebugSocket(appId) {
        return __awaiter(this, void 0, void 0, function* () {
            yield this.destroySocketSafe(this.cachedSockets[appId]);
            this.cachedSockets[appId] = null;
        });
    }
    destroySocketSafe(socket) {
        return __awaiter(this, void 0, void 0, function* () {
            if (socket && !socket.destroyed) {
                return new Promise((resolve, reject) => {
                    socket.on("close", resolve);
                    socket.destroy();
                });
            }
        });
    }
    startDeviceLogProcess(projectName, projectDir) {
        return __awaiter(this, void 0, void 0, function* () {
            if (projectName) {
                this.$deviceLogProvider.setProjectNameForDevice(this.deviceInfo.identifier, projectName);
                this.$deviceLogProvider.setProjectDirForDevice(this.deviceInfo.identifier, projectDir);
            }
            yield this.openDeviceLogStream();
        });
    }
}
__decorate([
    decorators_1.performanceLog()
], IOSDeviceBase.prototype, "getDebugSocket", null);
exports.IOSDeviceBase = IOSDeviceBase;
