"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const helpers = require("./common/helpers");
const yargs = require("yargs");
class Options {
    constructor($errors, $staticConfig, $settingsService) {
        this.$errors = $errors;
        this.$staticConfig = $staticConfig;
        this.$settingsService = $settingsService;
        this.optionsWhiteList = ["ui", "recursive", "reporter", "require", "timeout", "_", "$0"];
        this.globalOptions = {
            log: { type: "string", hasSensitiveValue: false },
            verbose: { type: "boolean", alias: "v", hasSensitiveValue: false },
            version: { type: "boolean", hasSensitiveValue: false },
            help: { type: "boolean", alias: "h", hasSensitiveValue: false },
            profileDir: { type: "string", hasSensitiveValue: true },
            analyticsClient: { type: "string", hasSensitiveValue: false },
            path: { type: "string", alias: "p", hasSensitiveValue: true },
            _: { type: "string", hasSensitiveValue: false }
        };
        this.options = _.extend({}, this.commonOptions, this.globalOptions);
        this.setArgv();
    }
    setupOptions(commandSpecificDashedOptions) {
        if (commandSpecificDashedOptions) {
            _.extend(this.options, commandSpecificDashedOptions);
            this.setArgv();
        }
        this.argv.bundle = "webpack";
        if (this.initialArgv.release && this.initialArgv.hmr) {
            this.$errors.failWithoutHelp("The options --release and --hmr cannot be used simultaneously.");
        }
        if (this.argv.hmr) {
            this.argv.hmr = !this.argv.release;
        }
        if (this.argv.debugBrk) {
            this.argv.hmr = false;
        }
    }
    get shorthands() {
        const result = [];
        _.each(_.keys(this.options), optionName => {
            if (this.options[optionName].alias) {
                result.push(this.options[optionName].alias);
            }
        });
        return result;
    }
    get commonOptions() {
        return {
            ipa: { type: "string", hasSensitiveValue: true },
            frameworkPath: { type: "string", hasSensitiveValue: true },
            frameworkName: { type: "string", hasSensitiveValue: false },
            framework: { type: "string", hasSensitiveValue: false },
            frameworkVersion: { type: "string", hasSensitiveValue: false },
            forDevice: { type: "boolean", hasSensitiveValue: false },
            iCloudContainerEnvironment: { type: "string", hasSensitiveValue: false },
            provision: { type: "object", hasSensitiveValue: true },
            client: { type: "boolean", default: true, hasSensitiveValue: false },
            env: { type: "object", hasSensitiveValue: false },
            production: { type: "boolean", hasSensitiveValue: false },
            debugTransport: { type: "boolean", hasSensitiveValue: false },
            keyStorePath: { type: "string", hasSensitiveValue: true },
            keyStorePassword: { type: "string", hasSensitiveValue: true },
            keyStoreAlias: { type: "string", hasSensitiveValue: true },
            keyStoreAliasPassword: { type: "string", hasSensitiveValue: true },
            ignoreScripts: { type: "boolean", hasSensitiveValue: false },
            disableNpmInstall: { type: "boolean", hasSensitiveValue: false },
            compileSdk: { type: "number", hasSensitiveValue: false },
            port: { type: "number", hasSensitiveValue: false },
            copyTo: { type: "string", hasSensitiveValue: true },
            js: { type: "boolean", hasSensitiveValue: false },
            javascript: { type: "boolean", hasSensitiveValue: false },
            ng: { type: "boolean", hasSensitiveValue: false },
            angular: { type: "boolean", hasSensitiveValue: false },
            vue: { type: "boolean", hasSensitiveValue: false },
            vuejs: { type: "boolean", hasSensitiveValue: false },
            tsc: { type: "boolean", hasSensitiveValue: false },
            ts: { type: "boolean", hasSensitiveValue: false },
            typescript: { type: "boolean", hasSensitiveValue: false },
            yarn: { type: "boolean", hasSensitiveValue: false },
            androidTypings: { type: "boolean", hasSensitiveValue: false },
            bundle: { type: "string", hasSensitiveValue: false },
            all: { type: "boolean", hasSensitiveValue: false },
            teamId: { type: "object", hasSensitiveValue: true },
            chrome: { type: "boolean", hasSensitiveValue: false },
            inspector: { type: "boolean", hasSensitiveValue: false },
            clean: { type: "boolean", hasSensitiveValue: false },
            watch: { type: "boolean", default: true, hasSensitiveValue: false },
            background: { type: "string", hasSensitiveValue: false },
            username: { type: "string", hasSensitiveValue: true },
            pluginName: { type: "string", hasSensitiveValue: false },
            includeTypeScriptDemo: { type: "string", hasSensitiveValue: false },
            includeAngularDemo: { type: "string", hasSensitiveValue: false },
            hmr: { type: "boolean", hasSensitiveValue: false, default: true },
            collection: { type: "string", alias: "c", hasSensitiveValue: false },
            json: { type: "boolean", hasSensitiveValue: false },
            avd: { type: "string", hasSensitiveValue: true },
            config: { type: "array", hasSensitiveValue: false },
            insecure: { type: "boolean", alias: "k", hasSensitiveValue: false },
            debug: { type: "boolean", alias: "d", hasSensitiveValue: false },
            timeout: { type: "string", hasSensitiveValue: false },
            device: { type: "string", hasSensitiveValue: true },
            availableDevices: { type: "boolean", hasSensitiveValue: false },
            appid: { type: "string", hasSensitiveValue: true },
            geny: { type: "string", hasSensitiveValue: true },
            debugBrk: { type: "boolean", hasSensitiveValue: false },
            debugPort: { type: "number", hasSensitiveValue: false },
            start: { type: "boolean", hasSensitiveValue: false },
            stop: { type: "boolean", hasSensitiveValue: false },
            ddi: { type: "string", hasSensitiveValue: true },
            justlaunch: { type: "boolean", hasSensitiveValue: false },
            file: { type: "string", hasSensitiveValue: true },
            force: { type: "boolean", alias: "f", hasSensitiveValue: false },
            emulator: { type: "boolean", hasSensitiveValue: false },
            sdk: { type: "string", hasSensitiveValue: false },
            template: { type: "string", hasSensitiveValue: true },
            certificate: { type: "string", hasSensitiveValue: true },
            certificatePassword: { type: "string", hasSensitiveValue: true },
            release: { type: "boolean", alias: "r", hasSensitiveValue: false },
            var: { type: "object", hasSensitiveValue: true },
            default: { type: "boolean", hasSensitiveValue: false },
            count: { type: "number", hasSensitiveValue: false },
            analyticsLogFile: { type: "string", hasSensitiveValue: true },
            cleanupLogFile: { type: "string", hasSensitiveValue: true },
            hooks: { type: "boolean", default: true, hasSensitiveValue: false },
            link: { type: "boolean", default: false, hasSensitiveValue: false },
            aab: { type: "boolean", hasSensitiveValue: false },
            performance: { type: "object", hasSensitiveValue: true }
        };
    }
    get optionNames() {
        return _.keys(this.options);
    }
    getOptionValue(optionName) {
        optionName = this.getCorrectOptionName(optionName);
        return this.argv[optionName];
    }
    validateOptions(commandSpecificDashedOptions) {
        this.setupOptions(commandSpecificDashedOptions);
        const parsed = Object.create(null);
        _.each(_.keys(this.argv), optionName => {
            parsed[optionName] = this.getOptionValue(optionName);
        });
        _.each(parsed, (value, originalOptionName) => {
            if (value === undefined) {
                return;
            }
            const optionName = this.getCorrectOptionName(originalOptionName);
            if (!_.includes(this.optionsWhiteList, optionName)) {
                if (!this.isOptionSupported(optionName)) {
                    this.$errors.failWithoutHelp(`The option '${originalOptionName}' is not supported. To see command's options, use '$ ${this.$staticConfig.CLIENT_NAME.toLowerCase()} help ${process.argv[2]}'. To see all commands use '$ ${this.$staticConfig.CLIENT_NAME.toLowerCase()} help'.`);
                }
                const optionType = this.getOptionType(optionName), optionValue = parsed[optionName];
                if (_.isArray(optionValue) && optionType !== "array") {
                    this.$errors.fail("You have set the %s option multiple times. Check the correct command syntax below and try again.", originalOptionName);
                }
                else if (optionType === "string" && helpers.isNullOrWhitespace(optionValue)) {
                    this.$errors.failWithoutHelp("The option '%s' requires non-empty value.", originalOptionName);
                }
                else if (optionType === "array" && optionValue.length === 0) {
                    this.$errors.failWithoutHelp(`The option '${originalOptionName}' requires one or more values, separated by a space.`);
                }
            }
        });
    }
    getCorrectOptionName(optionName) {
        const secondaryOptionName = this.getNonDashedOptionName(optionName);
        return _.includes(this.optionNames, secondaryOptionName) ? secondaryOptionName : optionName;
    }
    getOptionType(optionName) {
        const option = this.options[optionName] || this.tryGetOptionByAliasName(optionName);
        return option ? option.type : "";
    }
    tryGetOptionByAliasName(aliasName) {
        const option = _.find(this.options, opt => opt.alias === aliasName);
        return option;
    }
    isOptionSupported(option) {
        if (!this.options[option]) {
            const opt = this.tryGetOptionByAliasName(option);
            return !!opt;
        }
        return true;
    }
    getNonDashedOptionName(optionName) {
        const matchUpperCaseLetters = optionName.match(Options.NONDASHED_OPTION_REGEX);
        if (matchUpperCaseLetters) {
            const secondaryOptionName = matchUpperCaseLetters[1] + matchUpperCaseLetters[2].toUpperCase() + matchUpperCaseLetters[3] || '';
            return this.getNonDashedOptionName(secondaryOptionName);
        }
        return optionName;
    }
    getDashedOptionName(optionName) {
        const matchUpperCaseLetters = optionName.match(Options.DASHED_OPTION_REGEX);
        if (matchUpperCaseLetters) {
            const secondaryOptionName = `${matchUpperCaseLetters[1]}-${matchUpperCaseLetters[2].toLowerCase()}${matchUpperCaseLetters[3] || ''}`;
            return this.getDashedOptionName(secondaryOptionName);
        }
        return optionName;
    }
    setArgv() {
        const opts = {};
        _.each(this.options, (value, key) => {
            opts[this.getDashedOptionName(key)] = value;
        });
        const parsed = yargs(process.argv.slice(2));
        this.initialArgv = parsed.argv;
        this.argv = parsed.options(opts).argv;
        this.$settingsService.setSettings({ profileDir: this.argv.profileDir });
        this.argv.profileDir = this.argv["profile-dir"] = this.$settingsService.getProfileDir();
        if (this.argv.justlaunch) {
            this.argv.watch = false;
        }
        if (this.argv.ts || this.argv.typescript) {
            this.argv.tsc = true;
        }
        if (this.argv.angular) {
            this.argv.ng = true;
        }
        if (this.argv.vuejs) {
            this.argv.vue = true;
        }
        if (this.argv.javascript) {
            this.argv.js = true;
        }
        this.argv.bundle = "webpack";
        this.adjustDashedOptions();
    }
    adjustDashedOptions() {
        _.each(this.optionNames, optionName => {
            Object.defineProperty(Options.prototype, optionName, {
                configurable: true,
                get: () => {
                    return this.getOptionValue(optionName);
                },
                set: (value) => {
                    this.argv[optionName] = value;
                }
            });
        });
    }
}
Options.DASHED_OPTION_REGEX = /(.+?)([A-Z])(.*)/;
Options.NONDASHED_OPTION_REGEX = /(.+?)[-]([a-zA-Z])(.*)/;
exports.Options = Options;
$injector.register("options", Options);
