/** @file       log.h
    @brief
    @details
    @version    1.0.0
*/
#ifndef LOG_H_
#define LOG_H_

#ifdef __cplusplus
extern "C" {
#endif

#ifndef __KERNEL__
#include <string.h>
#include <time.h>
#else
#include <linux/string.h>
#endif

#ifndef TRUE
#define TRUE    (1)
#endif

#ifndef FALSE
#define FALSE   (0)
#endif

#ifndef MAX
/** @def MAX
    @brief 取最大值
*/
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#endif

#ifndef MIN
/** @def MIN
    @brief 取最小值
*/
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#endif

#define TIMEZONE_EAST_8H        (8 * 3600)

#ifndef __KERNEL__
#define DUMP_PREFIX_ADDRESS     (1)
#define DUMP_PREFIX_OFFSET      (2)
#endif

#define print(format, ...)   fprintf(stdout, format, __VA_ARGS__)

typedef enum
{
    CMD_LOG_ENABLE      = 0,
    CMD_LOG_FILE        = 1,
    CMD_LOG_MAIL        = 2,
    CMD_LOG_LEVEL       = 3,
    CMD_LOG_NETWORK     = 4,
    CMD_LOG_SERVER      = 5
} LOG_CFG_CMD;

/** @enum _LOG_LEVEL_
 *  LOG等级枚举变量
 */
typedef enum
{
    LOG_Fatal   = (1 << 0),
    LOG_Error   = (1 << 1),
    LOG_Warn    = (1 << 2),
    LOG_Debug   = (1 << 3),
    LOG_Info    = (1 << 4),
    LOG_Test    = (1 << 5),
    LOG_Call    = (1 << 6),
    LOG_Devp    = (1 << 7),
    LOG_Step    = (1 << 8),
    LOG_Unknown = (1 << 9),
    LOG_All     = (0xFFFFFFFF),
    LOG_Close   = 0x0,
} LOG_LEVEL;
/** @var typedef _LOG_LEVEL_ LOG_LEVEL
 *  @brief 错误值枚举类型
 */

#ifdef DISABLE_LOG
#define LOG_BUF(level, buf, len)
#define LOG_EX(level, format, args...)
#define LOG_EX2(level, format, args...)
#define LOG_TAG_EX(tag, level, format, args...)
#define DEBUG_CODE_LINE()
#define DEBUG_FUNCTION_BEGIN()
#define DEBUG_FUNCTION_END()
#else
#define LOG_BUF(level, buf, len) do { \
    const char* pFmtBuf = format_hex_buf("", DUMP_PREFIX_ADDRESS, 16, 1, buf, len, 1); \
    IHW_LOG(level, "[%s] - %s(%04d): %s[0-%d]:\n%s", basename_v2(__FILE__), __FUNCTION__, __LINE__, \
       #buf, len, pFmtBuf); \
    free((void*)pFmtBuf); \
} while(0);
/*! \def LOG_EX
    \brief 系统日志调试宏标识
*/
#define LOG_EX(level, format, args...) (IHW_LOG(level, "[%s] - %s(%04d):" format , basename_v2(__FILE__), __FUNCTION__, __LINE__, ##args))

/*! \def LOG_TAG_EX
    \brief 系统日志调试宏标识
*/
#define LOG_TAG_EX(tag, level, format, args...) (IHW_LOG(level, "{%s} [%s] %s(%04d):" format , tag, basename_v2(__FILE__), __FUNCTION__, __LINE__, ##args))

#define LOG_EX2(level, format, args...) (IHW_LOG_UNTAG(level, format , ##args))

/*! @def APP_BUILD_INFO
    @brief 应用程序编译信息
*/
#define APP_BUILD_INFO(appname, appver) (IHW_LOG(LOG_Info, "%s Ver:%s (Build: %s %s  GCC Ver:%s) With %d(bits) OS\n", \
                                                appname, appver, __DATE__, __TIME__, __VERSION__, sizeof(int*) * 8))


/*! @def DEBUG_CODE_LINE
    @brief 输出当前函数名,行号
*/
#define DEBUG_CODE_LINE()           (LOG_EX(LOG_Info, "\n"))

/*! @def DEBUG_FUNCTION_BEGIN
    @brief 函数入口标志
*/
#define DEBUG_FUNCTION_BEGIN()      (LOG_EX(LOG_Call, "+++++\n"))

/*! @def DEBUG_FUNCTION_END
    @brief 函数出口标志
*/
#define DEBUG_FUNCTION_END()        (LOG_EX(LOG_Call, "-----\n"))

/**
 * @brief           输出调试信息
 * @param level     调试信息开关
 * @param pMsg      调试信息内容
 */
void IHW_LOG(LOG_LEVEL level, const char* pMsg, ...);
void IHW_LOG_UNTAG(LOG_LEVEL level, const char* pMsg, ...);

void IHW_LogStrWithoutPrint(int level, char* pMsg);
void IHW_LogRawString(int level, char* pMsg);

/**
 * @brief           设置调试等级
 * @param level     调试等级
 * @param iEnable   1 打开调试等级, 0 关闭调试等级
 */
void IHW_EnableLogLevel(LOG_LEVEL level, int iEnable);

/**
 * @brief           初始化系统日志功能
 * @param pLogTag   系统日志标志
 * @param pPath     系统日志保存路径
 * @param bEnable   打开/关闭调试信息
 */
void IHW_InitLOG(const char* pLogTag, const char* pPath, int bEnable);

void IHW_RunLogService(void);

/**
 * @brief 判断文件、路径是否存在
 * @param pPath - 文件路径
 * @return int 存在返回 1, 否则返回 0;
 */
int IHW_IsFileExist(const char* pPath);

char* IHW_bin2hex(char *p, const unsigned char *cp, int count);

/* Return the last part of a pathname */
static inline const char* basename_v2(const char* path)
{
    const char* tail = strrchr(path, '/');
    return tail ? tail + 1 : path;
}

static inline int dirname_v2(const char* path, char* dir)
{
    const char* tail = strrchr(path, '/');

    if(tail)
    {
        memcpy(dir, path, tail - path);
        dir[tail - path] = 0;
    }
    else
    {
        strcpy(dir, "./");
    }

    return 0;
}
#endif

const char* LogLeveToString(LOG_LEVEL lv);

const char* format_hex_buf(const char* prefix_str, int prefix_type,
                    int rowsize, int groupsize,
                    const void* buf, int len, int ascii);
#ifndef __KERNEL__
void print_hex_dump_bytes(const char* prefix_str, int prefix_type,
                          const void* buf, int len);
#endif

#ifdef __cplusplus
}
#endif 
#endif //LOG_H_