"use strict";
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.PlatformCommandHelper = void 0;
const path = require("path");
const semver = require("semver");
const _ = require("lodash");
const constants = require("../constants");
const yok_1 = require("../common/yok");
class PlatformCommandHelper {
    constructor($platformController, $fs, $errors, $logger, $options, $mobileHelper, $packageInstallationManager, $pacoteService, $platformsDataService, $platformValidationService, $projectChangesService, $projectDataService, $tempService) {
        this.$platformController = $platformController;
        this.$fs = $fs;
        this.$errors = $errors;
        this.$logger = $logger;
        this.$options = $options;
        this.$mobileHelper = $mobileHelper;
        this.$packageInstallationManager = $packageInstallationManager;
        this.$pacoteService = $pacoteService;
        this.$platformsDataService = $platformsDataService;
        this.$platformValidationService = $platformValidationService;
        this.$projectChangesService = $projectChangesService;
        this.$projectDataService = $projectDataService;
        this.$tempService = $tempService;
    }
    addPlatforms(platforms, projectData, frameworkPath) {
        return __awaiter(this, void 0, void 0, function* () {
            if (this.$options.hostProjectPath) {
                this.$logger.info("Ignoring platform add becuase of --hostProjectPath flag");
                return;
            }
            const platformsDir = projectData.platformsDir;
            this.$fs.ensureDirectoryExists(platformsDir);
            for (const platform of platforms) {
                this.$platformValidationService.validatePlatform(platform, projectData);
                const platformPath = path.join(projectData.platformsDir, platform);
                const isPlatformAdded = this.isPlatformAdded(platform, platformPath, projectData);
                if (isPlatformAdded) {
                    this.$errors.fail(`Platform ${platform} already added`);
                }
                yield this.$platformController.addPlatform({
                    projectDir: projectData.projectDir,
                    platform,
                    frameworkPath,
                });
            }
        });
    }
    cleanPlatforms(platforms, projectData, framworkPath) {
        return __awaiter(this, void 0, void 0, function* () {
            for (const platform of platforms) {
                const version = this.getCurrentPlatformVersion(platform, projectData);
                yield this.removePlatforms([platform], projectData);
                const platformParam = version ? `${platform}@${version}` : platform;
                yield this.addPlatforms([platformParam], projectData, framworkPath);
            }
        });
    }
    removePlatforms(platforms, projectData) {
        return __awaiter(this, void 0, void 0, function* () {
            if (this.$options.hostProjectPath) {
                this.$logger.info("Ignoring platform remove becuase of --native-host flag");
                return;
            }
            for (const platform of platforms) {
                this.$platformValidationService.validatePlatformInstalled(platform, projectData);
                const platformData = this.$platformsDataService.getPlatformData(platform, projectData);
                let errorMessage;
                try {
                    yield platformData.platformProjectService.stopServices(platformData.projectRoot);
                }
                catch (err) {
                    errorMessage = err.message;
                }
                try {
                    const platformDir = path.join(projectData.platformsDir, platform.toLowerCase());
                    this.$fs.deleteDirectory(platformDir);
                    yield this.$packageInstallationManager.uninstall(platformData.frameworkPackageName, projectData.projectDir);
                    // this.$projectDataService.removeNSProperty(
                    // 	projectData.projectDir,
                    // 	platformData.frameworkPackageName
                    // );
                    this.$logger.info(`Platform ${platform} successfully removed.`);
                }
                catch (err) {
                    this.$logger.error(`Failed to remove ${platform} platform with errors:`);
                    if (errorMessage) {
                        this.$logger.error(errorMessage);
                    }
                    this.$errors.fail(err.message);
                }
            }
        });
    }
    updatePlatforms(platforms, projectData) {
        return __awaiter(this, void 0, void 0, function* () {
            for (const platformParam of platforms) {
                const data = platformParam.split("@"), platform = data[0], version = data[1];
                const hasPlatformDirectory = this.$fs.exists(path.join(projectData.platformsDir, platform.toLowerCase()));
                if (hasPlatformDirectory) {
                    yield this.updatePlatform(platform, version, projectData);
                }
                else {
                    yield this.$platformController.addPlatform({
                        projectDir: projectData.projectDir,
                        platform: platformParam,
                    });
                }
            }
        });
    }
    getInstalledPlatforms(projectData) {
        if (!this.$fs.exists(projectData.platformsDir)) {
            return [];
        }
        const subDirs = this.$fs.readDirectory(projectData.platformsDir);
        const platforms = this.$mobileHelper.platformNames.map((p) => p.toLowerCase());
        return _.filter(subDirs, (p) => platforms.indexOf(p) > -1);
    }
    getAvailablePlatforms(projectData) {
        const installedPlatforms = this.getInstalledPlatforms(projectData);
        return _.filter(this.$mobileHelper.platformNames, (p) => {
            return (installedPlatforms.indexOf(p) < 0 &&
                this.$platformValidationService.isPlatformSupportedForOS(p, projectData)); // Only those not already installed
        });
    }
    getPreparedPlatforms(projectData) {
        return _.filter(this.$mobileHelper.platformNames, (p) => {
            return this.isPlatformPrepared(p, projectData);
        });
    }
    getCurrentPlatformVersion(platform, projectData) {
        const platformData = this.$platformsDataService.getPlatformData(platform, projectData);
        const currentPlatformData = this.$projectDataService.getRuntimePackage(projectData.projectDir, platformData.platformNameLowerCase);
        const version = currentPlatformData && currentPlatformData.version;
        return version;
    }
    isPlatformAdded(platform, platformPath, projectData) {
        if (!this.$fs.exists(platformPath)) {
            return false;
        }
        const platformData = this.$platformsDataService.getPlatformData(platform, projectData);
        const prepareInfo = this.$projectChangesService.getPrepareInfo(platformData);
        if (!prepareInfo) {
            return true;
        }
        return (prepareInfo.nativePlatformStatus !==
            "1" /* constants.NativePlatformStatus.requiresPlatformAdd */);
    }
    updatePlatform(platform, version, projectData) {
        return __awaiter(this, void 0, void 0, function* () {
            const platformData = this.$platformsDataService.getPlatformData(platform, projectData);
            const data = this.$projectDataService.getRuntimePackage(projectData.projectDir, platformData.platformNameLowerCase);
            const currentVersion = data && data.version ? data.version : "0.2.0";
            const installedModuleDir = yield this.$tempService.mkdirSync("runtime-to-update");
            let newVersion = version === constants.PackageVersion.NEXT
                ? yield this.$packageInstallationManager.getNextVersion(platformData.frameworkPackageName)
                : version ||
                    (yield this.$packageInstallationManager.getLatestCompatibleVersion(platformData.frameworkPackageName));
            yield this.$pacoteService.extractPackage(`${platformData.frameworkPackageName}@${newVersion}`, installedModuleDir);
            const cachedPackageData = this.$fs.readJson(path.join(installedModuleDir, "package.json"));
            newVersion = (cachedPackageData && cachedPackageData.version) || newVersion;
            if (!semver.valid(newVersion)) {
                this.$errors.fail("The version %s is not valid. The version should consists from 3 parts separated by dot.", newVersion);
            }
            if (!semver.gt(currentVersion, newVersion)) {
                yield this.updatePlatformCore(platformData, { currentVersion, newVersion }, projectData);
            }
            else if (semver.eq(currentVersion, newVersion)) {
                this.$errors.fail("Current and new version are the same.");
            }
            else {
                this.$errors.fail(`Your current version: ${currentVersion} is higher than the one you're trying to install ${newVersion}.`);
            }
        });
    }
    updatePlatformCore(platformData, updateOptions, projectData) {
        return __awaiter(this, void 0, void 0, function* () {
            let packageName = platformData.normalizedPlatformName.toLowerCase();
            yield this.removePlatforms([packageName], projectData);
            packageName = updateOptions.newVersion
                ? `${packageName}@${updateOptions.newVersion}`
                : packageName;
            yield this.$platformController.addPlatform({
                projectDir: projectData.projectDir,
                platform: packageName,
            });
            this.$logger.info("Successfully updated to version ", updateOptions.newVersion);
        });
    }
    isPlatformPrepared(platform, projectData) {
        const platformData = this.$platformsDataService.getPlatformData(platform, projectData);
        return platformData.platformProjectService.isPlatformPrepared(platformData.projectRoot, projectData);
    }
}
exports.PlatformCommandHelper = PlatformCommandHelper;
yok_1.injector.register("platformCommandHelper", PlatformCommandHelper);
//# sourceMappingURL=platform-command-helper.js.map