/************** Begin of Log.h *******************************************/
/************************************************************************
 * Log.h
 *
 * edit by jesse in 2010-07-22
 * 日志相关代码的头文件
 ************************************************************************/
#if !defined(LOG_H_INCLUDED_)
#define LOG_H_INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000


///用户不需要使用日志,不要定义LOG_USELOG4CXX和LOG4C_ENABLE宏命令就可以了
#if !defined(LOG_USELOG4CXX) && !defined(LOG4C_ENABLE)

#define LOG4C(X) 
#define LOG4C_INIT()

#define LOG4C_PARAM_CFG_FILE_NAME(strCfgFileName) 
#define LOG4C_PARAM_LOG_LEVEL(strLogLevel) 
#define LOG4C_PARAM_LOG_FILE_NAME(strLogFileName) 
#define LOG4C_PARAM_LOG_FILE_SIZE(iFileSize) 
#define LOG4C_PARAM_LOG_FILE_NUM(iFileNum)
#define LOG4C_PARAM_REREAD_LOG_CFG_FILE(bReReadLogCfgFile)
#define LOG4C_INIT_WITH_PARAM()
#define LOG4C_INIT_WITH_PARAM_MULTI_PROCESS()

#define LOG4C_FINI()
#define LOG4C_INIT_DEFAULT()

#define LOG4C_NO_FILENUM(X) 
#define LOG4C_NO_FILENUM_NO_LAYOUT(X)
#define LOG4C_ORIGIN LOG4C_NO_FILENUM_NO_LAYOUT
#define LOG4C_BLOCK_BEGIN(X)
#define LOG4C_BLOCK_END(X) 
#define LOG4C_FUN(X) 
#define LOG4C_IF(X)
#define LOG4C_LINE()
#define LOG4C_HEX_DUMP(X)
#define LOG4C_RETURN(X)
#define LOG4C_RETURN_WITH_VALUE(X, reurnValue)

#else

#include <stdlib.h>

/**日志记录模块初始化宏定义
注意事项: 必须初始化日志模块后才能正确记录日志
本初始化不要求应用程序所在目录有日志配置文件log4crc，会自动生成一个缺省的log4crc文件
使用例子: LOG4C_INIT_DEFAULT();
作者:Jesse  日期:2010-07-22
*/
#define LOG4C_INIT_DEFAULT() \
	log_init_with_string("", "")

/**日志记录模块初始化宏定义
注意事项: 必须初始化日志模块后才能正确记录日志
本初始化要求应用程序所在目录有日志配置文件log4crc才行
使用例子: LOG4C_INIT();
作者:Jesse  日期:2010-07-22
*/
#define LOG4C_INIT() \
	log_init()

/************************************************************************
下面的为通过设置参数设置日志模块参数的宏定义(功能和LOG4C_INIT和LOG4C_INIT_DEFAULT类似):
1.必须先调用LOG_PARAM_XXXX系列宏定义设置参数,
1.1.如设置日志记录级别、生成日志文件名等。
1.2.若不LOG_PARAM_XXXX系列宏定义则将使用默认设置参数。
2.然后调用LOG_INIT_WITH_PARAM宏定义来初始化日志模块。
3.此时就可以记录日志了。
*/
#define LOG4C_PARAM_CFG_FILE_NAME(strCfgFileName) \
	log_set_log_cfg_file_name(strCfgFileName)

#define LOG4C_PARAM_LOG_LEVEL(strLogLevel) \
	log_set_log_level(strLogLevel)

#define LOG4C_PARAM_LOG_FILE_NAME(strLogFileName) \
	log_set_log_file_name(strLogFileName)

#define LOG4C_PARAM_LOG_FILE_SIZE(iFileSize) \
	log_set_log_file_size(iFileSize)

#define LOG4C_PARAM_LOG_FILE_NUM(iFileNum) \
	log_set_log_file_num(iFileNum)

#define LOG4C_PARAM_REREAD_LOG_CFG_FILE(bReReadLogCfgFile) \
	log_set_reread_log_cfg_file(bReReadLogCfgFile)

#define LOG4C_INIT_WITH_PARAM() \
	log_init_with_param()

#define LOG4C_INIT_WITH_PARAM_MULTI_PROCESS() \
	log_init_with_param_multi_process()

/************************************************************************/

/**日志记录模块结束宏定义
注意事项: 必须正确结束日志模块后才不会造成内存、资源泄漏
使用例子: LOG4C_FINI();
作者:Jesse  日期:2010-07-22
*/
#define LOG4C_FINI() \
	log_fini()

///进行LOG宏定义参数获取的结果
typedef struct __LOG_PARAM
{
	char strMsg[LOG4C_BUFFER_SIZE_DEFAULT];
	int iPriority;

	///LOG4C_IF时的条件参数
	int iCondition;

	///LOG4C_HEX_DUMP时的参数
	char *strHexBuf;
	int iHexBufLen;
}LOG_PARAM;

#define LOG4C(X) \
{ \
	const LOG_PARAM log_param = log_vsprintf_wrapper X; \
	log_msg( __FILE__, __LINE__, DEFAULT_LOG_CATEGORY_NAME, log_param.iPriority, log_param.strMsg ); \
}

#define LOG4C_NO_FILENUM(X) \
{ \
	const LOG_PARAM log_param = log_vsprintf_wrapper X; \
	log_msg_no_file_num( DEFAULT_LOG_CATEGORY_NAME, log_param.iPriority, log_param.strMsg );  \
}

#define LOG4C_NO_FILENUM_NO_LAYOUT(X) \
{ \
	const LOG_PARAM log_param = log_vsprintf_wrapper X; \
	log_msg_no_file_num_no_layout( DEFAULT_LOG_CATEGORY_NAME, log_param.iPriority, log_param.strMsg ); \
}

#define LOG4C_ORIGIN LOG4C_NO_FILENUM_NO_LAYOUT

#define LOG4C_BLOCK_BEGIN(X) \
{ \
	const LOG_PARAM log_param = log_vsnprintf_wrapper_msg X; \
	log4c_block_begin(__FILE__, __LINE__, log_param.strMsg); \
}

#define LOG4C_BLOCK_END(X) \
{	\
	const LOG_PARAM log_param = log_vsnprintf_wrapper_msg X; \
	log4c_block_end(__FILE__, __LINE__, log_param.strMsg); \
}

#define LOG4C_FUN(X) \
{ \
	const LOG_PARAM log_param = log_vsnprintf_wrapper_msg X; \
	log_msg_func(__FILE__, __FUNCTION__, __LINE__, DEFAULT_LOG_CATEGORY_NAME, LOG4C_PRIORITY_TRACE, log_param.strMsg ); \
}

/** Output trace on condition.
This macro outputs a trace of any information needed, using standard stream
output operators. The output is only made if the conditional is TRUE. 
example: LOG4C_IF((4>3, LOG4C_PRIORITY_TRACE, "HELLO"));
*/
#define LOG4C_IF(X) \
{ \
	const LOG_PARAM log_param = log_condition_vsnprintf_wrapper X; \
	if( log_param.iCondition ) {\
		log_msg( \
			__FILE__, \
			__LINE__, \
			DEFAULT_LOG_CATEGORY_NAME, \
			log_param.iPriority, \
			log_param.strMsg\
		); 	\
	}\
}

/** Trace the execution of a line.
This macro outputs a trace of a source file line execution.
*/
#define LOG4C_LINE() \
{ \
	char strBuffer[128] = {0}; \
	snprintf(strBuffer, sizeof(strBuffer), "line:%d", __LINE__); \
	log_msg( \
		__FILE__, \
		__LINE__, \
		DEFAULT_LOG_CATEGORY_NAME, \
		LOG4C_PRIORITY_TRACE, \
		strBuffer \
		); \
}

/**将内存中数据以十六进制方式打印出来的一个宏定义
example:LOG4C_HEX_DUMP((LOG4C_PRIORITY_TRACE, strHexBuf, iHexBufLen));
作者:Jesse 日期:2010-07-22
*/
#define LOG4C_HEX_DUMP(X)	\
{	\
	log_hex_dump_vsnprintf_wrapper X; \
}

/** 输出文件名和行号的日志输出宏,记录完日志直接return
然后再输入到LOG宏定义中
作者:Jesse 日期:2010-07-22
*/ 
#define LOG4C_RETURN(X) \
{ \
	LOG4C(X); \
	return; \
}

/** 输出文件名和行号的日志输出宏,记录完日志直接return returnValue;
然后再输入到LOG宏定义中
example:LOG4C_RETURN_WITH_VALUE(( LOG4C_PRIORITY_TRACE, "message%d", 1), returnValue);
作者:Jesse 日期:2010-07-22
*/ 
#define LOG4C_RETURN_WITH_VALUE(X, returnValue) \
{ \
	LOG4C(X); \
	return returnValue; \
}

#endif ///!defined(LOG_USELOG4CXX) 	&& 	!defined(LOG4C_ENABLE)

#if ((defined(LOG_USELOG4CXX) && defined(__cplusplus)) || defined(LOG4C_ENABLE)) 

#ifdef _WIN32
///log4c正确使用必须的一些宏定义
#define snprintf _snprintf

#ifndef HAVE_CONFIG_H
	#define HAVE_CONFIG_H
#endif
///#define LOG4C_EXPORTS
#endif

///定义linux下使用到而不存在的类型
#ifdef linux
	///typedef int BOOL;
#ifndef BOOL 
	#define BOOL int
	#define FALSE 0
	#define TRUE 1
#endif
	#define sprintf_s snprintf
	///#define strcpy_s strncpy
#endif


/// 日志输出缺省category
#ifndef DEFAULT_LOG_CATEGORY_NAME
	#define DEFAULT_LOG_CATEGORY_NAME "root"
#endif

/** 日志记录级别
*/
/** fatal */	#define LOG_FATAL		LOG4C_PRIORITY_FATAL	
/** alert */	#define LOG_ALERT		LOG4C_PRIORITY_ALERT	
/** crit */	    #define LOG_CRIT		LOG4C_PRIORITY_CRIT		
/** error */	#define LOG_ERROR		LOG4C_PRIORITY_ERROR	
/** warn */	    #define LOG_WARN		LOG4C_PRIORITY_WARN		
/** notice */	#define LOG_NOTICE		LOG4C_PRIORITY_NOTICE	
/** info */	    #define LOG_INFO		LOG4C_PRIORITY_INFO		
/** debug */	#define LOG_DEBUG		LOG4C_PRIORITY_DEBUG	
/** trace */	#define LOG_TRACE		LOG4C_PRIORITY_TRACE	
/** notset */	#define LOG_NOTSET		LOG4C_PRIORITY_NOTSET	
/** unknown */	#define LOG_UNKNOWN		LOG4C_PRIORITY_UNKNOWN

#include <log4c/defs.h>

__LOG4C_BEGIN_DECLS

/** 日志模块初始化
@return int:return 0 for success 
作者:Jesse  日期:2010-07-22
*/
LOG4C_API int log_init();

/** 日志模块初始化,指定配置文件名称
@return int:return 0 for success 
作者:Jesse  日期:2010-07-22
*/
LOG4C_API int log_init_with_cfg_file(const char *strCfgFileName);

/** 日志模块清理
@return int:return 0 for success 
作者:Jesse  日期:2010-07-22
*/
LOG4C_API int log_fini();

/**宏参数抽取priority函数
本函数接受LOG_DEBUG(X)的参数，并从该宏定义的参数中返回priority的值
@return const int : iPriority.
作者:Jesse  日期:2010-07-22
*/
LOG4C_API const int log_get_priority_wrapper(
	const int iPriority,	///日志记录级别
	const char* strFormat,	///日志内容格式
	...						///日志内容
	);

/**
将大小为count的缓冲区中内容按字节以16进制字符串打印出来,
返回值即为指向相应的字符串，
该返回指向的存储区域要调用本函数的用户显示的进行删除
*/
LOG4C_API void log4c_sprintf_data(char *buff, int count, char *dest_buffer);

/**日志记录宏定义
注意事项: 使用时参数必须使用两个括号括起来，LOG4C((X));见下面例子
使用例子: LOG4C((LOG_ERROR, "Hello World! My Name is %s, and my age is %d ", "Jess", "28" ));
作者:Jesse  日期:2010-07-22
*/

LOG4C_API const LOG_PARAM  log_vsprintf_wrapper(
	const int iPriority,	///日志记录级别
	const char* strFormat,	///日志内容格式
	...						///日志内容
	);

LOG4C_API const LOG_PARAM  log_condition_vsnprintf_wrapper(
	const int iCondition,	///条件
	const int iPriority,	///日志记录级别
	const char* strFormat,	///日志内容格式
	...						///日志内容
	);

LOG4C_API void log_hex_dump_vsnprintf_wrapper(
	const int iPriority,	///日志记录级别
	const char* strFormat,  ///日志内容格式
	const char* strHexBuf,	///缓冲区首地址
	const int iHexBufLen,	///缓冲区长度
	...						///日志内容
	);

LOG4C_API const LOG_PARAM log_vsnprintf_wrapper_msg(
	const char* strFormat,	///日志内容格式
	...						///日志内容
);

/** 日志记录
日志记录为一个字符串指针指向的内容
@return void
作者:Jesse  日期:2010-07-22
*/
LOG4C_API void log_msg(
			const char *strFile,	///文件名
			const int iLineNum,		///行号
			const char *strCatName,	///category名
			const int iPriority,	///日志记录级别
			const char *strFormat,	///日志内容格式
			...						///日志内容
			);

LOG4C_API void log_msg_func(
	const char *strFile,	///文件名
	const char *strFuncName,///函数名
	const int iLineNum,		///行号
	const char *strCatName,	///category名
	const int iPriority,	///日志记录级别
	const char *strFormat,	///日志内容格式
	...						///日志内容
	);

/** 日志记录,不记录文件名和行号
日志记录为一个字符串指针指向的内容
@return void
作者:Jesse  日期:2010-07-22
*/
LOG4C_API void log_msg_no_file_num(
			const char *strCatName,	///category名
			const int iPriority,	///日志记录级别
			const char *strFormat,	///日志内容格式
			...						///日志内容
			);

/** 日志记录,不记录文件名和行号,没有任何layout转换，直接输出相应的字符文本到日志中
此条记录没有行号，也没有线程号，也没有回车等
日志记录为一个字符串指针指向的内容
@return void
作者:Jesse  日期:2010-07-22
*/
LOG4C_API void log_msg_no_file_num_no_layout(
		   const char *strCatName,	///category名
		   const int iPriority,		///日志记录级别
		   const char *strFormat,		///日志内容格式
		   ...						///日志内容
		   );


/** 日志模块初始化
以日志配置文件字符串内容和日志配置文件命作为参数
若相应配置文件存在则使用，否则按照给定内容和文件名创建日志配置文件并使用之
@return int，0 表成功
作者:Jesse  日期:2010-07-22
*/
LOG4C_API int log_init_with_string(
			const char *strFileContent,
			const char *strFileName 
			);

/** 日志模块初始化
以日志配置文件命作为参数
@return int，0 表成功
作者:Jesse  日期:2010-07-22
*/
LOG4C_API int log_init_with_cfg_file_wrapper(
			const char * strConfigFile
			);

/** 日志模块初始化-日志配置文件的文件名设置
以日志配置文件命作为参数
@return void
作者:Jesse  日期:2010-07-22
*/
LOG4C_API void log_set_log_cfg_file_name(const char *strFileName);

/** 日志模块初始化-生成的日志文件的文件名设置
以日志文件命作为参数
@return void
作者:Jesse  日期:2010-07-22
*/
LOG4C_API void log_set_log_file_name(const char *strFileName);

/** 日志模块初始化-日志记录级别设置
@return void
作者:Jesse  日期:2010-07-22
*/
LOG4C_API void log_set_log_level(const char *strLogLevel);

/** 日志模块初始化-日志记录文件的大设置
@return void
作者:Jesse  日期:2010-07-22
*/
LOG4C_API void log_set_log_file_size(const int iFileSize);

/** 日志模块初始化-日志记录文件的个数设置
记录到最大个数后将回滚重复覆盖第一个日志文件，依次类推
@return void
作者:Jesse  日期:2010-07-22
*/
LOG4C_API void log_set_log_file_num(const int iFileNum);

/** 日志模块初始化-是否实时读取日志配置文件
设置是否每次记录时都读取日志配置文件
@param:const BOOL m_bReReadLogCfgFile
@return void
作者:Jesse  日期:2010-07-22
*/
LOG4C_API void log_set_reread_log_cfg_file(const BOOL bReReadLogCfgFile);

/** 日志模块初始化-带参数进行日志模块初始化
这里的参数则为上面的几个API设置的参数，
所以本函数一定要在日志配置参数设置好之后调用设置的参数才能生效的
@return int,OK,成功;FAILURE,失败
作者:Jesse  日期:2010-07-22
*/
LOG4C_API int log_init_with_param();

/** 日志模块初始化-带参数进行日志模块初始化,程序的多个运行实例产生的日志不互相冲突
这里的参数则为上面的几个API设置的参数，
所以本函数一定要在日志配置参数设置好之后调用设置的参数才能生效的
@return int,OK,成功;FAILURE,失败
作者:Jesse  日期:2010-07-22
*/
LOG4C_API int log_init_with_param_multi_process();

/** 日志记录Block方式能清楚的表明调用层次
类似下面这种B-Entry类型日志:
main.cpp(87) B-Entry	==> main
main.cpp(90) B-Entry	====> main_01
main.cpp(92) B-Entry	======> main_02
main.cpp(92) B-Exit	<====== main_02 
main.cpp(90) B-Exit	<==== main_01
@return void
作者:Jesse  日期:2010-07-22
*/
LOG4C_API void log4c_block_begin(const char * fileName, int lineNum, const char * traceName);

/** 日志记录Block方式能清楚的表明调用层次
类似下面这种B-Exit类型日志:
main.cpp(87) B-Entry	==> main
main.cpp(90) B-Entry	====> main_01
main.cpp(92) B-Entry	======> main_02
main.cpp(92) B-Exit	<====== main_02 
main.cpp(90) B-Exit	<==== main_01
@return void
作者:Jesse  日期:2010-07-22
*/
LOG4C_API void log4c_block_end(const char * fileName, int lineNum, const char * traceName);

/**检测配置文件是否存在
@return const int : iPriority.
作者:Jesse  日期:2010-07-22
*/
extern const int log_check(void);

/**检测配置文件是否存在,只检测传入的配置文件名
@return const int : iPriority.
作者:Jesse  日期:2010-07-22
*/
extern const int log_check_with_cfg_file(const char *strCfgFileName);

/**宏参数抽取format函数
本函数接受LOG_DEBUG(X)的参数，并从该宏定义的参数中返回format的值
@return const char* : strFormat
作者:Jesse  日期:2010-07-22
*/
extern const char* log_get_format_wrapper(
	const int iPriority,	///日志记录级别
	const char* strFormat,	///日志内容格式
	...						///日志内容
	);


/** 设置appender
@return int:
作者:Jesse  日期:2010-07-22
*/
extern int log_setappender(
			const char *strCatName,		///category名
			const char *strAppenderName ///appender名
			);

/** 日志记录
支持类似printf函数的带格式输出
@return void
作者:Jesse  日期:2010-07-22
*/
extern void log_log(
			const char *strCatName,	///category名
			const int iPriority,	///日志记录级别
			const char *strFormat,	///日志内容格式
			...						///日志内容
			);

/** 日志模块初始化-日志模块使用实例个数自增
@return void
作者:Jesse  日期:2010-07-22
*/
extern void IncreaseLogModuleUsage();

__LOG4C_END_DECLS

///#include "log4c.h"
#endif ///((defined(LOG_USELOG4CXX) && defined(__cplusplus)) || defined(LOG4C_ENABLE))

#endif // !defined(LOG_H_INCLUDED_)
/************** End of Log.h *******************************************/