"use strict";
const osenv = require("osenv");
const path = require("path");
const util = require("util");
class AutoCompletionService {
    constructor($fs, $childProcess, $logger, $staticConfig, $hostInfo) {
        this.$fs = $fs;
        this.$childProcess = $childProcess;
        this.$logger = $logger;
        this.$staticConfig = $staticConfig;
        this.$hostInfo = $hostInfo;
        this.scriptsOk = true;
        this.scriptsUpdated = false;
        this.disableAnalytics = true;
    }
    get shellProfiles() {
        if (!this._shellProfiles) {
            this._shellProfiles = [];
            this._shellProfiles.push(this.getHomePath(".bash_profile"));
            this._shellProfiles.push(this.getHomePath(".bashrc"));
            this._shellProfiles.push(this.getHomePath(".zshrc"));
        }
        return this._shellProfiles;
    }
    get cliRunCommandsFile() {
        if (!this._cliRunCommandsFile) {
            this._cliRunCommandsFile = this.getHomePath(util.format(".%src", this.$staticConfig.CLIENT_NAME.toLowerCase()));
            if (this.$hostInfo.isWindows) {
                this._cliRunCommandsFile = this._cliRunCommandsFile.replace(/\\/g, "/");
            }
        }
        return this._cliRunCommandsFile;
    }
    getTabTabObsoleteRegex(clientName) {
        let tabTabStartPoint = util.format(AutoCompletionService.TABTAB_COMPLETION_START_REGEX_PATTERN, clientName.toLowerCase());
        let tabTabEndPoint = util.format(AutoCompletionService.TABTAB_COMPLETION_END_REGEX_PATTERN, clientName.toLowerCase());
        let tabTabRegex = new RegExp(util.format("%s[\\s\\S]*%s", tabTabStartPoint, tabTabEndPoint));
        return tabTabRegex;
    }
    removeObsoleteAutoCompletion() {
        return (() => {
            let shellProfilesToBeCleared = this.shellProfiles;
            shellProfilesToBeCleared.push(this.getHomePath(".profile"));
            shellProfilesToBeCleared.forEach(file => {
                try {
                    let text = this.$fs.readText(file).wait();
                    let newText = text.replace(this.getTabTabObsoleteRegex(this.$staticConfig.CLIENT_NAME), "");
                    if (this.$staticConfig.CLIENT_NAME_ALIAS) {
                        newText = newText.replace(this.getTabTabObsoleteRegex(this.$staticConfig.CLIENT_NAME_ALIAS), "");
                    }
                    if (newText !== text) {
                        this.$logger.trace("Remove obsolete AutoCompletion from file %s.", file);
                        this.$fs.writeFile(file, newText).wait();
                    }
                }
                catch (error) {
                    if (error.code !== "ENOENT") {
                        this.$logger.trace("Error while trying to disable autocompletion for '%s' file. Error is:\n%s", error.toString());
                    }
                }
            });
        }).future()();
    }
    get completionShellScriptContent() {
        if (!this._completionShellScriptContent) {
            let startText = util.format(AutoCompletionService.COMPLETION_START_COMMENT_PATTERN, this.$staticConfig.CLIENT_NAME.toLowerCase());
            let content = util.format("if [ -f %s ]; then \n    source %s \nfi", this.cliRunCommandsFile, this.cliRunCommandsFile);
            let endText = util.format(AutoCompletionService.COMPLETION_END_COMMENT_PATTERN, this.$staticConfig.CLIENT_NAME.toLowerCase());
            this._completionShellScriptContent = util.format("\n%s\n%s\n%s\n", startText, content, endText);
        }
        return this._completionShellScriptContent;
    }
    isAutoCompletionEnabled() {
        return (() => {
            let result = true;
            _.each(this.shellProfiles, filePath => {
                result = this.isNewAutoCompletionEnabledInFile(filePath).wait() || this.isObsoleteAutoCompletionEnabledInFile(filePath).wait();
                if (!result) {
                    return false;
                }
            });
            return result;
        }).future()();
    }
    disableAutoCompletion() {
        return (() => {
            _.each(this.shellProfiles, shellFile => this.removeAutoCompletionFromShellScript(shellFile).wait());
            this.removeObsoleteAutoCompletion().wait();
            if (this.scriptsOk && this.scriptsUpdated) {
                this.$logger.out("Restart your shell to disable command auto-completion.");
            }
        }).future()();
    }
    enableAutoCompletion() {
        return (() => {
            this.updateCLIShellScript().wait();
            _.each(this.shellProfiles, shellFile => this.addAutoCompletionToShellScript(shellFile).wait());
            this.removeObsoleteAutoCompletion().wait();
            if (this.scriptsOk && this.scriptsUpdated) {
                this.$logger.out("Restart your shell to enable command auto-completion.");
            }
        }).future()();
    }
    isObsoleteAutoCompletionEnabled() {
        return (() => {
            let result = true;
            _.each(this.shellProfiles, shellProfile => {
                result = this.isObsoleteAutoCompletionEnabledInFile(shellProfile).wait();
                if (!result) {
                    return false;
                }
            });
            return result;
        }).future()();
    }
    isNewAutoCompletionEnabledInFile(fileName) {
        return (() => {
            try {
                let data = this.$fs.readText(fileName).wait();
                if (data && data.indexOf(this.completionShellScriptContent) !== -1) {
                    return true;
                }
            }
            catch (err) {
                this.$logger.trace("Error while checking is autocompletion enabled in file %s. Error is: '%s'", fileName, err.toString());
            }
            return false;
        }).future()();
    }
    isObsoleteAutoCompletionEnabledInFile(fileName) {
        return (() => {
            try {
                let text = this.$fs.readText(fileName).wait();
                return text.match(this.getTabTabObsoleteRegex(this.$staticConfig.CLIENT_NAME)) || text.match(this.getTabTabObsoleteRegex(this.$staticConfig.CLIENT_NAME));
            }
            catch (err) {
                this.$logger.trace("Error while checking is obsolete autocompletion enabled in file %s. Error is: '%s'", fileName, err.toString());
            }
        }).future()();
    }
    addAutoCompletionToShellScript(fileName) {
        return (() => {
            try {
                if (!this.isNewAutoCompletionEnabledInFile(fileName).wait() || this.isObsoleteAutoCompletionEnabledInFile(fileName).wait()) {
                    this.$logger.trace("AutoCompletion is not enabled in %s file. Trying to enable it.", fileName);
                    this.$fs.appendFile(fileName, this.completionShellScriptContent).wait();
                    this.scriptsUpdated = true;
                }
            }
            catch (err) {
                this.$logger.out("Unable to update %s. Command-line completion might not work.", fileName);
                if ((err.code === "EPERM" || err.code === "EACCES") && !this.$hostInfo.isWindows && process.env.SUDO_USER) {
                    this.$logger.out("To enable command-line completion, run '$ %s autocomplete enable'.", this.$staticConfig.CLIENT_NAME);
                }
                this.$logger.trace(err);
                this.scriptsOk = false;
            }
        }).future()();
    }
    removeAutoCompletionFromShellScript(fileName) {
        return (() => {
            try {
                if (this.isNewAutoCompletionEnabledInFile(fileName).wait()) {
                    this.$logger.trace("AutoCompletion is enabled in %s file. Trying to disable it.", fileName);
                    let data = this.$fs.readText(fileName).wait();
                    data = data.replace(this.completionShellScriptContent, "");
                    this.$fs.writeFile(fileName, data).wait();
                    this.scriptsUpdated = true;
                }
            }
            catch (err) {
                if (err.code !== "ENOENT") {
                    this.$logger.out("Failed to update %s. Auto-completion may still work or work incorrectly. ", fileName);
                    this.$logger.out(err);
                    this.scriptsOk = false;
                }
            }
        }).future()();
    }
    updateCLIShellScript() {
        return (() => {
            let filePath = this.cliRunCommandsFile;
            try {
                let doUpdate = true;
                if (this.$fs.exists(filePath).wait()) {
                    let contents = this.$fs.readText(filePath).wait();
                    let regExp = new RegExp(util.format("%s\\s+completion\\s+--\\s+", this.$staticConfig.CLIENT_NAME.toLowerCase()));
                    let matchCondition = contents.match(regExp);
                    if (this.$staticConfig.CLIENT_NAME_ALIAS) {
                        matchCondition = matchCondition || contents.match(new RegExp(util.format("%s\\s+completion\\s+--\\s+", this.$staticConfig.CLIENT_NAME_ALIAS.toLowerCase())));
                    }
                    if (matchCondition) {
                        doUpdate = false;
                    }
                }
                if (doUpdate) {
                    let clientExecutableFileName = (this.$staticConfig.CLIENT_NAME_ALIAS || this.$staticConfig.CLIENT_NAME).toLowerCase();
                    let pathToExecutableFile = path.join(__dirname, `../../../bin/${clientExecutableFileName}.js`);
                    this.$childProcess.exec(`"${process.argv[0]}" "${pathToExecutableFile}" completion >> "${filePath}"`).wait();
                    this.$fs.chmod(filePath, "0644").wait();
                }
            }
            catch (err) {
                this.$logger.out("Failed to update %s. Auto-completion may not work. ", filePath);
                this.$logger.trace(err);
                this.scriptsOk = false;
            }
        }).future()();
    }
    getHomePath(fileName) {
        return path.join(osenv.home(), fileName);
    }
}
AutoCompletionService.COMPLETION_START_COMMENT_PATTERN = "###-%s-completion-start-###";
AutoCompletionService.COMPLETION_END_COMMENT_PATTERN = "###-%s-completion-end-###";
AutoCompletionService.TABTAB_COMPLETION_START_REGEX_PATTERN = "###-begin-%s-completion-###";
AutoCompletionService.TABTAB_COMPLETION_END_REGEX_PATTERN = "###-end-%s-completion-###";
exports.AutoCompletionService = AutoCompletionService;
$injector.register("autoCompletionService", AutoCompletionService);
