"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ArgumentManager = exports.PROMPT_ME_DESIGNATOR = void 0;
const tslib_1 = require("tslib");
const _ = require("lodash");
const command_base_1 = require("./command-base"); // Circular ref... lovely.
/** The value provided as input that indicates
 * a user's desire to be prompted with a list from which choose the value(s),
 * instead of entering them manually or taking a default. */
exports.PROMPT_ME_DESIGNATOR = "?";
/** Persists and retrieves memorized command arguments. */
class ArgumentManager {
    constructor(commandName, projCfg, projCfgRepo, logger, _ui) {
        this.commandName = commandName;
        this.projCfg = projCfg;
        this.projCfgRepo = projCfgRepo;
        this.logger = logger;
        this._ui = _ui;
    }
    runWithDefaults(input, handler) {
        return new Promise((resolve, reject) => tslib_1.__awaiter(this, void 0, void 0, function* () {
            try {
                if (input.flags.unremember) {
                    yield this.unmemorizeCommand(this.commandName, input.flags.unremember);
                }
                else {
                    if (!input.flags.withoutdefaults) {
                        yield this.setDefaults(input.args, input.flags);
                    }
                    yield handler(input.args, input.flags);
                }
                if (input.flags.remember || input.flags.rememberAs) {
                    // this.memorizeCommand_old(this.commandName, this.argv, flags.rememberAs);
                    yield this.memorizeCommand(this.commandName, input.args, input.flags, input.flags.rememberAs);
                }
                resolve();
            }
            catch (err) {
                reject(err);
            }
        }));
    }
    /** Mutates the args and flags with default values. */
    setDefaults(args, flags) {
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            return new Promise((resolve, reject) => tslib_1.__awaiter(this, void 0, void 0, function* () {
                var _a, _b, _c, _d;
                try {
                    // did they invoke a memorized call?
                    if (flags.as) {
                        if (((_a = this.projCfg) === null || _a === void 0 ? void 0 : _a.namedCalls) && ((_b = this.projCfg) === null || _b === void 0 ? void 0 : _b.namedCalls[this.commandName])) {
                            let namedCall;
                            if (flags.as === exports.PROMPT_ME_DESIGNATOR) {
                                let calls = _.keys(this.projCfg.namedCalls[this.commandName]).sort();
                                namedCall = (yield this._ui.promptSelect("namedCall", "Select a build command:", calls));
                                flags.as = namedCall;
                            }
                            else {
                                namedCall = flags.as;
                            }
                            let defaults = this.projCfg.namedCalls[this.commandName][namedCall];
                            if (defaults) {
                                if (defaults.args)
                                    _.defaults(args, defaults.args);
                                if (defaults.flags)
                                    _.defaults(flags, defaults.flags);
                                this.logger.debug(`Argument defaults were provided from memorized call in project config: [${namedCall}].`);
                                this.logger.debug(JSON.stringify(defaults));
                            }
                            else
                                throw new Error(`Could not find named call: [${namedCall}]`);
                        }
                        else
                            throw new Error(`There are no named calls memorized.`);
                    }
                    // DO we have defaults?
                    if (((_c = this.projCfg) === null || _c === void 0 ? void 0 : _c.namedCalls) && ((_d = this.projCfg) === null || _d === void 0 ? void 0 : _d.namedCalls[this.commandName])) {
                        let defaults = this.projCfg.namedCalls[this.commandName].default;
                        if (defaults) {
                            if (defaults.args)
                                _.defaults(args, defaults.args);
                            if (defaults.flags)
                                _.defaults(flags, defaults.flags);
                            this.logger.debug(`Argument defaults provided from project config.`);
                            this.logger.debug(JSON.stringify(defaults));
                        }
                    }
                    this.logger.debug(`Ultimate argument values: ${JSON.stringify(Object.assign(Object.assign({}, args), flags))}`);
                    resolve();
                }
                catch (err) {
                    reject(err);
                }
            }));
        });
    }
    memorizeCommand(commandName, args, flags, givenName = "default") {
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            return new Promise((resolve, reject) => tslib_1.__awaiter(this, void 0, void 0, function* () {
                try {
                    // We dont want to remember these flags...
                    let omitList = [
                        command_base_1.commandBase.globalFlags.as.name,
                        command_base_1.commandBase.globalFlags.remember.name,
                        command_base_1.commandBase.globalFlags.rememberAs.name,
                        command_base_1.commandBase.globalFlags.unremember.name,
                        command_base_1.commandBase.globalFlags.withoutdefaults.name
                    ];
                    this.logger.debug(`Memorizing [${commandName}] argument list as: ${givenName}...`);
                    let calls = {};
                    if (this.projCfg && this.projCfgRepo) {
                        if (!this.projCfg.namedCalls)
                            this.projCfg.namedCalls = {};
                        calls = this.projCfg.namedCalls[commandName] || {};
                    }
                    // for (let arg in args) {
                    //   if (omitList.indexOf(arg) > 0)
                    // }
                    let trimmed = Object.assign({}, flags);
                    for (let unmemorable in omitList) {
                        _.unset(trimmed, omitList[unmemorable]);
                    }
                    // let call = "";
                    // // Add args
                    // for (let name in args) {
                    //   if (call != "") call = call.concat(" ");
                    //   let val: string = args[name];
                    //   val = (val.match && val.match(/\s/)) ? this.inQuotes(val) : val;
                    //   call = call.concat(val);  // for args, we dont want the arg name, just the value
                    // }
                    // // Add flags
                    // for (let flagName in trimmed) {
                    //   if (call != "") call = call.concat(" ");
                    //   call = call.concat("--", flagName);
                    //   if (trimmed[flagName]) {
                    //     let flagVal: string = trimmed[flagName];
                    //     flagVal = (flagVal.match && flagVal.match(/\s/)) ? this.inQuotes(flagVal) : flagVal;
                    //     call = call.concat(" ", flagVal);
                    //   }
                    // }
                    calls[givenName] = { args: args, flags: trimmed };
                    // Write to project config
                    if (this.projCfg && this.projCfgRepo) {
                        if (!this.projCfg.namedCalls)
                            this.projCfg.namedCalls = {};
                        this.projCfg.namedCalls[commandName] = calls;
                        yield this.projCfgRepo.updateProjectConfigFile(this.projCfg);
                        this.logger.notice("Successfully remembered for the project.");
                    }
                    resolve();
                }
                catch (err) {
                    reject(err);
                }
            }));
        });
    }
    inQuotes(original) {
        let escaped = original.replace("\"", "\\\"");
        return `"${original}"`;
    }
    isEmpty(obj) {
        // this.logger.trace(`obj has ${Object.keys(obj).length} keys.`);
        return Object.keys(obj).length == 0;
    }
    unmemorizeCommand(commandName, givenName = "default") {
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            return new Promise((resolve, reject) => tslib_1.__awaiter(this, void 0, void 0, function* () {
                var _a;
                try {
                    this.logger.debug(`Removing memorized [${commandName}] argument list: ${givenName}...`);
                    if (this.projCfgRepo && ((_a = this.projCfg) === null || _a === void 0 ? void 0 : _a.namedCalls)
                        && this.projCfg.namedCalls[commandName]
                        && this.projCfg.namedCalls[commandName][givenName]) {
                        _.unset(this.projCfg.namedCalls[commandName], givenName);
                        if (this.isEmpty(this.projCfg.namedCalls[commandName])) {
                            _.unset(this.projCfg.namedCalls, commandName);
                            if (this.isEmpty(this.projCfg.namedCalls)) {
                                _.unset(this.projCfg, "namedCalls");
                            }
                        }
                        yield this.projCfgRepo.updateProjectConfigFile(this.projCfg);
                        this.logger.notice("Successfully removed.");
                    }
                    resolve();
                }
                catch (err) {
                    reject(err);
                }
            }));
        });
    }
}
exports.ArgumentManager = ArgumentManager;
//# sourceMappingURL=argument-manager.js.map