/*---------------------------------------------------------
 * Copyright (C) Microsoft Corporation. All rights reserved.
 *--------------------------------------------------------*/
"use strict";
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var fs = require('fs');
var debugSession_1 = require('./debugSession');
(function (LogLevel) {
    LogLevel[LogLevel["Verbose"] = 0] = "Verbose";
    LogLevel[LogLevel["Log"] = 1] = "Log";
    LogLevel[LogLevel["Warn"] = 2] = "Warn";
    LogLevel[LogLevel["Error"] = 3] = "Error";
    LogLevel[LogLevel["Stop"] = 4] = "Stop";
})(exports.LogLevel || (exports.LogLevel = {}));
var LogLevel = exports.LogLevel;
var Logger = (function () {
    function Logger() {
        this._pendingLogQ = [];
    }
    Logger.prototype.log = function (msg, level) {
        if (level === void 0) { level = LogLevel.Log; }
        msg = msg + '\n';
        this._write(msg, level);
    };
    Logger.prototype.verbose = function (msg) {
        this.log(msg, LogLevel.Verbose);
    };
    Logger.prototype.warn = function (msg) {
        this.log(msg, LogLevel.Warn);
    };
    Logger.prototype.error = function (msg) {
        this.log(msg, LogLevel.Error);
    };
    /**
     * `log` adds a newline, `write` doesn't
     */
    Logger.prototype._write = function (msg, level) {
        if (level === void 0) { level = LogLevel.Log; }
        // [null, undefined] => string
        msg = msg + '';
        if (this._pendingLogQ) {
            this._pendingLogQ.push({ msg: msg, level: level });
        }
        else {
            this._currentLogger.log(msg, level);
        }
    };
    /**
     * Set the logger's minimum level to log in the console, and whether to log to the file. Log messages are queued before this is
     * called the first time, because minLogLevel defaults to Warn.
     */
    Logger.prototype.setup = function (consoleMinLogLevel, logToFile) {
        var _this = this;
        if (this._currentLogger) {
            this._currentLogger.setup(consoleMinLogLevel, logToFile);
            // Now that we have a minimum logLevel, we can clear out the queue of pending messages
            if (this._pendingLogQ) {
                var logQ = this._pendingLogQ;
                this._pendingLogQ = null;
                logQ.forEach(function (item) { return _this._write(item.msg, item.level); });
            }
        }
    };
    Logger.prototype.init = function (logCallback, logFilePath, logToConsole) {
        // Re-init, create new global Logger
        this._pendingLogQ = this._pendingLogQ || [];
        this._currentLogger = new InternalLogger(logCallback, logFilePath, logToConsole);
        if (logFilePath) {
            var d = new Date();
            var timestamp = d.toLocaleTimeString() + ', ' + d.toLocaleDateString();
            this.verbose(timestamp);
        }
    };
    return Logger;
}());
exports.Logger = Logger;
exports.logger = new Logger();
/**
 * Manages logging, whether to console.log, file, or VS Code console.
 * Encapsulates the state specific to each logging session
 */
var InternalLogger = (function () {
    function InternalLogger(logCallback, logFilePath, isServer) {
        this._logCallback = logCallback;
        this._logFilePath = logFilePath;
        this._logToConsole = isServer;
        this._minLogLevel = LogLevel.Warn;
    }
    InternalLogger.prototype.setup = function (consoleMinLogLevel, logToFile) {
        var _this = this;
        this._minLogLevel = consoleMinLogLevel;
        // Open a log file in the specified location. Overwritten on each run.
        if (logToFile) {
            this.log("Verbose logs are written to:\n", LogLevel.Warn);
            this.log(this._logFilePath + '\n', LogLevel.Warn);
            this._logFileStream = fs.createWriteStream(this._logFilePath);
            this._logFileStream.on('error', function (e) {
                _this.sendLog("Error involving log file at path: " + _this._logFilePath + ". Error: " + e.toString(), LogLevel.Error);
            });
        }
    };
    InternalLogger.prototype.log = function (msg, level) {
        if (this._minLogLevel === LogLevel.Stop) {
            return;
        }
        if (level >= this._minLogLevel) {
            this.sendLog(msg, level);
        }
        if (this._logToConsole) {
            var logFn = level === LogLevel.Error ? console.error :
                level === LogLevel.Warn ? console.warn :
                    console.log;
            logFn(trimLastNewline(msg));
        }
        // If an error, prepend with '[Error]'
        if (level === LogLevel.Error) {
            msg = "[" + LogLevel[level] + "] " + msg;
        }
        if (this._logFileStream) {
            this._logFileStream.write(msg);
        }
    };
    InternalLogger.prototype.sendLog = function (msg, level) {
        // Truncate long messages, they can hang VS Code
        if (msg.length > 1500) {
            var endsInNewline = !!msg.match(/(\n|\r\n)$/);
            msg = msg.substr(0, 1500) + '[...]';
            if (endsInNewline) {
                msg = msg + '\n';
            }
        }
        if (this._logCallback) {
            var event_1 = new LogOutputEvent(msg, level);
            this._logCallback(event_1);
        }
    };
    return InternalLogger;
}());
var LogOutputEvent = (function (_super) {
    __extends(LogOutputEvent, _super);
    function LogOutputEvent(msg, level) {
        var category = level === LogLevel.Error ? 'stderr' :
            level === LogLevel.Warn ? 'console' :
                'stdout';
        _super.call(this, msg, category);
    }
    return LogOutputEvent;
}(debugSession_1.OutputEvent));
exports.LogOutputEvent = LogOutputEvent;
function trimLastNewline(str) {
    return str.replace(/(\n|\r\n)$/, '');
}
exports.trimLastNewline = trimLastNewline;
//# sourceMappingURL=data:application/json;base64,[encoded data, 13528 characters]