"use strict";
var constants = require("../constants");
var osenv = require("osenv");
var path = require("path");
var shelljs = require("shelljs");
var ProjectService = (function () {
    function ProjectService($npm, $errors, $fs, $logger, $projectDataService, $projectHelper, $projectNameService, $projectTemplatesService, $options) {
        this.$npm = $npm;
        this.$errors = $errors;
        this.$fs = $fs;
        this.$logger = $logger;
        this.$projectDataService = $projectDataService;
        this.$projectHelper = $projectHelper;
        this.$projectNameService = $projectNameService;
        this.$projectTemplatesService = $projectTemplatesService;
        this.$options = $options;
    }
    ProjectService.prototype.createProject = function (projectName, selectedTemplate) {
        var _this = this;
        return (function () {
            if (!projectName) {
                _this.$errors.fail("You must specify <App name> when creating a new project.");
            }
            projectName = _this.$projectNameService.ensureValidName(projectName, { force: _this.$options.force }).wait();
            var projectId = _this.$options.appid || _this.$projectHelper.generateDefaultAppId(projectName, constants.DEFAULT_APP_IDENTIFIER_PREFIX);
            var projectDir = path.join(path.resolve(_this.$options.path || "."), projectName);
            _this.$fs.createDirectory(projectDir).wait();
            if (_this.$fs.exists(projectDir).wait() && !_this.$fs.isEmptyDir(projectDir).wait()) {
                _this.$errors.fail("Path already exists and is not empty %s", projectDir);
            }
            _this.createPackageJson(projectDir, projectId).wait();
            var customAppPath = _this.getCustomAppPath();
            if (customAppPath) {
                customAppPath = path.resolve(customAppPath);
                if (!_this.$fs.exists(customAppPath).wait()) {
                    _this.$errors.failWithoutHelp("The specified path \"" + customAppPath + "\" doesn't exist. Check that you specified the path correctly and try again.");
                }
                var customAppContents = _this.$fs.enumerateFilesInDirectorySync(customAppPath);
                if (customAppContents.length === 0) {
                    _this.$errors.failWithoutHelp("The specified path \"" + customAppPath + "\" is empty directory.");
                }
            }
            _this.$logger.trace("Creating a new NativeScript project with name %s and id %s at location %s", projectName, projectId, projectDir);
            var projectAppDirectory = path.join(projectDir, constants.APP_FOLDER_NAME);
            var appPath = null;
            if (customAppPath) {
                _this.$logger.trace("Using custom app from %s", customAppPath);
                var relativePathFromSourceToTarget = path.relative(customAppPath, projectAppDirectory);
                if (relativePathFromSourceToTarget !== projectAppDirectory) {
                    var doesRelativePathGoUpAtLeastOneDir = relativePathFromSourceToTarget.split(path.sep)[0] === "..";
                    if (!doesRelativePathGoUpAtLeastOneDir) {
                        _this.$errors.fail("Project dir %s must not be created at/inside the template used to create the project %s.", projectDir, customAppPath);
                    }
                }
                _this.$logger.trace("Copying custom app into %s", projectAppDirectory);
                appPath = customAppPath;
            }
            else {
                var templatePath = _this.$projectTemplatesService.prepareTemplate(selectedTemplate, projectDir).wait();
                _this.$logger.trace("Copying application from '" + templatePath + "' into '" + projectAppDirectory + "'.");
                var templatePackageJson = _this.$fs.readJson(path.join(templatePath, "package.json")).wait();
                selectedTemplate = templatePackageJson.name;
                appPath = templatePath;
            }
            try {
                _this.createProjectCore(projectDir, appPath, projectId).wait();
                _this.mergeProjectAndTemplateProperties(projectDir, appPath).wait();
                _this.$npm.install(projectDir, projectDir, { "ignore-scripts": _this.$options.ignoreScripts }).wait();
                selectedTemplate = selectedTemplate || "";
                var templateName = (constants.RESERVED_TEMPLATE_NAMES[selectedTemplate.toLowerCase()] || selectedTemplate) || constants.RESERVED_TEMPLATE_NAMES["default"];
                _this.$npm.uninstall(selectedTemplate, { save: true }, projectDir).wait();
                _this.$logger.trace("Using NativeScript verified template: " + templateName + " with version undefined.");
            }
            catch (err) {
                _this.$fs.deleteDirectory(projectDir).wait();
                throw err;
            }
            _this.$logger.printMarkdown("Project `%s` was successfully created.", projectName);
        }).future()();
    };
    ProjectService.prototype.mergeProjectAndTemplateProperties = function (projectDir, templatePath) {
        var _this = this;
        return (function () {
            var templatePackageJsonPath = path.join(templatePath, constants.PACKAGE_JSON_FILE_NAME);
            if (_this.$fs.exists(templatePackageJsonPath).wait()) {
                var projectPackageJsonPath = path.join(projectDir, constants.PACKAGE_JSON_FILE_NAME);
                var projectPackageJsonData = _this.$fs.readJson(projectPackageJsonPath).wait();
                _this.$logger.trace("Initial project package.json data: ", projectPackageJsonData);
                var templatePackageJsonData = _this.$fs.readJson(templatePackageJsonPath).wait();
                if (projectPackageJsonData.dependencies || templatePackageJsonData.dependencies) {
                    projectPackageJsonData.dependencies = _this.mergeDependencies(projectPackageJsonData.dependencies, templatePackageJsonData.dependencies);
                }
                if (projectPackageJsonData.devDependencies || templatePackageJsonData.devDependencies) {
                    projectPackageJsonData.devDependencies = _this.mergeDependencies(projectPackageJsonData.devDependencies, templatePackageJsonData.devDependencies);
                }
                _this.$logger.trace("New project package.json data: ", projectPackageJsonData);
                _this.$fs.writeJson(projectPackageJsonPath, projectPackageJsonData).wait();
            }
            else {
                _this.$logger.trace("Template " + templatePath + " does not have " + constants.PACKAGE_JSON_FILE_NAME + " file.");
            }
        }).future()();
    };
    ProjectService.prototype.mergeDependencies = function (projectDependencies, templateDependencies) {
        this.$logger.trace("Merging dependencies, projectDependencies are: ", projectDependencies, " templateDependencies are: ", templateDependencies);
        projectDependencies = projectDependencies || {};
        _.extend(projectDependencies, templateDependencies || {});
        var sortedDeps = {};
        var dependenciesNames = _.keys(projectDependencies).sort();
        _.each(dependenciesNames, function (key) {
            sortedDeps[key] = projectDependencies[key];
        });
        this.$logger.trace("Sorted merged dependencies are: ", sortedDeps);
        return sortedDeps;
    };
    ProjectService.prototype.createProjectCore = function (projectDir, appSourcePath, projectId) {
        var _this = this;
        return (function () {
            _this.$fs.ensureDirectoryExists(projectDir).wait();
            var appDestinationPath = path.join(projectDir, constants.APP_FOLDER_NAME);
            _this.$fs.createDirectory(appDestinationPath).wait();
            shelljs.cp('-R', path.join(appSourcePath, "*"), appDestinationPath);
            shelljs.cp('-R', path.join(appSourcePath, ".*"), appDestinationPath);
            _this.$fs.createDirectory(path.join(projectDir, "platforms")).wait();
            var tnsModulesVersion = _this.$options.tnsModulesVersion;
            var packageName = constants.TNS_CORE_MODULES_NAME;
            if (tnsModulesVersion) {
                packageName = packageName + "@" + tnsModulesVersion;
            }
            _this.$npm.install(packageName, projectDir, { save: true, "save-exact": true }).wait();
        }).future()();
    };
    ProjectService.prototype.createPackageJson = function (projectDir, projectId) {
        var _this = this;
        return (function () {
            _this.$projectDataService.initialize(projectDir);
            _this.$projectDataService.setValue("id", projectId).wait();
        }).future()();
    };
    ProjectService.prototype.getCustomAppPath = function () {
        var customAppPath = this.$options.copyFrom || this.$options.linkTo;
        if (customAppPath) {
            if (customAppPath.indexOf("http://") === 0) {
                this.$errors.fail("Only local paths for custom app are supported.");
            }
            if (customAppPath.substr(0, 1) === '~') {
                customAppPath = path.join(osenv.home(), customAppPath.substr(1));
            }
        }
        return customAppPath;
    };
    return ProjectService;
}());
exports.ProjectService = ProjectService;
$injector.register("projectService", ProjectService);
