"use strict";
const path = require("path");
class NodePackageManager {
    constructor($fs, $hostInfo, $errors, $childProcess, $logger, $options) {
        this.$fs = $fs;
        this.$hostInfo = $hostInfo;
        this.$errors = $errors;
        this.$childProcess = $childProcess;
        this.$logger = $logger;
        this.$options = $options;
    }
    install(packageName, pathToSave, config) {
        return (() => {
            if (this.$options.disableNpmInstall) {
                return;
            }
            if (this.$options.ignoreScripts) {
                config = config || {};
                config["ignore-scripts"] = true;
            }
            let jsonContentBefore = this.$fs.readJson(path.join(pathToSave, "package.json"));
            let dependenciesBefore = _.keys(jsonContentBefore.dependencies).concat(_.keys(jsonContentBefore.devDependencies));
            let flags = this.getFlagsString(config, true);
            let params = ["install"];
            if (packageName !== pathToSave) {
                params.push(packageName);
            }
            params = params.concat(flags);
            let pwd = pathToSave;
            if (this.$options.path) {
                let relativePathFromCwdToSource = "";
                if (this.$options.frameworkPath) {
                    relativePathFromCwdToSource = path.relative(this.$options.frameworkPath, pathToSave);
                    if (this.$fs.exists(relativePathFromCwdToSource)) {
                        packageName = relativePathFromCwdToSource;
                    }
                }
            }
            try {
                let spawnResult = this.$childProcess.spawnFromEvent(this.getNpmExecutableName(), params, "close", { cwd: pwd }).wait();
                this.$logger.out(spawnResult.stdout);
            }
            catch (err) {
                if (err.message && err.message.indexOf("EPEERINVALID") !== -1) {
                    this.$logger.warn(err.message);
                }
                else {
                    throw err;
                }
            }
            let jsonContentAfter = this.$fs.readJson(path.join(pathToSave, "package.json"));
            let dependenciesAfter = _.keys(jsonContentAfter.dependencies).concat(_.keys(jsonContentAfter.devDependencies));
            let dependencyDiff = _(jsonContentAfter.dependencies)
                .omitBy((val, key) => jsonContentBefore && jsonContentBefore.dependencies && jsonContentBefore.dependencies[key] && jsonContentBefore.dependencies[key] === val)
                .keys()
                .value();
            let devDependencyDiff = _(jsonContentAfter.devDependencies)
                .omitBy((val, key) => jsonContentBefore && jsonContentBefore.devDependencies && jsonContentBefore.devDependencies[key] && jsonContentBefore.devDependencies[key] === val)
                .keys()
                .value();
            let diff = dependencyDiff.concat(devDependencyDiff);
            if (diff.length <= 0 && dependenciesBefore.length === dependenciesAfter.length && packageName !== pathToSave) {
                this.$errors.failWithoutHelp(`The plugin ${packageName} is already installed`);
            }
            if (diff.length <= 0 && dependenciesBefore.length !== dependenciesAfter.length) {
                this.$errors.failWithoutHelp(`Couldn't install package correctly`);
            }
            return diff;
        }).future()();
    }
    uninstall(packageName, config, path) {
        let flags = this.getFlagsString(config, false);
        return this.$childProcess.exec(`npm uninstall ${packageName} ${flags}`, { cwd: path });
    }
    search(filter, config) {
        let args = ([filter] || []).concat(config.silent);
        return this.$childProcess.exec(`npm search ${args.join(" ")}`);
    }
    view(packageName, config) {
        return (() => {
            let flags = this.getFlagsString(config, false);
            let viewResult;
            try {
                viewResult = this.$childProcess.exec(`npm view ${packageName} ${flags}`).wait();
            }
            catch (e) {
                this.$errors.failWithoutHelp(e);
            }
            return JSON.parse(viewResult);
        }).future()();
    }
    getNpmExecutableName() {
        let npmExecutableName = "npm";
        if (this.$hostInfo.isWindows) {
            npmExecutableName += ".cmd";
        }
        return npmExecutableName;
    }
    getFlagsString(config, asArray) {
        let array = [];
        for (let flag in config) {
            if (config[flag]) {
                if (flag === "dist-tags" || flag === "versions") {
                    array.push(` ${flag}`);
                    continue;
                }
                array.push(`--${flag}`);
            }
        }
        if (asArray) {
            return array;
        }
        return array.join(" ");
    }
}
exports.NodePackageManager = NodePackageManager;
$injector.register("npm", NodePackageManager);
