"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const util_1 = tslib_1.__importDefault(require("util"));
const defaultLvl = 2;
const lvlStr = ["E ", "W ", "I ", "!4", "!3", "!2", "!1", "P ", " 1", " 2", " 3", " 4"];
class Logger {
    constructor(lvl) {
        this.stackFrameOffset = 0;
        this.out = (...str) => {
            // tslint:disable-next-line
            console.log(str.join(" "));
        };
        this.lvl = lvl === undefined ? defaultLvl : lvl;
    }
    joinArgs(args) {
        return args.map((a) => {
            if (typeof a === "string") {
                return a;
            }
            if (a == null) {
                return "null";
            }
            try {
                // return JSON.stringify(a, undefined, 4);
                let type = typeof a;
                if (a === Object(a)) {
                    if (a.constructor) {
                        type = a.constructor.name;
                    }
                }
                // Have some special cases for the content
                let content = a.toString();
                if (type === "Uint8Array" || type === "Buffer") {
                    content = Buffer.from(a).toString("hex");
                }
                else if (content === "[object Object]") {
                    content = util_1.default.inspect(a);
                }
                return "{" + type + "}: " + content;
            }
            catch (e) {
                // tslint:disable-next-line
                this.out("error while inspecting:", e);
                return a;
            }
        }).join(" ");
    }
    printCaller(err, i) {
        try {
            const stack = err.stack.split("\n");
            const method = stack[i + this.stackFrameOffset].trim().replace(/^at */, "").split("(");
            let module = "unknown";
            let file = method[0].replace(/^.*\//g, "");
            if (method.length > 1) {
                module = method[0];
                file = method[1].replace(/^.*\/|\)$/g, "");
            }
            // @ts-ignore
            return (file).padEnd(30);
        }
        catch (e) {
            return this.out("Couldn't get stack - " + e.toString(), (i + 2 + this.stackFrameOffset).toString());
        }
    }
    printLvl(l, args) {
        let indent = Math.abs(l);
        indent = indent >= 5 ? 0 : indent;
        if (l <= this.lvl) {
            // tslint:disable-next-line
            this.out(lvlStr[l + 7] + ": " + this.printCaller(new Error(), 3) +
                " -> " + " ".repeat(indent * 2) + this.joinArgs(args));
        }
    }
    print(...args) {
        this.printLvl(0, args);
    }
    lvl1(...args) {
        this.printLvl(1, args);
    }
    lvl2(...args) {
        this.printLvl(2, args);
    }
    lvl3(...args) {
        this.printLvl(3, args);
    }
    lvl4(...args) {
        this.printLvl(4, args);
    }
    llvl1(...args) {
        this.printLvl(-1, args);
    }
    llvl2(...args) {
        this.printLvl(-2, args);
    }
    llvl3(...args) {
        this.printLvl(-3, args);
    }
    llvl4(...args) {
        this.printLvl(-4, args);
    }
    info(...args) {
        this.printLvl(-5, args);
    }
    warn(...args) {
        this.printLvl(-6, args);
    }
    error(...args) {
        this.printLvl(-7, args);
    }
    catch(e, ...args) {
        let errMsg = e;
        if (e instanceof Error) {
            errMsg = e.message;
        }
        if (e instanceof Error) {
            for (let i = this.stackFrameOffset; i < e.stack.split("\n").length - this.stackFrameOffset; i++) {
                this.out("C : " + this.printCaller(e, i) + " -> " + this.joinArgs(args));
            }
        }
        else {
            this.out("C : " + this.printCaller(new Error(), 2) + " -> (" + errMsg + ")");
        }
    }
    rcatch(e, ...args) {
        this.stackFrameOffset++;
        this.catch(e, ...args);
        this.stackFrameOffset--;
        const errMsg = e instanceof Error ? e.message : e;
        return Promise.reject(errMsg.toString().replace(/Error: /, ""));
    }
}
exports.Logger = Logger;
// tslint:disable-next-line
let Log = new Logger(defaultLvl);
exports.default = Log;
