// SPDX-License-Identifier: GPL-2.0+ AND LGPL-2.0+ AND LGPL-2.1+

#ifndef _MVB_HEAP_DEBUG_H_
#define _MVB_HEAP_DEBUG_H_

#include <stdint.h>
#include <stdio.h>
#include <unistd.h>
#include <time.h>
#include <sys/syscall.h>

static inline int64_t log_time() /* nanoseconds */
{
    struct timespec t;
    t.tv_sec = t.tv_nsec = 0;
    clock_gettime(CLOCK_MONOTONIC, &t);
    return (int64_t)(t.tv_sec)*1000000000LL + t.tv_nsec;
}
#define log_ns2s(v)   (v/1000000000.0)

static inline int log_tid()
{
    return syscall(SYS_gettid);
}

#define LOG_OFF     0    /* no log */
#define LOG_FATAL   1    /* A servre error that might casue system crash */
#define LOG_ERR     2    /* An error possibly recoverable */
#define LOG_WARN    3    /* An event that might possible lead to an error */
#define LOG_INFO    4    /* An eventfor information purposes */
#define LOG_DEBUG   5    /* A general debugging event */
#define LOG_TRACE   6    /* A Fine-grained debug message */
#define LOG_ALL     7    /* Capture any log */

#ifndef LOG_DEFAULT
#define LOG_DEFAULT LOG_DEBUG
#endif

#define LOG(log_level, print_level, fmt, arg...) \
    do { \
        if ((log_level) <= (print_level)) { \
            printf("[%.6f][%d]" fmt "\n", log_ns2s(log_time()), log_tid(), ##arg); \
        } \
    } while (0);

#define LOGA(print_level, log_tag, fmt, arg...) \
    LOG(LOG_ALL, print_level, "[A][%s]: [%s] " fmt, log_tag, __FUNCTION__, ##arg)
#define LOGT(print_level, log_tag, fmt, arg...) \
    LOG(LOG_TRACE, print_level, "[T][%s]: [%s] " fmt, log_tag, __FUNCTION__, ##arg)
#define LOGD(print_level, log_tag, fmt, arg...) \
    LOG(LOG_DEBUG, print_level, "[D][%s]: [%s] " fmt, log_tag, __FUNCTION__, ##arg)
#define LOGI(print_level, log_tag, fmt, arg...) \
    LOG(LOG_INFO, print_level, "[I][%s]: [%s] " fmt, log_tag, __FUNCTION__, ##arg)
#define LOGW(print_level, log_tag, fmt, arg...) \
    LOG(LOG_WARN, print_level, "[W][%s]: [%s] WARN: " fmt, log_tag, __FUNCTION__, ##arg)
#define LOGE(print_level, log_tag, fmt, arg...) \
    LOG(LOG_ERR, print_level, "[E][%s]: [%s@%s:L%d] ERR: " fmt, \
        log_tag, __FUNCTION__, __FILE__, __LINE__, ##arg)
#define LOGF(print_level, log_tag, fmt, arg...) \
    LOG(LOG_FATAL, print_level, "[F][%s]: [%s@%s:L%d] FATAL: " fmt, \
        log_tag, __FUNCTION__, __FILE__, __LINE__, ##arg)
#define LOGO(log_tag, fmt, arg...) \
    LOG(LOG_ALL, LOG_ALL, "[O][%s]: [%s] " fmt, log_tag, __FUNCTION__, ##arg)


extern int32_t mvb_log_level;
#define MVB_LOG_TAG "MVB"
#define MVB_LOGA(fmt, arg...) LOGA(mvb_log_level, MVB_LOG_TAG, fmt, ##arg)
#define MVB_LOGT(fmt, arg...) LOGT(mvb_log_level, MVB_LOG_TAG, fmt, ##arg)
#define MVB_LOGD(fmt, arg...) LOGD(mvb_log_level, MVB_LOG_TAG, fmt, ##arg)
#define MVB_LOGI(fmt, arg...) LOGI(mvb_log_level, MVB_LOG_TAG, fmt, ##arg)
#define MVB_LOGW(fmt, arg...) LOGW(mvb_log_level, MVB_LOG_TAG, fmt, ##arg)
#define MVB_LOGE(fmt, arg...) LOGE(mvb_log_level, MVB_LOG_TAG, fmt, ##arg)
#define MVB_LOGF(fmt, arg...) LOGF(mvb_log_level, MVB_LOG_TAG, fmt, ##arg)
#define MVB_LOGO(fmt, arg...) LOGO(MVB_LOG_TAG, fmt, ##arg)

#endif
