"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const winston = require("winston");
const _ = require("lodash");
/**
 * Logging levels in Wise conforms NPM logging levels
 */
class AbstractLog {
    constructor(name) {
        this.verboseOutput = false;
        this.name = name;
    }
    init(evaluateLevels) {
        const definedLevels = evaluateLevels
            .filter(level => !!level)
            .map(level => level + "");
        const chosenLevels = winston.config.npm.levels;
        const availableLevelNames = _.keys(chosenLevels);
        definedLevels.forEach(level => {
            if (availableLevelNames.indexOf(level) === -1)
                throw new Error("Log.init fed with improper log level. "
                    + "Available levels: [ " + availableLevelNames.join(",") + " ]");
        });
        const mostVerboseLevel = definedLevels
            .reduce((prevLevel, currLevel) => chosenLevels[currLevel] > chosenLevels[prevLevel] ? currLevel : prevLevel) || "info";
        this.logger = winston.createLogger({
            levels: chosenLevels,
            level: mostVerboseLevel,
            transports: [
                new winston.transports.Console({
                    stderrLevels: _.keys(chosenLevels).filter(level => chosenLevels[level] <= chosenLevels.warn),
                    format: winston.format.combine(winston.format.timestamp({ format: "YYYY-MM-DD HH:mm:ss" }), winston.format.printf(info => {
                        if (this.verboseOutput || chosenLevels[info.level] <= chosenLevels["verbose"]) {
                            return `${this.name} | ${info.timestamp} [${info.level}]: ${info.message}`;
                        }
                        else {
                            return `${this.name} | ${info.message}`;
                        }
                    })),
                    handleExceptions: true,
                    timestamp: true,
                })
            ]
        });
        if (this.logger.levels[this.logger.level] >= this.logger.levels[AbstractLog.level.http]) {
            console.log("log.level[\"" + this.name + "\"]=\"" + this.getLogger().level + "\"");
        }
    }
    setVerboseOutput(verboseOutput) {
        this.verboseOutput = verboseOutput;
    }
    getLevel() {
        return this.getLogger().level;
    }
    getName() {
        return this.name;
    }
    cheapDebug(debugStringReturnerFn) {
        const logger = this.getLogger();
        if (logger.levels[logger.level] >= logger.levels["debug"])
            logger.debug(debugStringReturnerFn());
    }
    isDebug() {
        const logger = this.getLogger();
        return logger.levels[logger.level] >= logger.levels["debug"];
    }
    cheapInfo(infoStringReturnerFn) {
        const logger = this.getLogger();
        if (logger.levels[logger.level] >= logger.levels["info"])
            logger.debug(infoStringReturnerFn());
    }
    promiseResolveDebug(msgBeginning, result) {
        this.cheapDebug(() => msgBeginning + JSON.stringify(result));
        return result;
    }
    promiseRejectionDebug(msgBeginning, error) {
        this.cheapDebug(() => msgBeginning + JSON.stringify(error));
        throw error;
    }
    error(msg) {
        this.getLogger().error(msg);
    }
    warn(msg) {
        this.getLogger().warn(msg);
    }
    info(msg) {
        this.getLogger().info(msg);
    }
    http(msg) {
        this.getLogger().http(msg);
    }
    verbose(msg) {
        this.getLogger().verbose(msg);
    }
    debug(msg) {
        this.getLogger().debug(msg);
    }
    silly(msg) {
        this.getLogger().silly(msg);
    }
    /**
     * Calls generator fn only if logging level is reached.
     */
    efficient(level, msgGeneratorFn) {
        const logger = this.getLogger();
        if (logger.levels[logger.level] >= logger.levels[level]) {
            logger.log(level, msgGeneratorFn());
        }
    }
    exception(level, error) {
        const logger = this.getLogger();
        logger.log(level, error.name + ": " + error.message
            + (error.stack ? "\n" + error.stack : ""));
    }
    json(level, object, pretty = false) {
        const logger = this.getLogger();
        logger.log(level, (pretty ? JSON.stringify(object, undefined, 2) : JSON.stringify(object)));
    }
    getLogger() {
        if (!this.logger) {
            this.init([]);
            if (!this.logger)
                throw new Error("Could not initialize logger");
        }
        return this.logger;
    }
}
AbstractLog.level = {
    error: "error",
    warn: "warn",
    info: "info",
    http: "http",
    verbose: "verbose",
    debug: "debug",
    silly: "silly"
};
exports.AbstractLog = AbstractLog;
//# sourceMappingURL=Abstractlog.js.map