/*
 * The macro definitions for debug
 *
 * These macros are defined in static. If you want to use debug macro, you can
 * use as following code:
 *
 * In your C/C++ file, enable/disable PRINT_DEBUG macro, and then include this
 * header file.
 *
 * #define DBG_TAG           "MOD_TAG"
 * #define DBG_LVL           DBG_INFO
 * #include "debug_print.h"          // must after of DBG_LVL, DBG_TAG or other options
 *
 * Then in your C/C++ file, you can use LOG_X macro to print out logs:
 * LOG_D("this is a debug log!");
 * LOG_E("this is a error log!");
 */

#ifndef _PRINTT_DBG_H_
#define _PRINTT_DBG_H_

#include "debug_config.h"

#include <stdio.h>

#ifdef __cplusplus
extern "C" {
#endif

/* the debug log will force enable when PRINT_DEBUG macro is defined */
#if defined(PRINT_DEBUG) && !defined(DBG_ENABLE)
#define DBG_ENABLE
#endif

/* it will force output color log when PRINT_DEBUG_COLOR macro is defined */
#if defined(PRINT_DEBUG_COLOR) && !defined(DBG_COLOR)
#define DBG_COLOR
#endif

#if defined(RT_USING_ULOG)
/* using ulog compatible with rtdbg  */
#include <ulog.h>
#else

/* DEBUG level */
#define DBG_ERROR           0
#define DBG_WARNING         1
#define DBG_INFO            2
#define DBG_LOG             3

#ifdef DBG_TAG
#ifndef DBG_SECTION_NAME
#define DBG_SECTION_NAME    DBG_TAG
#endif
#else
/* compatible with old version */
#ifndef DBG_SECTION_NAME
#define DBG_SECTION_NAME    "DBG"
#endif
#endif /* DBG_TAG */

#ifdef DBG_ENABLE

#ifdef DBG_LVL
#ifndef DBG_LEVEL
#define DBG_LEVEL         DBG_LVL
#endif
#else
/* compatible with old version */
#ifndef DBG_LEVEL
#define DBG_LEVEL         DBG_WARNING
#endif
#endif /* DBG_LVL */

/*
可以选择的编码如下所示:
	编码    颜色/动作 
	0       重新设置属性到缺省设置 
	1       设置粗体 
	2       设置一半亮度（模拟彩色显示器的颜色） 
	4       设置下划线（模拟彩色显示器的颜色） 
	5       设置闪烁 
	7       设置反向图象
	8       隐形
	22      设置一般密度 
	24      关闭下划线 
	25      关闭闪烁 
	27      关闭反向图象
	颜色分为背景色和字体色，30~39用来设置字体色，40~49设置背景
	30      设置黑色前景 
	31      设置红色前景 
	32      设置绿色前景 
	33      设置黄色前景 
	34      设置蓝色前景 
	35      设置紫色前景 
	36      设置青色前景 
	37      设置白色前景 
	38      在缺省的前景颜色上设置下划线 
	39      在缺省的前景颜色上关闭下划线 
	40      设置黑色背景 
	41      设置红色背景 
	42      设置绿色背景 
	43      设置黄色背景 
	44      设置蓝色背景 
	45      设置紫色背景 
	46      设置青色背景 
	47      设置白色背景 
	49      设置缺省黑色背景

其他一些有趣的编码(“\e”也可写成“\033”):
	\e[2J     清屏 
	\e[K      清除从光标到行尾的内容 
	\e[?25l   隐藏光标 
	\e[?25h   显示光标
	\e[y;xH   设置光标位置（x代表行，y代表列）
	\e[s      保存光标位置 
	\e[u      恢复光标位置
	\e[nA     光标上移n行 
	\e[nB     光标下移n行 
	\e[nC     光标右移n行 
	\e[nD     光标左移n行
	\e[0q     关闭所有的键盘指示灯 
	\e[1q     设置“滚动锁定”指示灯 (Scroll Lock) 
	\e[2q     设置“数值锁定”指示灯 (Num Lock) 
	\e[3q     设置“大写锁定”指示灯 (Caps Lock) 
*/

/*
 * The color for terminal (foreground)
 * BLACK    30
 * RED      31
 * GREEN    32
 * YELLOW   33
 * BLUE     34
 * PURPLE   35
 * CYAN     36
 * WHITE    37
 */

#ifdef DBG_COLOR
#define _DBG_COLOR(n)        PRINT_FUNC("\e["#n"m")

#ifdef PRINT_TIME_TAG
#define _DBG_LOG_HDR(lvl_name, color_n)                    \
    do                                                      \
    {                                                       \
        char time_buffer[128] = "";                         \
        debug_get_time(time_buffer, sizeof(time_buffer));   \
        PRINT_FUNC("[""%s] ", time_buffer);\
    }                                                       \
    while (0)
#else
#define _DBG_LOG_HDR(lvl_name, color_n)                    \
    PRINT_FUNC("\e["#color_n"m[" lvl_name "/" DBG_SECTION_NAME "] ")
#endif

#define _DBG_LOG_X_END                                     \
    do                                                      \
    {                                                       \
        fflush(stdout);                                     \
    }                                                       \
    while (0)

#else
#define _DBG_COLOR(n)
#define _DBG_LOG_HDR(lvl_name, color_n)                    \
    PRINT_FUNC("[" lvl_name "/" DBG_SECTION_NAME "] ")
#define _DBG_LOG_X_END                                     \
    PRINT_FUNC("\n")
#endif /* DBG_COLOR */

/*
 * static debug routine
 * NOTE: This is a NOT RECOMMENDED API. Please using LOG_X API.
 *       It will be DISCARDED later. Because it will take up more resources.
 */
#define dbg_log(level, fmt, ...)                            \
    if ((level) <= DBG_LEVEL)                               \
    {                                                       \
        switch(level)                                       \
        {                                                   \
            case DBG_ERROR:   _DBG_LOG_HDR("E", 31); break; \
            case DBG_WARNING: _DBG_LOG_HDR("W", 33); break; \
            case DBG_INFO:    _DBG_LOG_HDR("I", 32); break; \
            case DBG_LOG:     _DBG_LOG_HDR("D", 0); break;  \
            default: break;                                 \
        }                                                   \
        PRINT_FUNC(fmt, ##__VA_ARGS__);                     \
        _DBG_COLOR(0);                                      \
    }

#define dbg_here                                            \
    if ((DBG_LEVEL) <= DBG_LOG){                            \
        PRINT_FUNC(DBG_SECTION_NAME " Here %s:%d\n",        \
            __FUNCTION__, __LINE__);                        \
    }

#define dbg_log_line(lvl, color_n, fmt, ...)                \
    do                                                      \
    {                                                       \
        _DBG_LOG_HDR(lvl, color_n);                         \
        PRINT_FUNC(fmt, ##__VA_ARGS__);                     \
        _DBG_LOG_X_END;                                     \
    }                                                       \
    while (0)

#define dbg_raw(...)         PRINT_FUNC(__VA_ARGS__);

#else
#define dbg_log(level, fmt, ...)
#define dbg_here
#define dbg_enter
#define dbg_exit
#define dbg_log_line(lvl, color_n, fmt, ...)
#define dbg_raw(...)
#endif /* DBG_ENABLE */

#if (DBG_LEVEL >= DBG_LOG)
#define LOG_D(fmt, ...)      dbg_log_line("D", 0, fmt, ##__VA_ARGS__)
#else
#define LOG_D(...)
#endif

#if (DBG_LEVEL >= DBG_INFO)
#define LOG_I(fmt, ...)      dbg_log_line("I", 32, fmt, ##__VA_ARGS__)
#else
#define LOG_I(...)
#endif

#if (DBG_LEVEL >= DBG_WARNING)
#define LOG_W(fmt, ...)      dbg_log_line("W", 33, fmt, ##__VA_ARGS__)
#else
#define LOG_W(...)
#endif

#if (DBG_LEVEL >= DBG_ERROR)
#define LOG_E(fmt, ...)      dbg_log_line("E", 31, fmt, ##__VA_ARGS__)
#else
#define LOG_E(...)
#endif

#define LOG_RAW(...)         dbg_raw(__VA_ARGS__)

#endif /* defined(RT_USING_ULOG) && define(DBG_ENABLE) */

#ifdef __cplusplus
}
#endif

#endif /* _PRINTT_DBG_H_ */
