"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) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    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) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.PlatformLiveSyncServiceBase = void 0;
const path = require("path");
const util = require("util");
const _ = require("lodash");
const constants_1 = require("../../constants");
const helpers_1 = require("../../common/helpers");
const decorators_1 = require("../../common/decorators");
const color_1 = require("../../color");
class PlatformLiveSyncServiceBase {
    constructor($fs, $logger, $platformsDataService, $projectFilesManager, $devicePathProvider, $options) {
        this.$fs = $fs;
        this.$logger = $logger;
        this.$platformsDataService = $platformsDataService;
        this.$projectFilesManager = $projectFilesManager;
        this.$devicePathProvider = $devicePathProvider;
        this.$options = $options;
        this._deviceLiveSyncServicesCache = {};
    }
    getDeviceLiveSyncService(device, projectData) {
        const platform = device.deviceInfo.platform.toLowerCase();
        const platformData = this.$platformsDataService.getPlatformData(device.deviceInfo.platform, projectData);
        const frameworkVersion = platformData.platformProjectService.getFrameworkVersion(projectData);
        const key = (0, helpers_1.getHash)(`${device.deviceInfo.identifier}${projectData.projectIdentifiers[platform]}${projectData.projectDir}${frameworkVersion}`);
        if (!this._deviceLiveSyncServicesCache[key]) {
            this._deviceLiveSyncServicesCache[key] = this._getDeviceLiveSyncService(device, projectData, frameworkVersion);
        }
        return this._deviceLiveSyncServicesCache[key];
    }
    shouldRestart(projectData, liveSyncInfo) {
        return __awaiter(this, void 0, void 0, function* () {
            const deviceLiveSyncService = this.getDeviceLiveSyncService(liveSyncInfo.deviceAppData.device, projectData);
            const shouldRestart = yield deviceLiveSyncService.shouldRestart(projectData, liveSyncInfo);
            return shouldRestart;
        });
    }
    syncAfterInstall(device, liveSyncInfo) {
        return __awaiter(this, void 0, void 0, function* () {
            /* intentionally left blank */
        });
    }
    restartApplication(projectData, liveSyncInfo) {
        return __awaiter(this, void 0, void 0, function* () {
            const deviceLiveSyncService = this.getDeviceLiveSyncService(liveSyncInfo.deviceAppData.device, projectData);
            this.$logger.info(`Restarting application on device ${liveSyncInfo.deviceAppData.device.deviceInfo.identifier}...`);
            yield deviceLiveSyncService.restartApplication(projectData, liveSyncInfo);
        });
    }
    tryRefreshApplication(projectData, liveSyncInfo) {
        return __awaiter(this, void 0, void 0, function* () {
            let didRefresh = true;
            if (liveSyncInfo.isFullSync || liveSyncInfo.modifiedFilesData.length) {
                const deviceLiveSyncService = this.getDeviceLiveSyncService(liveSyncInfo.deviceAppData.device, projectData);
                this.$logger.info(`Refreshing application on device ${liveSyncInfo.deviceAppData.device.deviceInfo.identifier}...`);
                didRefresh = yield deviceLiveSyncService.tryRefreshApplication(projectData, liveSyncInfo);
            }
            return didRefresh;
        });
    }
    fullSync(syncInfo) {
        return __awaiter(this, void 0, void 0, function* () {
            const projectData = syncInfo.projectData;
            const device = syncInfo.device;
            const deviceLiveSyncService = this.getDeviceLiveSyncService(device, syncInfo.projectData);
            const platformData = this.$platformsDataService.getPlatformData(device.deviceInfo.platform, projectData);
            const deviceAppData = yield this.getAppData(syncInfo);
            if (deviceLiveSyncService.beforeLiveSyncAction) {
                yield deviceLiveSyncService.beforeLiveSyncAction(deviceAppData);
            }
            const projectFilesPath = path.join(platformData.appDestinationDirectoryPath, this.$options.hostProjectModuleName);
            const localToDevicePaths = yield this.$projectFilesManager.createLocalToDevicePaths(deviceAppData, projectFilesPath, null, []);
            const modifiedFilesData = yield this.transferFiles(deviceAppData, localToDevicePaths, projectFilesPath, projectData, syncInfo.liveSyncDeviceData, { isFullSync: true, force: syncInfo.force });
            return {
                modifiedFilesData,
                isFullSync: true,
                deviceAppData,
                useHotModuleReload: syncInfo.useHotModuleReload,
            };
        });
    }
    liveSyncWatchAction(device, liveSyncInfo) {
        return __awaiter(this, void 0, void 0, function* () {
            const projectData = liveSyncInfo.projectData;
            const deviceLiveSyncService = this.getDeviceLiveSyncService(device, projectData);
            const syncInfo = _.merge({ device, watch: true }, liveSyncInfo);
            const deviceAppData = yield this.getAppData(syncInfo);
            if (deviceLiveSyncService.beforeLiveSyncAction) {
                yield deviceLiveSyncService.beforeLiveSyncAction(deviceAppData);
            }
            let modifiedLocalToDevicePaths = [];
            if (liveSyncInfo.filesToSync.length) {
                const filesToSync = liveSyncInfo.filesToSync;
                // const mappedFiles = _.map(filesToSync, filePath => this.$projectFilesProvider.mapFilePath(filePath, device.deviceInfo.platform, projectData));
                // Some plugins modify platforms dir on afterPrepare (check nativescript-dev-sass) - we want to sync only existing file.
                const existingFiles = filesToSync.filter((m) => m && this.$fs.exists(m));
                this.$logger.trace("Will execute livesync for files: ", existingFiles);
                const skippedFiles = _.difference(filesToSync, existingFiles);
                if (skippedFiles.length) {
                    this.$logger.trace("The following files will not be synced as they do not exist:", skippedFiles);
                }
                if (existingFiles.length) {
                    const platformData = this.$platformsDataService.getPlatformData(device.deviceInfo.platform, projectData);
                    const projectFilesPath = path.join(platformData.appDestinationDirectoryPath, this.$options.hostProjectModuleName);
                    const localToDevicePaths = yield this.$projectFilesManager.createLocalToDevicePaths(deviceAppData, projectFilesPath, existingFiles, []);
                    modifiedLocalToDevicePaths.push(...localToDevicePaths);
                    modifiedLocalToDevicePaths = yield this.transferFiles(deviceAppData, localToDevicePaths, projectFilesPath, projectData, liveSyncInfo.liveSyncDeviceData, { isFullSync: false, force: liveSyncInfo.force });
                }
            }
            if (liveSyncInfo.filesToRemove.length) {
                const filePaths = liveSyncInfo.filesToRemove;
                const platformData = this.$platformsDataService.getPlatformData(device.deviceInfo.platform, projectData);
                const mappedFiles = _(filePaths)
                    // .map(filePath => this.$projectFilesProvider.mapFilePath(filePath, device.deviceInfo.platform, projectData))
                    .filter((filePath) => !!filePath)
                    .value();
                const projectFilesPath = path.join(platformData.appDestinationDirectoryPath, constants_1.APP_FOLDER_NAME);
                const localToDevicePaths = yield this.$projectFilesManager.createLocalToDevicePaths(deviceAppData, projectFilesPath, mappedFiles, []);
                modifiedLocalToDevicePaths.push(...localToDevicePaths);
                yield deviceLiveSyncService.removeFiles(deviceAppData, localToDevicePaths, projectFilesPath);
            }
            return {
                modifiedFilesData: modifiedLocalToDevicePaths,
                isFullSync: false,
                deviceAppData,
                useHotModuleReload: liveSyncInfo.useHotModuleReload,
            };
        });
    }
    transferFiles(deviceAppData, localToDevicePaths, projectFilesPath, projectData, liveSyncDeviceData, options) {
        return __awaiter(this, void 0, void 0, function* () {
            let transferredFiles = [];
            const deviceLiveSyncService = this.getDeviceLiveSyncService(deviceAppData.device, projectData);
            transferredFiles = yield deviceLiveSyncService.transferFiles(deviceAppData, localToDevicePaths, projectFilesPath, projectData, liveSyncDeviceData, options);
            yield deviceAppData.device.applicationManager.setTransferredAppFiles(localToDevicePaths.map((l) => l.getLocalPath()));
            this.logFilesSyncInformation(transferredFiles, "Successfully transferred %s on device %s.", this.$logger.info, deviceAppData.device.deviceInfo.identifier);
            return transferredFiles;
        });
    }
    getAppData(syncInfo) {
        return __awaiter(this, void 0, void 0, function* () {
            const platform = syncInfo.device.deviceInfo.platform.toLowerCase();
            const appIdentifier = syncInfo.projectData.projectIdentifiers[platform];
            const deviceProjectRootOptions = _.assign({ appIdentifier }, syncInfo);
            return {
                appIdentifier,
                device: syncInfo.device,
                platform: syncInfo.device.deviceInfo.platform,
                getDeviceProjectRootPath: () => this.$devicePathProvider.getDeviceProjectRootPath(syncInfo.device, deviceProjectRootOptions),
                deviceSyncZipPath: this.$devicePathProvider.getDeviceSyncZipPath(syncInfo.device),
                connectTimeout: syncInfo.connectTimeout,
                projectDir: syncInfo.projectData.projectDir,
            };
        });
    }
    logFilesSyncInformation(localToDevicePaths, message, action, deviceIdentifier) {
        if (localToDevicePaths && localToDevicePaths.length < 10) {
            _.each(localToDevicePaths, (file) => {
                action.call(this.$logger, util.format(message, color_1.color.yellow(path.basename(file.getLocalPath()))), deviceIdentifier);
            });
        }
        else {
            action.call(this.$logger, util.format(message, "all files", deviceIdentifier));
        }
    }
}
__decorate([
    (0, decorators_1.performanceLog)()
], PlatformLiveSyncServiceBase.prototype, "liveSyncWatchAction", null);
exports.PlatformLiveSyncServiceBase = PlatformLiveSyncServiceBase;
//# sourceMappingURL=platform-livesync-service-base.js.map