"use strict";
var fs = require("fs");
var path = require("path");
var semver = require("semver");
var shelljs = require("shelljs");
var constants = require("../../constants");
var minimatch = require("minimatch");
var Future = require("fibers/future");
var NpmDependencyResolver = (function () {
    function NpmDependencyResolver(projectDir) {
        this.projectDir = projectDir;
    }
    NpmDependencyResolver.prototype.getDevDependencies = function (projectDir) {
        var projectFilePath = path.join(projectDir, constants.PACKAGE_JSON_FILE_NAME);
        var projectFileContent = require(projectFilePath);
        return projectFileContent.devDependencies || {};
    };
    NpmDependencyResolver.prototype.resolveDependencies = function (changedDirectories, platform) {
        var _this = this;
        var devDependencies = this.getDevDependencies(this.projectDir);
        var dependencies = Object.create(null);
        _.each(changedDirectories, function (changedDirectoryAbsolutePath) {
            if (!devDependencies[path.basename(changedDirectoryAbsolutePath)]) {
                var pathToPackageJson = path.join(changedDirectoryAbsolutePath, constants.PACKAGE_JSON_FILE_NAME);
                var packageJsonFiles = fs.existsSync(pathToPackageJson) ? [pathToPackageJson] : [];
                var nodeModulesFolderPath = path.join(changedDirectoryAbsolutePath, constants.NODE_MODULES_FOLDER_NAME);
                packageJsonFiles = packageJsonFiles.concat(_this.enumeratePackageJsonFilesSync(nodeModulesFolderPath));
                _.each(packageJsonFiles, function (packageJsonFilePath) {
                    var fileContent = require(packageJsonFilePath);
                    if (!devDependencies[fileContent.name] && fileContent.name && fileContent.version) {
                        var currentDependency = {
                            name: fileContent.name,
                            version: fileContent.version,
                            directory: path.dirname(packageJsonFilePath),
                            nativescript: fileContent.nativescript
                        };
                        var addedDependency = dependencies[currentDependency.name];
                        if (addedDependency) {
                            if (semver.gt(currentDependency.version, addedDependency.version)) {
                                var currentDependencyMajorVersion = semver.major(currentDependency.version);
                                var addedDependencyMajorVersion = semver.major(addedDependency.version);
                                var message = "The dependency located at " + addedDependency.directory + " with version " + addedDependency.version + " will be replaced with dependency located at " + currentDependency.directory + " with version " + currentDependency.version;
                                var logger = $injector.resolve("$logger");
                                currentDependencyMajorVersion === addedDependencyMajorVersion ? logger.out(message) : logger.warn(message);
                                dependencies[currentDependency.name] = currentDependency;
                            }
                        }
                        else {
                            dependencies[currentDependency.name] = currentDependency;
                        }
                    }
                });
            }
        });
        return dependencies;
    };
    NpmDependencyResolver.prototype.enumeratePackageJsonFilesSync = function (nodeModulesDirectoryPath, foundFiles) {
        foundFiles = foundFiles || [];
        if (fs.existsSync(nodeModulesDirectoryPath)) {
            var contents = fs.readdirSync(nodeModulesDirectoryPath);
            for (var i = 0; i < contents.length; ++i) {
                var moduleName = contents[i];
                var moduleDirectoryInNodeModules = path.join(nodeModulesDirectoryPath, moduleName);
                var packageJsonFilePath = path.join(moduleDirectoryInNodeModules, constants.PACKAGE_JSON_FILE_NAME);
                if (fs.existsSync(packageJsonFilePath)) {
                    foundFiles.push(packageJsonFilePath);
                }
                var directoryPath = path.join(moduleDirectoryInNodeModules, constants.NODE_MODULES_FOLDER_NAME);
                if (fs.existsSync(directoryPath)) {
                    this.enumeratePackageJsonFilesSync(directoryPath, foundFiles);
                }
                else if (fs.statSync(moduleDirectoryInNodeModules).isDirectory()) {
                    this.enumeratePackageJsonFilesSync(moduleDirectoryInNodeModules, foundFiles);
                }
            }
        }
        return foundFiles;
    };
    return NpmDependencyResolver;
}());
exports.NpmDependencyResolver = NpmDependencyResolver;
var TnsModulesCopy = (function () {
    function TnsModulesCopy(outputRoot, $fs) {
        this.outputRoot = outputRoot;
        this.$fs = $fs;
    }
    TnsModulesCopy.prototype.copyModules = function (dependencies, platform) {
        var _this = this;
        _.each(dependencies, function (dependency) {
            _this.copyDependencyDir(dependency);
            if (dependency.name === constants.TNS_CORE_MODULES_NAME) {
                var tnsCoreModulesResourcePath = path.join(_this.outputRoot, constants.TNS_CORE_MODULES_NAME);
                var allFiles = _this.$fs.enumerateFilesInDirectorySync(tnsCoreModulesResourcePath);
                var deleteFilesFutures = allFiles.filter(function (file) { return minimatch(file, "**/*.ts", { nocase: true }); }).map(function (file) { return _this.$fs.deleteFile(file); });
                Future.wait(deleteFilesFutures);
                shelljs.cp("-Rf", path.join(tnsCoreModulesResourcePath, "*"), _this.outputRoot);
                _this.$fs.deleteDirectory(tnsCoreModulesResourcePath).wait();
            }
        });
    };
    TnsModulesCopy.prototype.copyDependencyDir = function (dependency) {
        var dependencyDir = path.dirname(dependency.name || "");
        var insideNpmScope = /^@/.test(dependencyDir);
        var targetDir = this.outputRoot;
        if (insideNpmScope) {
            targetDir = path.join(this.outputRoot, dependencyDir);
        }
        shelljs.mkdir("-p", targetDir);
        shelljs.cp("-Rf", dependency.directory, targetDir);
        shelljs.rm("-rf", path.join(targetDir, dependency.name, "node_modules"));
    };
    return TnsModulesCopy;
}());
exports.TnsModulesCopy = TnsModulesCopy;
var NpmPluginPrepare = (function () {
    function NpmPluginPrepare($fs, $pluginsService, $platformsData) {
        this.$fs = $fs;
        this.$pluginsService = $pluginsService;
        this.$platformsData = $platformsData;
    }
    NpmPluginPrepare.prototype.preparePlugins = function (dependencies, platform) {
        var _this = this;
        if (_.isEmpty(dependencies)) {
            return;
        }
        this.$platformsData.getPlatformData(platform).platformProjectService.beforePrepareAllPlugins().wait();
        _.each(dependencies, function (dependency) {
            var isPlugin = !!dependency.nativescript;
            if (isPlugin) {
                console.log("preparing: " + dependency.name);
                _this.$pluginsService.prepare(dependency, platform).wait();
            }
        });
        this.$platformsData.getPlatformData(platform).platformProjectService.afterPrepareAllPlugins().wait();
    };
    return NpmPluginPrepare;
}());
exports.NpmPluginPrepare = NpmPluginPrepare;
