"use strict";
const helpers = require("../helpers");
const Future = require("fibers/future");
global.XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest;
global.XMLHttpRequest.prototype.withCredentials = false;
class AnalyticsServiceBase {
    constructor($logger, $options, $staticConfig, $errors, $prompter, $userSettingsService, $analyticsSettingsService, $progressIndicator, $osInfo) {
        this.$logger = $logger;
        this.$options = $options;
        this.$staticConfig = $staticConfig;
        this.$errors = $errors;
        this.$prompter = $prompter;
        this.$userSettingsService = $userSettingsService;
        this.$analyticsSettingsService = $analyticsSettingsService;
        this.$progressIndicator = $progressIndicator;
        this.$osInfo = $osInfo;
        this.analyticsStatuses = {};
        this.isAnalyticsStatusesInitialized = false;
    }
    get acceptTrackFeatureSetting() {
        return `Accept${this.$staticConfig.TRACK_FEATURE_USAGE_SETTING_NAME}`;
    }
    checkConsent() {
        return (() => {
            if (this.$analyticsSettingsService.canDoRequest().wait()) {
                if (this.isNotConfirmed(this.$staticConfig.TRACK_FEATURE_USAGE_SETTING_NAME).wait() && helpers.isInteractive()) {
                    this.$logger.out("Do you want to help us improve "
                        + this.$analyticsSettingsService.getClientName()
                        + " by automatically sending anonymous usage statistics? We will not use this information to identify or contact you."
                        + " You can read our official Privacy Policy at");
                    let message = this.$analyticsSettingsService.getPrivacyPolicyLink();
                    let trackFeatureUsage = this.$prompter.confirm(message, () => true).wait();
                    this.setStatus(this.$staticConfig.TRACK_FEATURE_USAGE_SETTING_NAME, trackFeatureUsage, true).wait();
                    if (!trackFeatureUsage) {
                        this.setStatus(this.$staticConfig.ERROR_REPORT_SETTING_NAME, trackFeatureUsage, true).wait();
                    }
                    this.checkConsentCore(trackFeatureUsage).wait();
                }
                if (this.isNotConfirmed(this.$staticConfig.ERROR_REPORT_SETTING_NAME).wait()) {
                    this.$logger.out(`Error reporting will be enabled. You can disable it by running '$ ${this.$staticConfig.CLIENT_NAME.toLowerCase()} error-reporting disable'.`);
                    this.setStatus(this.$staticConfig.ERROR_REPORT_SETTING_NAME, true).wait();
                }
            }
        }).future()();
    }
    trackFeature(featureName) {
        let category = this.$options.analyticsClient ||
            (helpers.isInteractive() ? "CLI" : "Non-interactive");
        return this.track(category, featureName);
    }
    track(featureName, featureValue) {
        return (() => {
            this.initAnalyticsStatuses().wait();
            this.$logger.trace(`Trying to track feature '${featureName}' with value '${featureValue}'.`);
            if (this.analyticsStatuses[this.$staticConfig.TRACK_FEATURE_USAGE_SETTING_NAME] === AnalyticsStatus.enabled) {
                this.trackFeatureCore(`${featureName}.${featureValue}`).wait();
            }
        }).future()();
    }
    trackException(exception, message) {
        return (() => {
            this.initAnalyticsStatuses().wait();
            this.$logger.trace(`Trying to track exception with message '${message}'.`);
            if (this.analyticsStatuses[this.$staticConfig.ERROR_REPORT_SETTING_NAME] === AnalyticsStatus.enabled
                && this.$analyticsSettingsService.canDoRequest().wait()) {
                try {
                    this.start().wait();
                    if (this._eqatecMonitor) {
                        this.$logger.printInfoMessageOnSameLine("Sending exception report (press Ctrl+C to stop)...");
                        this._eqatecMonitor.trackException(exception, message);
                        this.$progressIndicator.showProgressIndicator(this.waitForSending(), 500).wait();
                    }
                }
                catch (e) {
                    this.$logger.trace("Analytics exception: '%s'", e.toString());
                }
            }
        }).future()();
    }
    setStatus(settingName, enabled, doNotTrackSetting) {
        return (() => {
            this.analyticsStatuses[settingName] = enabled ? AnalyticsStatus.enabled : AnalyticsStatus.disabled;
            this.$userSettingsService.saveSetting(settingName, enabled.toString()).wait();
            if (!doNotTrackSetting) {
                this.trackFeatureCore(`${settingName}.${enabled ? "enabled" : "disabled"}`).wait();
            }
            if (this.analyticsStatuses[settingName] === AnalyticsStatus.disabled
                && this.analyticsStatuses[settingName] === AnalyticsStatus.disabled) {
                this.tryStopEqatecMonitor();
            }
        }).future()();
    }
    isEnabled(settingName) {
        return (() => {
            let analyticsStatus = this.getStatus(settingName).wait();
            return analyticsStatus === AnalyticsStatus.enabled;
        }).future()();
    }
    tryStopEqatecMonitor(code) {
        if (this._eqatecMonitor) {
            process.removeListener("exit", this.tryStopEqatecMonitor);
            this._eqatecMonitor.stop();
            this._eqatecMonitor = null;
        }
    }
    getStatusMessage(settingName, jsonFormat, readableSettingName) {
        if (jsonFormat) {
            return this.getJsonStatusMessage(settingName);
        }
        return this.getHumanReadableStatusMessage(settingName, readableSettingName);
    }
    restartEqatecMonitor(projectApiKey) {
        return (() => {
            this.tryStopEqatecMonitor();
            this.start(projectApiKey).wait();
        }).future()();
    }
    checkConsentCore(trackFeatureUsage) {
        return this.trackFeatureCore(`${this.acceptTrackFeatureSetting}.${!!trackFeatureUsage}`);
    }
    trackFeatureCore(featureTrackString) {
        return (() => {
            try {
                if (this.$analyticsSettingsService.canDoRequest().wait()) {
                    this.start().wait();
                    if (this._eqatecMonitor) {
                        this._eqatecMonitor.trackFeature(featureTrackString);
                        this.waitForSending().wait();
                    }
                }
            }
            catch (e) {
                this.$logger.trace("Analytics exception: '%s'", e.toString());
            }
        }).future()();
    }
    getStatus(settingName) {
        return (() => {
            if (!this.analyticsStatuses[settingName]) {
                let settingValue = this.$userSettingsService.getSettingValue(settingName).wait();
                if (settingValue) {
                    let isEnabled = helpers.toBoolean(settingValue);
                    if (isEnabled) {
                        this.analyticsStatuses[settingName] = AnalyticsStatus.enabled;
                    }
                    else {
                        this.analyticsStatuses[settingName] = AnalyticsStatus.disabled;
                    }
                }
                else {
                    this.analyticsStatuses[settingName] = AnalyticsStatus.notConfirmed;
                }
            }
            return this.analyticsStatuses[settingName];
        }).future()();
    }
    start(analyticsProjectKey) {
        return (() => {
            if (this._eqatecMonitor) {
                return;
            }
            require("../vendor/EqatecMonitor.min");
            analyticsProjectKey = analyticsProjectKey || this.$staticConfig.ANALYTICS_API_KEY;
            let settings = global._eqatec.createSettings(analyticsProjectKey);
            settings.useHttps = false;
            settings.userAgent = this.getUserAgentString();
            settings.version = this.$staticConfig.version;
            settings.useCookies = false;
            settings.loggingInterface = {
                logMessage: this.$logger.trace.bind(this.$logger),
                logError: this.$logger.debug.bind(this.$logger)
            };
            this._eqatecMonitor = global._eqatec.createMonitor(settings);
            let guid = this.$userSettingsService.getSettingValue(this.$staticConfig.ANALYTICS_INSTALLATION_ID_SETTING_NAME).wait();
            if (!guid) {
                guid = helpers.createGUID(false);
                this.$userSettingsService.saveSetting(this.$staticConfig.ANALYTICS_INSTALLATION_ID_SETTING_NAME, guid).wait();
            }
            this.$logger.trace("%s: %s", this.$staticConfig.ANALYTICS_INSTALLATION_ID_SETTING_NAME, guid.toString());
            this._eqatecMonitor.setInstallationID(guid);
            try {
                this._eqatecMonitor.setUserID(this.$analyticsSettingsService.getUserId().wait());
                let currentCount = this.$analyticsSettingsService.getUserSessionsCount(analyticsProjectKey).wait();
                this.$analyticsSettingsService.setUserSessionsCount(++currentCount, analyticsProjectKey).wait();
                this._eqatecMonitor.setStartCount(currentCount);
            }
            catch (e) {
                this.$logger.trace("Error while initializing eqatecMonitor", e);
            }
            this._eqatecMonitor.start();
            process.on("exit", this.tryStopEqatecMonitor);
            this.reportNodeVersion().wait();
        }).future()();
    }
    reportNodeVersion() {
        return (() => {
            let reportedVersion = process.version.slice(1).replace(/[.]/g, "_");
            this.track("NodeJSVersion", reportedVersion).wait();
        }).future()();
    }
    getUserAgentString() {
        let userAgentString;
        let osType = this.$osInfo.type();
        if (osType === "Windows_NT") {
            userAgentString = "(Windows NT " + this.$osInfo.release() + ")";
        }
        else if (osType === "Darwin") {
            userAgentString = "(Mac OS X " + this.$osInfo.release() + ")";
        }
        else {
            userAgentString = "(" + osType + ")";
        }
        return userAgentString;
    }
    isNotConfirmed(settingName) {
        return (() => {
            let analyticsStatus = this.getStatus(settingName).wait();
            return analyticsStatus === AnalyticsStatus.notConfirmed;
        }).future()();
    }
    getHumanReadableStatusMessage(settingName, readableSettingName) {
        return (() => {
            let status = null;
            if (this.isNotConfirmed(settingName).wait()) {
                status = "disabled until confirmed";
            }
            else {
                status = AnalyticsStatus[this.getStatus(settingName).wait()];
            }
            return `${readableSettingName} is ${status}.`;
        }).future()();
    }
    getJsonStatusMessage(settingName) {
        return (() => {
            let status = this.getStatus(settingName).wait();
            let enabled = status === AnalyticsStatus.notConfirmed ? null : status === AnalyticsStatus.disabled ? false : true;
            return JSON.stringify({ enabled: enabled });
        }).future()();
    }
    initAnalyticsStatuses() {
        return (() => {
            if (this.$analyticsSettingsService.canDoRequest().wait()) {
                if (!this.isAnalyticsStatusesInitialized) {
                    this.$logger.trace("Initializing analytics statuses.");
                    let settingsNames = [this.$staticConfig.TRACK_FEATURE_USAGE_SETTING_NAME, this.$staticConfig.ERROR_REPORT_SETTING_NAME];
                    settingsNames.forEach(settingName => this.getStatus(settingName).wait());
                    this.isAnalyticsStatusesInitialized = true;
                }
                this.$logger.trace("Analytics statuses: ");
                this.$logger.trace(this.analyticsStatuses);
            }
        }).future()();
    }
    getIsSending() {
        return this._eqatecMonitor.status().isSending;
    }
    waitForSending() {
        let future = new Future();
        let intervalTime = 1000;
        let remainingTime = AnalyticsServiceBase.MAX_WAIT_SENDING_INTERVAL;
        if (this.getIsSending()) {
            this.$logger.trace(`Waiting for analytics to send information. Will check in a ${intervalTime}ms.`);
            let interval = setInterval(() => {
                if (!this.getIsSending() || (remainingTime <= 0)) {
                    clearInterval(interval);
                    future.return();
                }
                remainingTime -= intervalTime;
                this.$logger.trace(`Waiting for analytics to send information. Will check in a ${intervalTime}ms. Remaining time is: ${remainingTime}`);
            }, intervalTime);
        }
        else {
            future.return();
        }
        return future;
    }
}
AnalyticsServiceBase.MAX_WAIT_SENDING_INTERVAL = 30000;
exports.AnalyticsServiceBase = AnalyticsServiceBase;
(function (AnalyticsStatus) {
    AnalyticsStatus[AnalyticsStatus["enabled"] = 0] = "enabled";
    AnalyticsStatus[AnalyticsStatus["disabled"] = 1] = "disabled";
    AnalyticsStatus[AnalyticsStatus["notConfirmed"] = 2] = "notConfirmed";
})(exports.AnalyticsStatus || (exports.AnalyticsStatus = {}));
var AnalyticsStatus = exports.AnalyticsStatus;
