"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ApplicationManagerBase = void 0;
const events_1 = require("events");
const constants_1 = require("../constants");
const _ = require("lodash");
class ApplicationManagerBase extends events_1.EventEmitter {
    constructor($logger, $hooksService, $deviceLogProvider) {
        super();
        this.$logger = $logger;
        this.$hooksService = $hooksService;
        this.$deviceLogProvider = $deviceLogProvider;
        this.lastAvailableDebuggableAppViews = {};
    }
    async setTransferredAppFiles(files) {
        for (const file of files) {
            await this.$deviceLogProvider.setSourceFileLocation(file);
        }
    }
    async reinstallApplication(appIdentifier, packageFilePath, buildData) {
        const isApplicationInstalled = await this.isApplicationInstalled(appIdentifier);
        if (isApplicationInstalled && (buildData === null || buildData === void 0 ? void 0 : buildData.clean)) {
            await this.uninstallApplication(appIdentifier);
        }
        await this.installApplication(packageFilePath, appIdentifier, buildData);
    }
    async restartApplication(appData) {
        await this.stopApplication(appData);
        await this.startApplication(appData);
    }
    async isApplicationInstalled(appIdentifier) {
        await this.checkForApplicationUpdates();
        return _.includes(this.lastInstalledAppIdentifiers, appIdentifier);
    }
    async checkForApplicationUpdates() {
        if (!this.checkForApplicationUpdatesPromise) {
            this.checkForApplicationUpdatesPromise = new Promise(async (resolve, reject) => {
                let isFulfilled = false;
                try {
                    const currentlyInstalledAppIdentifiers = await this.getInstalledApplications();
                    const previouslyInstalledAppIdentifiers = this.lastInstalledAppIdentifiers || [];
                    const newAppIdentifiers = _.difference(currentlyInstalledAppIdentifiers, previouslyInstalledAppIdentifiers);
                    const removedAppIdentifiers = _.difference(previouslyInstalledAppIdentifiers, currentlyInstalledAppIdentifiers);
                    this.lastInstalledAppIdentifiers = currentlyInstalledAppIdentifiers;
                    _.each(newAppIdentifiers, (appIdentifier) => this.emit("applicationInstalled", appIdentifier));
                    _.each(removedAppIdentifiers, (appIdentifier) => this.emit("applicationUninstalled", appIdentifier));
                    await this.checkForAvailableDebuggableAppsChanges();
                }
                catch (err) {
                    isFulfilled = true;
                    reject(err);
                }
                finally {
                    this.checkForApplicationUpdatesPromise = null;
                    if (!isFulfilled) {
                        resolve();
                    }
                }
            });
        }
        return this.checkForApplicationUpdatesPromise;
    }
    async tryStartApplication(appData) {
        try {
            await this.startApplication(appData);
        }
        catch (err) {
            this.$logger.trace(`Unable to start application ${appData.appId} with name ${appData.projectName}. Error is: ${err.message}`);
        }
    }
    async checkForAvailableDebuggableAppsChanges() {
        const currentlyAvailableDebuggableApps = await this.getDebuggableApps();
        const previouslyAvailableDebuggableApps = this.lastAvailableDebuggableApps || [];
        const newAvailableDebuggableApps = _.differenceBy(currentlyAvailableDebuggableApps, previouslyAvailableDebuggableApps, "appIdentifier");
        const notAvailableAppsForDebugging = _.differenceBy(previouslyAvailableDebuggableApps, currentlyAvailableDebuggableApps, "appIdentifier");
        this.lastAvailableDebuggableApps = currentlyAvailableDebuggableApps;
        _.each(newAvailableDebuggableApps, (appInfo) => {
            this.emit("debuggableAppFound", appInfo);
        });
        _.each(notAvailableAppsForDebugging, (appInfo) => {
            this.emit("debuggableAppLost", appInfo);
            if (_.has(this.lastAvailableDebuggableAppViews, appInfo.appIdentifier)) {
                delete this.lastAvailableDebuggableAppViews[appInfo.appIdentifier];
            }
        });
        const cordovaDebuggableAppIdentifiers = _(currentlyAvailableDebuggableApps)
            .filter((c) => c.framework === constants_1.TARGET_FRAMEWORK_IDENTIFIERS.Cordova)
            .map((c) => c.appIdentifier)
            .value();
        const currentlyAvailableAppViews = await this.getDebuggableAppViews(cordovaDebuggableAppIdentifiers);
        _.each(currentlyAvailableAppViews, (currentlyAvailableViews, appIdentifier) => {
            const previouslyAvailableViews = this.lastAvailableDebuggableAppViews[appIdentifier];
            const newAvailableViews = _.differenceBy(currentlyAvailableViews, previouslyAvailableViews, "id");
            const notAvailableViews = _.differenceBy(previouslyAvailableViews, currentlyAvailableViews, "id");
            _.each(notAvailableViews, (debugWebViewInfo) => {
                this.emit("debuggableViewLost", appIdentifier, debugWebViewInfo);
            });
            _.each(newAvailableViews, (debugWebViewInfo) => {
                this.emit("debuggableViewFound", appIdentifier, debugWebViewInfo);
            });
            const keptViews = _.differenceBy(currentlyAvailableViews, newAvailableViews, "id");
            _.each(keptViews, (view) => {
                const previousTimeViewInfo = _.find(previouslyAvailableViews, (previousView) => previousView.id === view.id);
                if (!_.isEqual(view, previousTimeViewInfo)) {
                    this.emit("debuggableViewChanged", appIdentifier, view);
                }
            });
            this.lastAvailableDebuggableAppViews[appIdentifier] =
                currentlyAvailableViews;
        });
    }
}
exports.ApplicationManagerBase = ApplicationManagerBase;
