"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 path = require("path");
var shell = require("shelljs");
var constants = require("../constants");
var helpers = require("../common/helpers");
var semver = require("semver");
var app_files_updater_1 = require("./app-files-updater");
var temp = require("temp");
var project_changes_info_1 = require("./project-changes-info");
temp.track();
var clui = require("clui");
var buildInfoFileName = ".nsbuildinfo";
var PlatformService = (function () {
    function PlatformService($devicesService, $errors, $fs, $logger, $npmInstallationManager, $platformsData, $projectData, $projectDataService, $prompter, $hooksService, $commandsService, $options, $nodeModulesBuilder, $pluginsService, $projectFilesManager, $mobileHelper, $hostInfo, $xmlValidator, $npm, $sysInfo, $staticConfig, $devicePlatformsConstants, $childProcess) {
        this.$devicesService = $devicesService;
        this.$errors = $errors;
        this.$fs = $fs;
        this.$logger = $logger;
        this.$npmInstallationManager = $npmInstallationManager;
        this.$platformsData = $platformsData;
        this.$projectData = $projectData;
        this.$projectDataService = $projectDataService;
        this.$prompter = $prompter;
        this.$hooksService = $hooksService;
        this.$commandsService = $commandsService;
        this.$options = $options;
        this.$nodeModulesBuilder = $nodeModulesBuilder;
        this.$pluginsService = $pluginsService;
        this.$projectFilesManager = $projectFilesManager;
        this.$mobileHelper = $mobileHelper;
        this.$hostInfo = $hostInfo;
        this.$xmlValidator = $xmlValidator;
        this.$npm = $npm;
        this.$sysInfo = $sysInfo;
        this.$staticConfig = $staticConfig;
        this.$devicePlatformsConstants = $devicePlatformsConstants;
        this.$childProcess = $childProcess;
    }
    PlatformService.prototype.addPlatforms = function (platforms) {
        var _this = this;
        return (function () {
            var platformsDir = _this.$projectData.platformsDir;
            _this.$fs.ensureDirectoryExists(platformsDir).wait();
            _.each(platforms, function (platform) {
                _this.addPlatform(platform.toLowerCase()).wait();
            });
        }).future()();
    };
    PlatformService.prototype.addPlatform = function (platformParam) {
        var _this = this;
        return (function () {
            var _a = platformParam.split("@"), platform = _a[0], version = _a[1];
            _this.validatePlatform(platform);
            var platformPath = path.join(_this.$projectData.platformsDir, platform);
            if (_this.$fs.exists(platformPath).wait()) {
                _this.$errors.failWithoutHelp("Platform %s already added", platform);
            }
            var platformData = _this.$platformsData.getPlatformData(platform);
            var platformProjectService = platformData.platformProjectService;
            platformProjectService.validate().wait();
            _this.$logger.trace("Creating NativeScript project for the %s platform", platform);
            _this.$logger.trace("Path: %s", platformData.projectRoot);
            _this.$logger.trace("Package: %s", _this.$projectData.projectId);
            _this.$logger.trace("Name: %s", _this.$projectData.projectName);
            _this.$logger.out("Copying template files...");
            var packageToInstall = "";
            var npmOptions = {
                pathToSave: path.join(_this.$projectData.platformsDir, platform),
                dependencyType: "save"
            };
            if (!_this.$options.frameworkPath) {
                packageToInstall = platformData.frameworkPackageName;
                npmOptions["version"] = version;
            }
            var spinner = new clui.Spinner("Installing " + packageToInstall);
            try {
                spinner.start();
                var downloadedPackagePath = _this.$npmInstallationManager.install(packageToInstall, _this.$projectData.projectDir, npmOptions).wait();
                var frameworkDir = path.join(downloadedPackagePath, constants.PROJECT_FRAMEWORK_FOLDER_NAME);
                frameworkDir = path.resolve(frameworkDir);
                var coreModuleName = _this.addPlatformCore(platformData, frameworkDir).wait();
                _this.$npm.uninstall(coreModuleName, { save: true }, _this.$projectData.projectDir).wait();
            }
            catch (err) {
                _this.$fs.deleteDirectory(platformPath).wait();
                throw err;
            }
            finally {
                spinner.stop();
            }
            _this.$logger.out("Project successfully created.");
        }).future()();
    };
    PlatformService.prototype.addPlatformCore = function (platformData, frameworkDir) {
        var _this = this;
        return (function () {
            var coreModuleData = _this.$fs.readJson(path.join(frameworkDir, "../", "package.json")).wait();
            var installedVersion = coreModuleData.version;
            var coreModuleName = coreModuleData.name;
            _this.$projectDataService.initialize(_this.$projectData.projectDir);
            var customTemplateOptions = _this.getPathToPlatformTemplate(_this.$options.platformTemplate, platformData.frameworkPackageName).wait();
            var pathToTemplate = customTemplateOptions && customTemplateOptions.pathToTemplate;
            platformData.platformProjectService.createProject(path.resolve(frameworkDir), installedVersion, pathToTemplate).wait();
            platformData.platformProjectService.ensureConfigurationFileInAppResources().wait();
            platformData.platformProjectService.interpolateData().wait();
            platformData.platformProjectService.afterCreateProject(platformData.projectRoot).wait();
            _this.applyBaseConfigOption(platformData).wait();
            var frameworkPackageNameData = { version: installedVersion };
            if (customTemplateOptions) {
                frameworkPackageNameData.template = customTemplateOptions.selectedTemplate;
            }
            _this.$projectDataService.setValue(platformData.frameworkPackageName, frameworkPackageNameData).wait();
            return coreModuleName;
        }).future()();
    };
    PlatformService.prototype.getPathToPlatformTemplate = function (selectedTemplate, frameworkPackageName) {
        var _this = this;
        return (function () {
            if (!selectedTemplate) {
                var nativescriptPlatformData = _this.$projectDataService.getValue(frameworkPackageName).wait();
                selectedTemplate = nativescriptPlatformData && nativescriptPlatformData.template;
            }
            if (selectedTemplate) {
                var tempDir = temp.mkdirSync("platform-template");
                try {
                    var pathToTemplate = _this.$npm.install(selectedTemplate, tempDir).wait()[0];
                    return { selectedTemplate: selectedTemplate, pathToTemplate: pathToTemplate };
                }
                catch (err) {
                    _this.$logger.trace("Error while trying to install specified template: ", err);
                    _this.$errors.failWithoutHelp("Unable to install platform template " + selectedTemplate + ". Make sure the specified value is valid.");
                }
            }
            return null;
        }).future()();
    };
    PlatformService.prototype.getInstalledPlatforms = function () {
        var _this = this;
        return (function () {
            if (!_this.$fs.exists(_this.$projectData.platformsDir).wait()) {
                return [];
            }
            var subDirs = _this.$fs.readDirectory(_this.$projectData.platformsDir).wait();
            return _.filter(subDirs, function (p) { return _this.$platformsData.platformsNames.indexOf(p) > -1; });
        }).future()();
    };
    PlatformService.prototype.getAvailablePlatforms = function () {
        var _this = this;
        return (function () {
            var installedPlatforms = _this.getInstalledPlatforms().wait();
            return _.filter(_this.$platformsData.platformsNames, function (p) {
                return installedPlatforms.indexOf(p) < 0 && _this.isPlatformSupportedForOS(p);
            });
        }).future()();
    };
    PlatformService.prototype.getPreparedPlatforms = function () {
        var _this = this;
        return (function () {
            return _.filter(_this.$platformsData.platformsNames, function (p) { return _this.isPlatformPrepared(p).wait(); });
        }).future()();
    };
    PlatformService.prototype.preparePlatform = function (platform, force, skipModulesAndResources) {
        var _this = this;
        return (function () {
            _this.validatePlatform(platform);
            try {
                _this.$pluginsService.ensureAllDependenciesAreInstalled().wait();
            }
            catch (err) {
                _this.$logger.trace(err);
                _this.$errors.failWithoutHelp("Unable to install dependencies. Make sure your package.json is valid and all dependencies are correct. Error is: " + err.message);
            }
            if (platform === "ios") {
                _.each(_this.$pluginsService.getAllInstalledPlugins().wait(), function (pluginData) {
                    if (_this.$fs.exists(path.join(pluginData.pluginPlatformsFolderPath(platform), "Podfile")).wait() &&
                        !_this.$sysInfo.getCocoapodVersion().wait()) {
                        _this.$errors.failWithoutHelp(pluginData.name + " has Podfile and you don't have Cocoapods installed or it is not configured correctly. Please verify Cocoapods can work on your machine.");
                    }
                });
            }
            _this.ensurePlatformInstalled(platform).wait();
            var changeInfo = new project_changes_info_1.ProjectChangesInfo(platform, force, skipModulesAndResources, _this.$platformsData, _this.$projectData, _this.$devicePlatformsConstants, _this.$options, _this.$fs);
            _this._prepareInfo = changeInfo.prepareInfo;
            if (!_this.isPlatformPrepared(platform).wait() || changeInfo.hasChanges) {
                _this.preparePlatformCore(platform, changeInfo).wait();
                return true;
            }
            return false;
        }).future()();
    };
    PlatformService.prototype.preparePlatformCore = function (platform, changeInfo) {
        var _this = this;
        return (function () {
            var platformData = _this.$platformsData.getPlatformData(platform);
            if (changeInfo.appFilesChanged) {
                _this.copyAppFiles(platform).wait();
            }
            if (changeInfo.appResourcesChanged) {
                _this.copyAppResources(platform).wait();
                platformData.platformProjectService.prepareProject().wait();
            }
            if (changeInfo.modulesChanged) {
                _this.copyTnsModules(platform).wait();
            }
            var directoryPath = path.join(platformData.appDestinationDirectoryPath, constants.APP_FOLDER_NAME);
            var excludedDirs = [constants.APP_RESOURCES_FOLDER_NAME];
            if (!changeInfo.modulesChanged) {
                excludedDirs.push(constants.TNS_MODULES_FOLDER_NAME);
            }
            _this.$projectFilesManager.processPlatformSpecificFiles(directoryPath, platform, excludedDirs).wait();
            if (changeInfo.configChanged || changeInfo.modulesChanged) {
                _this.applyBaseConfigOption(platformData).wait();
                platformData.platformProjectService.processConfigurationFilesFromAppResources().wait();
            }
            platformData.platformProjectService.interpolateConfigurationFile().wait();
            _this.$logger.out("Project successfully prepared (" + platform + ")");
        }).future()();
    };
    PlatformService.prototype.copyAppFiles = function (platform) {
        var _this = this;
        return (function () {
            var platformData = _this.$platformsData.getPlatformData(platform);
            platformData.platformProjectService.ensureConfigurationFileInAppResources().wait();
            var appDestinationDirectoryPath = path.join(platformData.appDestinationDirectoryPath, constants.APP_FOLDER_NAME);
            _this.$fs.ensureDirectoryExists(appDestinationDirectoryPath).wait();
            var appSourceDirectoryPath = path.join(_this.$projectData.projectDir, constants.APP_FOLDER_NAME);
            var appUpdater = new app_files_updater_1.AppFilesUpdater(appSourceDirectoryPath, appDestinationDirectoryPath, _this.$options, _this.$fs);
            appUpdater.updateApp(function (sourceFiles) {
                _this.$xmlValidator.validateXmlFiles(sourceFiles).wait();
            });
        }).future()();
    };
    PlatformService.prototype.copyAppResources = function (platform) {
        var _this = this;
        return (function () {
            var platformData = _this.$platformsData.getPlatformData(platform);
            var appDestinationDirectoryPath = path.join(platformData.appDestinationDirectoryPath, constants.APP_FOLDER_NAME);
            var appResourcesDirectoryPath = path.join(appDestinationDirectoryPath, constants.APP_RESOURCES_FOLDER_NAME);
            if (_this.$fs.exists(appResourcesDirectoryPath).wait()) {
                platformData.platformProjectService.prepareAppResources(appResourcesDirectoryPath).wait();
                var appResourcesDestination = platformData.platformProjectService.getAppResourcesDestinationDirectoryPath().wait();
                _this.$fs.ensureDirectoryExists(appResourcesDestination).wait();
                shell.cp("-Rf", path.join(appResourcesDirectoryPath, platformData.normalizedPlatformName, "*"), appResourcesDestination);
                _this.$fs.deleteDirectory(appResourcesDirectoryPath).wait();
            }
        }).future()();
    };
    PlatformService.prototype.copyTnsModules = function (platform) {
        var _this = this;
        return (function () {
            var platformData = _this.$platformsData.getPlatformData(platform);
            var appDestinationDirectoryPath = path.join(platformData.appDestinationDirectoryPath, constants.APP_FOLDER_NAME);
            var lastModifiedTime = _this.$fs.exists(appDestinationDirectoryPath).wait() ? _this.$fs.getFsStats(appDestinationDirectoryPath).wait().mtime : null;
            try {
                var tnsModulesDestinationPath = path.join(appDestinationDirectoryPath, constants.TNS_MODULES_FOLDER_NAME);
                _this.$nodeModulesBuilder.prepareNodeModules(tnsModulesDestinationPath, platform, lastModifiedTime).wait();
            }
            catch (error) {
                _this.$logger.debug(error);
                shell.rm("-rf", appDestinationDirectoryPath);
                _this.$errors.failWithoutHelp("Processing node_modules failed. " + error);
            }
        }).future()();
    };
    PlatformService.prototype.cleanDestinationApp = function (platform) {
        var _this = this;
        return (function () {
            _this.ensurePlatformInstalled(platform).wait();
            var appSourceDirectoryPath = path.join(_this.$projectData.projectDir, constants.APP_FOLDER_NAME);
            var platformData = _this.$platformsData.getPlatformData(platform);
            var appDestinationDirectoryPath = path.join(platformData.appDestinationDirectoryPath, constants.APP_FOLDER_NAME);
            var appUpdater = new app_files_updater_1.AppFilesUpdater(appSourceDirectoryPath, appDestinationDirectoryPath, _this.$options, _this.$fs);
            appUpdater.cleanDestinationApp();
        }).future()();
    };
    PlatformService.prototype.buildPlatform = function (platform, buildConfig) {
        var _this = this;
        return (function () {
            platform = platform.toLowerCase();
            var platformData = _this.$platformsData.getPlatformData(platform);
            platformData.platformProjectService.buildProject(platformData.projectRoot, buildConfig).wait();
            _this.$logger.out("Project successfully built.");
        }).future()();
    };
    PlatformService.prototype.prepareAndBuild = function (platform, buildConfig, forceBuild) {
        var _this = this;
        return (function () {
            var shouldBuild = _this.preparePlatform(platform, false).wait();
            var platformData = _this.$platformsData.getPlatformData(platform);
            var buildInfoFilePath = _this.getBuildOutputPath(platform, platformData, buildConfig);
            var buildInfoFile = path.join(buildInfoFilePath, buildInfoFileName);
            if (!shouldBuild) {
                if (_this.$fs.exists(buildInfoFile).wait()) {
                    var buildInfoText = _this.$fs.readText(buildInfoFile).wait();
                    shouldBuild = _this._prepareInfo.time !== buildInfoText;
                }
                else {
                    shouldBuild = true;
                }
            }
            if (shouldBuild || forceBuild) {
                _this.buildForDeploy(platform, buildConfig).wait();
                _this.$fs.writeFile(buildInfoFile, _this._prepareInfo.time).wait();
            }
        }).future()();
    };
    PlatformService.prototype.getBuildOutputPath = function (platform, platformData, buildConfig) {
        var buildForDevice = buildConfig ? buildConfig.buildForDevice : this.$options.forDevice;
        if (platform === this.$devicePlatformsConstants.iOS.toLowerCase()) {
            return buildForDevice ? platformData.deviceBuildOutputPath : platformData.emulatorBuildOutputPath;
        }
        return platformData.deviceBuildOutputPath;
    };
    PlatformService.prototype.buildForDeploy = function (platform, buildConfig) {
        var _this = this;
        return (function () {
            platform = platform.toLowerCase();
            var platformData = _this.$platformsData.getPlatformData(platform);
            platformData.platformProjectService.buildForDeploy(platformData.projectRoot, buildConfig).wait();
            _this.$logger.out("Project successfully built");
        }).future()();
    };
    PlatformService.prototype.lastOutputPath = function (platform, settings) {
        var packageFile;
        var platformData = this.$platformsData.getPlatformData(platform);
        if (settings.isForDevice) {
            packageFile = this.getLatestApplicationPackageForDevice(platformData).wait().packageName;
        }
        else {
            packageFile = this.getLatestApplicationPackageForEmulator(platformData).wait().packageName;
        }
        if (!packageFile || !this.$fs.exists(packageFile).wait()) {
            this.$errors.failWithoutHelp("Unable to find built application. Try 'tns build %s'.", platform);
        }
        return packageFile;
    };
    PlatformService.prototype.copyLastOutput = function (platform, targetPath, settings) {
        var _this = this;
        return (function () {
            platform = platform.toLowerCase();
            targetPath = path.resolve(targetPath);
            var packageFile = _this.lastOutputPath(platform, settings);
            _this.$fs.ensureDirectoryExists(path.dirname(targetPath)).wait();
            if (_this.$fs.exists(targetPath).wait() && _this.$fs.getFsStats(targetPath).wait().isDirectory()) {
                var sourceFileName = path.basename(packageFile);
                _this.$logger.trace("Specified target path: '" + targetPath + "' is directory. Same filename will be used: '" + sourceFileName + "'.");
                targetPath = path.join(targetPath, sourceFileName);
            }
            _this.$fs.copyFile(packageFile, targetPath).wait();
            _this.$logger.info("Copied file '" + packageFile + "' to '" + targetPath + "'.");
        }).future()();
    };
    PlatformService.prototype.removePlatforms = function (platforms) {
        var _this = this;
        return (function () {
            _this.$projectDataService.initialize(_this.$projectData.projectDir);
            _.each(platforms, function (platform) {
                _this.validatePlatformInstalled(platform);
                var platformData = _this.$platformsData.getPlatformData(platform);
                var platformDir = path.join(_this.$projectData.platformsDir, platform);
                _this.$fs.deleteDirectory(platformDir).wait();
                _this.$projectDataService.removeProperty(platformData.frameworkPackageName).wait();
                _this.$logger.out("Platform " + platform + " successfully removed.");
            });
        }).future()();
    };
    PlatformService.prototype.updatePlatforms = function (platforms) {
        var _this = this;
        return (function () {
            _.each(platforms, function (platformParam) {
                var _a = platformParam.split("@"), platform = _a[0], version = _a[1];
                if (_this.isPlatformInstalled(platform).wait()) {
                    _this.updatePlatform(platform, version).wait();
                }
                else {
                    _this.addPlatform(platformParam).wait();
                }
            });
        }).future()();
    };
    PlatformService.prototype.runPlatform = function (platform, buildConfig) {
        platform = platform.toLowerCase();
        if (this.$options.emulator) {
            return this.deployOnEmulator(platform, buildConfig);
        }
        return this.deployOnDevice(platform, buildConfig);
    };
    PlatformService.prototype.installOnDevice = function (platform, buildConfig) {
        var _this = this;
        return (function () {
            platform = platform.toLowerCase();
            _this.ensurePlatformInstalled(platform).wait();
            var platformData = _this.$platformsData.getPlatformData(platform);
            _this.$devicesService.initialize({ platform: platform, deviceId: _this.$options.device }).wait();
            var packageFileDict = {};
            var action = function (device) {
                return (function () {
                    var packageFileKey = _this.getPackageFileKey(device);
                    var packageFile = packageFileDict[packageFileKey];
                    if (!packageFile) {
                        if (_this.$devicesService.isiOSSimulator(device)) {
                            _this.prepareAndBuild(platform, buildConfig).wait();
                            packageFile = _this.getLatestApplicationPackageForEmulator(platformData).wait().packageName;
                        }
                        else {
                            var deviceBuildConfig = buildConfig || {};
                            deviceBuildConfig.buildForDevice = true;
                            _this.prepareAndBuild(platform, deviceBuildConfig).wait();
                            packageFile = _this.getLatestApplicationPackageForDevice(platformData).wait().packageName;
                        }
                    }
                    platformData.platformProjectService.deploy(device.deviceInfo.identifier).wait();
                    device.applicationManager.reinstallApplication(_this.$projectData.projectId, packageFile).wait();
                    _this.$logger.info("Successfully deployed on device with identifier '" + device.deviceInfo.identifier + "'.");
                    packageFileDict[packageFileKey] = packageFile;
                }).future()();
            };
            _this.$devicesService.execute(action, _this.getCanExecuteAction(platform)).wait();
        }).future()();
    };
    PlatformService.prototype.getPackageFileKey = function (device) {
        if (this.$mobileHelper.isAndroidPlatform(device.deviceInfo.platform)) {
            return device.deviceInfo.platform.toLowerCase();
        }
        return device.deviceInfo.platform.toLowerCase() + device.deviceInfo.type;
    };
    PlatformService.prototype.deployOnDevice = function (platform, buildConfig) {
        var _this = this;
        return (function () {
            _this.installOnDevice(platform, buildConfig).wait();
            _this.startOnDevice(platform).wait();
        }).future()();
    };
    PlatformService.prototype.startOnDevice = function (platform) {
        var _this = this;
        return (function () {
            var action = function (device) { return device.applicationManager.startApplication(_this.$projectData.projectId); };
            _this.$devicesService.execute(action, _this.getCanExecuteAction(platform)).wait();
        }).future()();
    };
    PlatformService.prototype.getCanExecuteAction = function (platform) {
        var _this = this;
        var canExecute = function (currentDevice) {
            if (_this.$options.device && currentDevice && currentDevice.deviceInfo) {
                var device = _this.$devicesService.getDeviceByDeviceOption();
                if (device && device.deviceInfo) {
                    return currentDevice.deviceInfo.identifier === device.deviceInfo.identifier;
                }
            }
            if (_this.$mobileHelper.isiOSPlatform(platform) && _this.$hostInfo.isDarwin) {
                if (_this.$devicesService.isOnlyiOSSimultorRunning() || _this.$options.emulator || _this.$devicesService.isiOSSimulator(currentDevice)) {
                    return true;
                }
                return _this.$devicesService.isiOSDevice(currentDevice);
            }
            return true;
        };
        return canExecute;
    };
    PlatformService.prototype.deployOnEmulator = function (platform, buildConfig) {
        var _this = this;
        platform = platform.toLowerCase();
        if (this.$options.avd) {
            this.$logger.warn("Option --avd is no longer supported. Please use --device instead!");
        }
        if (this.$options.availableDevices || this.$options.device || this.$options.avd) {
            return (function () {
                var devices;
                if (_this.$mobileHelper.isiOSPlatform(platform)) {
                    devices = _this.$childProcess.exec("instruments -s devices").wait();
                }
                else if (_this.$mobileHelper.isAndroidPlatform(platform)) {
                    var androidPath = path.join(process.env.ANDROID_HOME, "tools", "android");
                    devices = _this.$childProcess.exec(androidPath + " list avd").wait();
                }
                if (_this.$options.availableDevices) {
                    _this.$logger.info(devices);
                }
                if (_this.$options.device || _this.$options.avd) {
                    if (_this.$options.device) {
                        _this.$options.avd = _this.$options.device;
                    }
                    if (devices.indexOf(_this.$options.device) !== -1 || devices.indexOf(_this.$options.avd) !== -1) {
                        _this.ensurePlatformInstalled(platform).wait();
                        var packageFile = void 0, logFilePath = void 0;
                        var platformData = _this.$platformsData.getPlatformData(platform);
                        var emulatorServices = platformData.emulatorServices;
                        emulatorServices.checkAvailability().wait();
                        emulatorServices.checkDependencies().wait();
                        _this.prepareAndBuild(platform, buildConfig).wait();
                        packageFile = _this.getLatestApplicationPackageForEmulator(platformData).wait().packageName;
                        _this.$logger.out("Using ", packageFile);
                        logFilePath = path.join(platformData.projectRoot, _this.$projectData.projectName, "emulator.log");
                        emulatorServices.runApplicationOnEmulator(packageFile, { stderrFilePath: logFilePath, stdoutFilePath: logFilePath, appId: _this.$projectData.projectId }).wait();
                    }
                    else {
                        _this.$errors.fail("Cannot find device with name: " + (_this.$options.device || _this.$options.avd) + ".");
                    }
                }
            }).future()();
        }
        else {
            this.$options.emulator = true;
            return this.deployOnDevice(platform, buildConfig);
        }
    };
    PlatformService.prototype.validatePlatform = function (platform) {
        if (!platform) {
            this.$errors.fail("No platform specified.");
        }
        platform = platform.split("@")[0].toLowerCase();
        if (!this.isValidPlatform(platform)) {
            this.$errors.fail("Invalid platform %s. Valid platforms are %s.", platform, helpers.formatListOfNames(this.$platformsData.platformsNames));
        }
        if (!this.isPlatformSupportedForOS(platform)) {
            this.$errors.fail("Applications for platform %s can not be built on this OS - %s", platform, process.platform);
        }
    };
    PlatformService.prototype.validatePlatformInstalled = function (platform) {
        this.validatePlatform(platform);
        if (!this.isPlatformInstalled(platform).wait()) {
            this.$errors.fail("The platform %s is not added to this project. Please use 'tns platform add <platform>'", platform);
        }
    };
    PlatformService.prototype.ensurePlatformInstalled = function (platform) {
        var _this = this;
        return (function () {
            if (!_this.isPlatformInstalled(platform).wait()) {
                _this.addPlatform(platform).wait();
            }
        }).future()();
    };
    PlatformService.prototype.isPlatformInstalled = function (platform) {
        return this.$fs.exists(path.join(this.$projectData.platformsDir, platform.toLowerCase()));
    };
    PlatformService.prototype.isValidPlatform = function (platform) {
        return this.$platformsData.getPlatformData(platform);
    };
    PlatformService.prototype.isPlatformSupportedForOS = function (platform) {
        var targetedOS = this.$platformsData.getPlatformData(platform).targetedOS;
        var res = !targetedOS || targetedOS.indexOf("*") >= 0 || targetedOS.indexOf(process.platform) >= 0;
        return res;
    };
    PlatformService.prototype.isPlatformPrepared = function (platform) {
        var platformData = this.$platformsData.getPlatformData(platform);
        return platformData.platformProjectService.isPlatformPrepared(platformData.projectRoot);
    };
    PlatformService.prototype.getApplicationPackages = function (buildOutputPath, validPackageNames) {
        var _this = this;
        return (function () {
            var candidates = _this.$fs.readDirectory(buildOutputPath).wait();
            var packages = _.filter(candidates, function (candidate) {
                return _.includes(validPackageNames, candidate);
            }).map(function (currentPackage) {
                currentPackage = path.join(buildOutputPath, currentPackage);
                return {
                    packageName: currentPackage,
                    time: _this.$fs.getFsStats(currentPackage).wait().mtime
                };
            });
            return packages;
        }).future()();
    };
    PlatformService.prototype.getLatestApplicationPackage = function (buildOutputPath, validPackageNames) {
        var _this = this;
        return (function () {
            var packages = _this.getApplicationPackages(buildOutputPath, validPackageNames).wait();
            if (packages.length === 0) {
                var packageExtName = path.extname(validPackageNames[0]);
                _this.$errors.fail("No %s found in %s directory", packageExtName, buildOutputPath);
            }
            packages = _.sortBy(packages, function (pkg) { return pkg.time; }).reverse();
            return packages[0];
        }).future()();
    };
    PlatformService.prototype.getLatestApplicationPackageForDevice = function (platformData) {
        return this.getLatestApplicationPackage(platformData.deviceBuildOutputPath, platformData.validPackageNamesForDevice);
    };
    PlatformService.prototype.getLatestApplicationPackageForEmulator = function (platformData) {
        return this.getLatestApplicationPackage(platformData.emulatorBuildOutputPath || platformData.deviceBuildOutputPath, platformData.validPackageNamesForEmulator || platformData.validPackageNamesForDevice);
    };
    PlatformService.prototype.updatePlatform = function (platform, version) {
        var _this = this;
        return (function () {
            var platformData = _this.$platformsData.getPlatformData(platform);
            _this.$projectDataService.initialize(_this.$projectData.projectDir);
            var data = _this.$projectDataService.getValue(platformData.frameworkPackageName).wait();
            var currentVersion = data && data.version ? data.version : "0.2.0";
            var newVersion = version === constants.PackageVersion.NEXT ?
                _this.$npmInstallationManager.getNextVersion(platformData.frameworkPackageName).wait() :
                version || _this.$npmInstallationManager.getLatestCompatibleVersion(platformData.frameworkPackageName).wait();
            var installedModuleDir = _this.$npmInstallationManager.install(platformData.frameworkPackageName, _this.$projectData.projectDir, { version: newVersion, dependencyType: "save" }).wait();
            var cachedPackageData = _this.$fs.readJson(path.join(installedModuleDir, "package.json")).wait();
            newVersion = (cachedPackageData && cachedPackageData.version) || newVersion;
            var canUpdate = platformData.platformProjectService.canUpdatePlatform(installedModuleDir).wait();
            _this.$npm.uninstall(platformData.frameworkPackageName, { save: true }, _this.$projectData.projectDir).wait();
            if (canUpdate) {
                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)) {
                    _this.updatePlatformCore(platformData, currentVersion, newVersion, canUpdate).wait();
                }
                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 + ".");
                }
            }
            else {
                _this.$errors.failWithoutHelp("Native Platform cannot be updated.");
            }
        }).future()();
    };
    PlatformService.prototype.updatePlatformCore = function (platformData, currentVersion, newVersion, canUpdate) {
        var _this = this;
        return (function () {
            var packageName = platformData.normalizedPlatformName.toLowerCase();
            _this.removePlatforms([packageName]).wait();
            packageName = newVersion ? packageName + "@" + newVersion : packageName;
            _this.addPlatform(packageName).wait();
            _this.$logger.out("Successfully updated to version ", newVersion);
        }).future()();
    };
    PlatformService.prototype.applyBaseConfigOption = function (platformData) {
        var _this = this;
        return (function () {
            if (_this.$options.baseConfig) {
                var newConfigFile = path.resolve(_this.$options.baseConfig);
                _this.$logger.trace("Replacing '" + platformData.configurationFilePath + "' with '" + newConfigFile + "'.");
                _this.$fs.copyFile(newConfigFile, platformData.configurationFilePath).wait();
            }
        }).future()();
    };
    __decorate([
        helpers.hook('prepare')
    ], PlatformService.prototype, "preparePlatformCore", null);
    return PlatformService;
}());
exports.PlatformService = PlatformService;
$injector.register("platformService", PlatformService);
