/*
 * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
 *
 * This software is dual-licensed to you under the MIT License (MIT) and
 * the Universal Permissive License (UPL). See the LICENSE file in the root
 * directory for license terms. You may choose either license, or both.
 */

#ifndef IOTCS_LOG_H
#define IOTCS_LOG_H

#ifdef __cplusplus
extern "C" {
#endif

#include "advanced/iotcs_log.h"

#define LOG_LEVEL_NONE 0
#define LOG_LEVEL_CRIT 1
#define LOG_LEVEL_ERR  2
#define LOG_LEVEL_WARN 3
#define LOG_LEVEL_INFO 4
#define LOG_LEVEL_DBG  5
#define LOG_LEVEL_ALL  LOG_LEVEL_DBG
    
#define LOG_CHANNEL_DM    0
#define LOG_CHANNEL_EXT   1
#define LOG_CHANNEL_CORE  2
#define LOG_CHANNEL_JSON  3
#define LOG_CHANNEL_MSG   4
#define LOG_CHANNEL_PROTO 5
#define LOG_CHANNEL_TAM   6
#define LOG_CHANNEL_UTIL  7
#define LOG_CHANNEL_LOG   8
#define LOG_CHANNEL_TEST  9
#define LOG_CHANNEL_PORT_QUEUE  10
#define LOG_CHANNEL_PORT_CRYPTO 11
#define LOG_CHANNEL_PORT_TAM    12
#define LOG_CHANNEL_PORT_DIAG   13
#define LOG_CHANNEL_PORT_MEM    14
#define LOG_CHANNEL_PORT_MUTEX  15
#define LOG_CHANNEL_PORT_SSL    16
#define LOG_CHANNEL_PORT_SYSTEM 17
#define LOG_CHANNEL_PORT_THREAD 18
#define LOG_CHANNEL_PORT_MQTT   19
#define LOG_CHANNEL_CPP_WRAPPER 20
#define LOG_CHANNEL_NUM         21

#ifndef IOTCS_LOG_LEVEL
    #ifdef IOTCS_DEBUG
        #define IOTCS_LOG_LEVEL LOG_LEVEL_ALL
    #else
        #define IOTCS_LOG_LEVEL LOG_LEVEL_ERR
    #endif
#endif

#ifndef IOTCS_LOG_USE_FILE_LINE
    #ifdef IOTCS_DEBUG
        #define IOTCS_LOG_USE_FILE_LINE
    #endif
#endif
    
#ifdef IOTCS_LOG_USE_FILE_LINE
    #define FILE_N_LINE , __FILE__, __LINE__,
#else
    #define FILE_N_LINE ,
#endif

#define LOG_LOGS(_lvl, _ch, _msg) do {log_str(_lvl, _ch FILE_N_LINE _msg);} while(0)
#define LOG_LOGSN(_lvl, _ch, _msg, _len) do {log_strn(_lvl, _ch FILE_N_LINE _msg, _len);} while(0)
#define LOG_LOG(_lvl, _ch, _msg, ...) do {log_msg(_lvl, _ch FILE_N_LINE _msg, __VA_ARGS__);} while(0)

#if IOTCS_LOG_LEVEL >= LOG_LEVEL_CRIT
#define LOG_WRP_CRITS(_ch, _msg) LOG_LOGS(IOTCS_LOG_LEVEL_CRITICAL, _ch, _msg)
#define LOG_WRP_CRITSN(_ch, _msg, _len) LOG_LOGSN(IOTCS_LOG_LEVEL_CRITICAL, _ch, _msg, _len)
#define LOG_WRP_CRIT(_ch, _msg, ...) LOG_LOG(IOTCS_LOG_LEVEL_CRITICAL, _ch, _msg, __VA_ARGS__)
#else
#define LOG_WRP_CRITS(_ch, _msg)
#define LOG_WRP_CRITSN(_ch, _msg, _len)
#define LOG_WRP_CRIT(_ch, _msg, ...)
#endif

#if IOTCS_LOG_LEVEL >= LOG_LEVEL_ERR
#define LOG_WRP_ERRS(_ch, _msg) LOG_LOGS(IOTCS_LOG_LEVEL_ERROR, _ch, _msg)
#define LOG_WRP_ERRSN(_ch, _msg, _len) LOG_LOGSN(IOTCS_LOG_LEVEL_ERROR, _ch, _msg, _len)
#define LOG_WRP_ERR(_ch, _msg, ...) LOG_LOG(IOTCS_LOG_LEVEL_ERROR, _ch, _msg, __VA_ARGS__)
#else
#define LOG_WRP_ERRS(_ch, _msg)
#define LOG_WRP_ERRSN(_ch, _msg, _len)
#define LOG_WRP_ERR(_ch, _msg, ...)
#endif
    
#if IOTCS_LOG_LEVEL >= LOG_LEVEL_WARN
#define LOG_WRP_WARNS(_ch, _msg) LOG_LOGS(IOTCS_LOG_LEVEL_WARNING, _ch, _msg)
#define LOG_WRP_WARNSN(_ch, _msg, _len) LOG_LOGSN(IOTCS_LOG_LEVEL_WARNING, _ch, _msg, _len)
#define LOG_WRP_WARN(_ch, _msg, ...) LOG_LOG(IOTCS_LOG_LEVEL_WARNING, _ch, _msg, __VA_ARGS__)
#else
#define LOG_WRP_WARNS(_ch, _msg)
#define LOG_WRP_WARNSN(_ch, _msg, _len)
#define LOG_WRP_WARN(_ch, _msg, ...)
#endif
    
#if IOTCS_LOG_LEVEL >= LOG_LEVEL_INFO
#define LOG_WRP_INFOS(_ch, _msg) LOG_LOGS(IOTCS_LOG_LEVEL_INFO, _ch, _msg)
#define LOG_WRP_INFOSN(_ch, _msg, _len) LOG_LOGSN(IOTCS_LOG_LEVEL_INFO, _ch, _msg, _len)
#define LOG_WRP_INFO(_ch, _msg, ...) LOG_LOG(IOTCS_LOG_LEVEL_INFO, _ch, _msg, __VA_ARGS__)
#else
#define LOG_WRP_INFOS(_ch, _msg)
#define LOG_WRP_INFOSN(_ch, _msg, _len)
#define LOG_WRP_INFO(_ch, _msg, ...)
#endif
    
#if IOTCS_LOG_LEVEL >= LOG_LEVEL_DBG
#define LOG_WRP_DBGS(_ch, _msg) LOG_LOGS(IOTCS_LOG_LEVEL_DEBUG, _ch, _msg)
#define LOG_WRP_DBGSN(_ch, _msg, _len) LOG_LOGSN(IOTCS_LOG_LEVEL_DEBUG, _ch, _msg, _len)
#define LOG_WRP_DBG(_ch, _msg, ...) LOG_LOG(IOTCS_LOG_LEVEL_DEBUG, _ch, _msg, __VA_ARGS__)
#else
#define LOG_WRP_DBGS(_ch, _msg)
#define LOG_WRP_DBGSN(_ch, _msg, _len)
#define LOG_WRP_DBG(_ch, _msg, ...)
#endif

iotcs_result log_internal_init(void);
void log_internal_finit(void);
#ifdef IOTCS_LOG_USE_FILE_LINE
void log_msg(iotcs_log_level level, iotcs_log_channel channel, const char *file, int line, const char *fmt, ...);
void log_str(iotcs_log_level level, iotcs_log_channel channel, const char *file, int line, const char *preformatted);
void log_strn(iotcs_log_level level, iotcs_log_channel channel, const char *file, int line, const char *preformatted, size_t len);
#else
void log_msg(iotcs_log_level level, iotcs_log_channel channel, const char *fmt, ...);
void log_str(iotcs_log_level level, iotcs_log_channel channel, const char *preformatted);
void log_strn(iotcs_log_level level, iotcs_log_channel channel, const char *preformatted, size_t len);
#endif

void log_printdump(const char* buffer, int sz);

#ifdef __cplusplus
}
#endif

#endif /* IOTCS_LOG_H */
