/************** Begin of log.c *******************************************/
/*
* log.cpp
*
* added by jesse in 2008-2-3
* 日志相关代码的定义文件
*/

#ifdef HAVE_CONFIG_H

#endif
#include "log4c/config.h"
#include <stdlib.h>
#include <string.h>
#ifdef  HAVE_ALLOCA_H
#include <alloca.h>
#endif
#include <sd/sprintf.h>
#include <sd/malloc.h>
#include <sd/factory.h>
#include <log4c/appender.h>
#include <log4c/priority.h>
#include <log4c/logging_event.h>
#include <log4c/category.h>
#include <log4c/rc.h>
#include <sd/error.h>
#include <sd/sd_xplatform.h>
#include <sd/sd_xplatform.h>

#include "log4c/vos.h"
#include "log4c/log.h"
#include "GlobalMacro.h"

//////////////////////////////////////////////////////////////////////////
///下面括起来代码和log_check拷贝自init.c
typedef struct log_c_rcfile
{
	char name[256];
	time_t ctime;
	int    exists;
} log_c_rcfile_t;

static log_c_rcfile_t log_c_rcfiles[] = 
{
#if 1
	{ "$LOG4C_RCPATH/log4crc" },
	{  "$HOME/.log4crc" },
#endif 
	{ "./log4crc" }
};

static const int log_c_nrcfiles = sizeof(log_c_rcfiles) / sizeof(log_c_rcfiles[0]);
//////////////////////////////////////////////////////////////////////////
static SEM_ID gs_semphore = NULL;
static int gs_iModuleUsage_shmid = 0;
//////////////////////////////////////////////////////////////////////////


/** 日志模块初始化
@return int:return 0 for success 
作者:jesse  日期:2008-2-3
*/
int log_init()
{
	///设置两个环境变量SD_DEBUG和SD_ERROR,使sd_debug和sd_error两个函数起作用
	///putenv("SD_DEBUG=SD_DEBUG");
	///putenv("SD_ERROR=SD_ERROR");
	log_check();
	return(log4c_init());
}

/** 日志模块初始化,指定配置文件名称
@return int:return 0 for success 
作者:jesse  日期:2008-9-5
*/
int log_init_with_cfg_file(const char *strCfgFileName)
{
	log_check_with_cfg_file(strCfgFileName);
	return(log4c_init_with_cfg_file(strCfgFileName));
}

extern void ReleaseModuleUsage();
/** 日志模块清理
@return int:return 0 for success 
作者:jesse  日期:2008-2-3
*/
int log_fini()
{
	int iResult = log4c_fini();

	// 解决资源泄漏 [4/18/2009 jesse]
	VOS_DELETE_SEM(gs_semphore);
	ReleaseModuleUsage();

	return iResult;
}

/**检测配置文件是否存在
@return const int : iPriority.
作者:jesse  日期:2008-2-18
*/
const int log_check(void)
{ 
	int iReturn = 0;
	BOOL bCfgFileExist = FALSE;
	int i = 0;

	printf("check configuration files...\n");

	/* check configuration files */		
	printf("looking for conf files...\n");

#if 1
	snprintf(log_c_rcfiles[0].name, sizeof(log_c_rcfiles[0].name) - 1, "%s/log4crc", 
		getenv("LOG4C_RCPATH") ? getenv("LOG4C_RCPATH") : LOG4C_RCPATH);
	snprintf(log_c_rcfiles[1].name, sizeof(log_c_rcfiles[1].name) - 1, "%s/.log4crc",
		getenv("HOME") ? getenv("HOME") : "");
#endif

	for (i = 0; i < log_c_nrcfiles; i++) 
	{
		printf("checking for conf file at '%s'\n", log_c_rcfiles[i].name);
		if (SD_ACCESS_READ(log_c_rcfiles[i].name))
		{
			continue;
		}
		if (SD_STAT_CTIME(log_c_rcfiles[i].name,&log_c_rcfiles[i].ctime) != 0)
		{
			sd_error("sd_stat_ctime %s failed", log_c_rcfiles[i].name);
		}
		log_c_rcfiles[i].exists=1;
		bCfgFileExist = TRUE;

#if 0
		if (log4c_load(log_c_rcfiles[i].name) == -1)
		{
			sd_error("loading %s failed", log_c_rcfiles[i].name);
			iReturn = -1;
		}
		else
		{
			printf("loading %s succeeded\n", log_c_rcfiles[i].name);
			break;
		}
#endif

	}


	if (TRUE == bCfgFileExist)
	{
		printf("find configuration file\n");
	}
	else
	{
		printf("can't find configuration file,\nplease put you conf file in the same dir of execute file.\n");
	}

	return iReturn;
}

/**检测配置文件是否存在,只检测传入的配置文件名
@return const int : iPriority.
作者:jesse  日期:2008-9-4
*/
const int log_check_with_cfg_file(const char *strCfgFileName)
{ 
	int iReturn = 0;
	BOOL bCfgFileExist = FALSE;
	int i = 0;

	printf("check configuration files...\n");

	/* check configuration files */		
	printf("looking for conf files...\n");

#if 1
	snprintf(log_c_rcfiles[0].name, sizeof(log_c_rcfiles[0].name) - 1, "%s/log4crc", 
		getenv("LOG4C_RCPATH") ? getenv("LOG4C_RCPATH") : LOG4C_RCPATH);
	snprintf(log_c_rcfiles[1].name, sizeof(log_c_rcfiles[1].name) - 1, "%s/.log4crc",
		getenv("HOME") ? getenv("HOME") : "");
#endif

	if(NULL == strCfgFileName)
	{
		iReturn = -1;
	}
	else
	{
		printf("checking for conf file at '%s'\n", strCfgFileName);
		if (SD_ACCESS_READ(strCfgFileName))
		{
			iReturn = -1;
		}
		else
		{
			if (SD_STAT_CTIME(strCfgFileName,&log_c_rcfiles[i].ctime) != 0)
			{
				sd_error("sd_stat_ctime %s failed", strCfgFileName);
			}

			bCfgFileExist = TRUE;
#if 0
			if (log4c_load(strCfgFileName) == -1)
			{
				sd_error("loading %s failed", strCfgFileName);
				iReturn = -1;
			}
			else
			{
				printf("loading %s succeeded\n", strCfgFileName);
			}
#endif
		}		
	}

	if (TRUE == bCfgFileExist)
	{
		printf("find configuration file\n");
	}
	else
	{
		printf("can't find configuration file,\nplease put you conf file in the same dir of execute file.\n");
	}

	return iReturn;
}

/** 日志记录
日志记录为一个字符串指针指向的内容
@return void
作者:jesse  日期:2008-2-3
*/
void log_msg(
	const char *strFile,	///文件名
	const int iLineNum,		///行号
	const char *strCatName,	///category名
	const int iPriority,	///日志记录级别
	const char *strFormat,	///日志内容格式
	...						///日志内容
	)
{
	const log4c_category_t* a_category = log4c_category_get(strCatName);
	if (log4c_category_is_priority_enabled(a_category, iPriority)) 
	{		
		va_list va;
		va_start(va, strFormat);

		///下面从带路径的文件名解析出不带路径的纯文件名
		{
			///static SEM_ID semphore = NULL;
			const char * strFilePath = strFile;
			const char * strFileName = strrchr(strFilePath, '/');
			char strMsgBuffer[LOG4C_BUFFER_SIZE_MAX] = {0};

			///为线程安全这里加锁，[2/15/2008 jesse]
			if (NULL == gs_semphore)
			{
				gs_semphore = VOS_CreateMSem(VOS_SEM_Q_FIFO);
			}
			VOS_TakeSem(gs_semphore, VOS_WAIT_FOREVER);

			if (strFileName != NULL)
			{
				strFileName++;
			}
			else
			{
				strFileName = strrchr(strFilePath, '\\');
				if (strFileName != NULL)
				{
					strFileName++;
				}
				else
				{
					strFileName = strFilePath;
				}
			}

			snprintf(strMsgBuffer, sizeof(strMsgBuffer)-1, "%-8s(%d) %s\n", strFileName, iLineNum, strFormat);
			log4c_category_vlog(a_category, iPriority, strMsgBuffer, va);

			// 解锁 [2/15/2008 jesse]
			VOS_GiveSem(gs_semphore);
		}

		va_end(va);		
	}
}

/** 日志记录
日志记录为一个字符串指针指向的内容
@return void
作者:jesse  日期:2008-2-3
*/
void log_msg_func(
	const char *strFile,	///文件名
	const char *strFuncName,///函数名
	const int iLineNum,		///行号
	const char *strCatName,	///category名
	const int iPriority,	///日志记录级别
	const char *strFormat,	///日志内容格式
	...						///日志内容
	)
{
	const log4c_category_t* a_category = log4c_category_get(strCatName);
	if (log4c_category_is_priority_enabled(a_category, iPriority)) 
	{		
		va_list va;
		va_start(va, strFormat);

		///下面从带路径的文件名解析出不带路径的纯文件名
		{
			///static SEM_ID semphore = NULL;
			const char * strFilePath = strFile;
			const char * strFileName = strrchr(strFilePath, '/');
			char strMsgBuffer[LOG4C_BUFFER_SIZE_MAX] = {0};

			///为线程安全这里加锁，[2/15/2008 jesse]
			if (NULL == gs_semphore)
			{
				gs_semphore = VOS_CreateMSem(VOS_SEM_Q_FIFO);
			}
			VOS_TakeSem(gs_semphore, VOS_WAIT_FOREVER);

			if (strFileName != NULL)
			{
				strFileName++;
			}
			else
			{
				strFileName = strrchr(strFilePath, '\\');
				if (strFileName != NULL)
				{
					strFileName++;
				}
				else
				{
					strFileName = strFilePath;
				}
			}

			snprintf(strMsgBuffer, sizeof(strMsgBuffer)-1, "%-8s(%d) Function:%s %s\n", strFileName, iLineNum, strFuncName, strFormat);
			log4c_category_vlog(a_category, iPriority, strMsgBuffer, va);

			// 解锁 [2/15/2008 jesse]
			VOS_GiveSem(gs_semphore);
		}

		va_end(va);		
	}
}

/** 日志记录,不记录文件名和行号
日志记录为一个字符串指针指向的内容
@return void
作者:jesse  日期:2008-2-3
*/
void log_msg_no_file_num(
	const char *strCatName,	///category名
	const int iPriority,		///日志记录级别
	const char *strFormat,		///日志内容格式
	...						///日志内容
	)
{
	const log4c_category_t* a_category = log4c_category_get(strCatName);
	if (log4c_category_is_priority_enabled(a_category, iPriority)) 
	{		
		va_list va;
		va_start(va, strFormat);

		{
			///static SEM_ID semphore = NULL;
			char strMsgBuffer[10240] = {0};

			///为线程安全这里加锁，[2/15/2008 jesse]
			if (NULL == gs_semphore)
			{
				gs_semphore = VOS_CreateMSem(VOS_SEM_Q_FIFO);
			}
			VOS_TakeSem(gs_semphore, VOS_WAIT_FOREVER);			

			snprintf(strMsgBuffer, sizeof(strMsgBuffer)-1, "%s\n",  strFormat);
			log4c_category_vlog(a_category, iPriority, strMsgBuffer, va);

			// 解锁 [2/15/2008 jesse]
			VOS_GiveSem(gs_semphore);
		}

		va_end(va);		
	}
}


/** 日志记录,不记录文件名和行号,没有任何layout转换，直接输出相应的字符文本到日志中
此条记录没有行号，也没有线程号，也没有回车等
日志记录为一个字符串指针指向的内容
@return void
作者:jesse  日期:2008-9-14
*/
void log_msg_no_file_num_no_layout(
	const char *strCatName,	///category名
	const int iPriority,		///日志记录级别
	const char *strFormat,		///日志内容格式
	...						///日志内容
	)
{
	const log4c_category_t* a_category = log4c_category_get(strCatName);
	if (log4c_category_is_priority_enabled(a_category, iPriority)) 
	{		
		va_list va;
		va_start(va, strFormat);

		{
			///static SEM_ID semphore = NULL;
			char strMsgBuffer[10240] = {0};

			///为线程安全这里加锁，[2/15/2008 jesse]
			if (NULL == gs_semphore)
			{
				gs_semphore = VOS_CreateMSem(VOS_SEM_Q_FIFO);
			}
			VOS_TakeSem(gs_semphore, VOS_WAIT_FOREVER);			

			snprintf(strMsgBuffer, sizeof(strMsgBuffer)-1, "%s",  strFormat);
			log4c_category_vlog_no_file_num_no_layout(a_category, iPriority, strMsgBuffer, va);

			// 解锁 [2/15/2008 jesse]
			VOS_GiveSem(gs_semphore);
		}

		va_end(va);		
	}
}

/** 设置appender
@return int:
作者:jesse  日期:2008-2-3
*/
int log_setappender(
	const char *strCatName,		///category名
	const char *strAppenderName ///appender名
	)
{
	log4c_category_set_appender(log4c_category_get(strCatName), log4c_appender_get(strAppenderName));
	return(0);                     
}

/** 日志记录
支持类似printf函数的带格式输出
@return void
作者:jesse  日期:2008-2-3
*/
void log_log(
	const char *strCatName,	///category名
	const int iPriority,	///日志记录级别
	const char* strFormat,	///日志内容格式
	...						///日志内容
	)
{
	const log4c_category_t* a_category = log4c_category_get(strCatName);
	if (log4c_category_is_priority_enabled(a_category, iPriority)) 
	{
		va_list va;
		va_start(va, strFormat);
		log4c_category_vlog(a_category, iPriority, strFormat, va);
		va_end(va);
	}
}


#if 0
/** 日志记录Wrapper函数
日志记录为一个字符串指针指向的内容
@return int:return 0 for success 
作者:jesse  日期:2008-2-4
*/
void log_msg_wrapper (
	const int iPriority,	///日志记录级别
	const char *strFormat,	///日志内容格式
	...						///日志内容
	)
{
	const log4c_category_t* a_category = log4c_category_get(DEFAULT_LOG_CATEGORY_NAME);

	///log_msg(__FILE__, __LINE__, DEFAULT_LOG_CATEGORY_NAME, iPriority, strFormat);
	if (log4c_category_is_priority_enabled(a_category, iPriority)) 
	{
		char strMsg[10240] = {0};
		va_list va;
		va_start(va, strFormat);
		{			
			int iSprintSize = 0;
			iSprintSize = vsnprintf(strMsg, sizeof(strMsg), strFormat, va);
			if ( iSprintSize >= sizeof(strMsg))
			{
				sd_error("truncating message of %d bytes (bufsize = %d)", iSprintSize, sizeof(strMsg));
			}
		}
		va_end(va);

		log4c_category_vlog(a_category, iPriority, strMsg, va);		
	}	
}
#endif

const LOG_PARAM log_vsprintf_wrapper(
	const int iPriority,	///日志记录级别
	const char* strFormat,	///日志内容格式
	...						///日志内容
	)
{
	LOG_PARAM log_param;
	va_list va;
	va_start(va, strFormat);
	{	
#if 1
		vsnprintf(log_param.strMsg, LOG4C_BUFFER_SIZE_DEFAULT, strFormat, va);
#else
		memcpy(log_param.strMsg, sd_vsprintf( strFormat, va), sizeof(log_param.strMsg));	
#endif
	}
	va_end(va);

	log_param.iPriority = iPriority;

	return log_param;
}

const LOG_PARAM  log_condition_vsnprintf_wrapper(
	const int iCondition,	///条件
	const int iPriority,	///日志记录级别
	const char* strFormat,	///日志内容格式
	...						///日志内容
)
{
	LOG_PARAM log_param;
	va_list va;
	va_start(va, strFormat);
	{	
#if 1
		vsnprintf(log_param.strMsg, LOG4C_BUFFER_SIZE_DEFAULT, strFormat, va);
#else
		memcpy(log_param.strMsg, sd_vsprintf( strFormat, va), sizeof(log_param.strMsg));	
#endif	
	}
	va_end(va);

	log_param.iCondition = iCondition;
	log_param.iPriority = iPriority;

	return log_param;
}

void log_hex_dump_vsnprintf_wrapper(
	const int iPriority,	///日志记录级别
	const char* strHexBuf,		///缓冲区首地址
	const int iHexBufLen,		///缓冲区长度
	...						///日志内容
)
{
	char *strBuffer = (char *)malloc(LOG4C_BUFFER_SIZE_MAX);
	memset(strBuffer, 0, LOG4C_BUFFER_SIZE_MAX);
	log4c_sprintf_data((char*)(strHexBuf), (iHexBufLen), strBuffer);
	log_msg_no_file_num(
		DEFAULT_LOG_CATEGORY_NAME, 
		iPriority, 
		strBuffer 
		); 
}

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

	va_list va;
	va_start(va, strFormat);
	{	
#if 1
		vsnprintf(log_param.strMsg, LOG4C_BUFFER_SIZE_DEFAULT, strFormat, va);
#else
		memcpy(log_param.strMsg, sd_vsprintf( strFormat, va), sizeof(log_param.strMsg));	
#endif	
	}
	va_end(va);

	return log_param;
}

void log_msg_wrapper(
	const char *strFileName,///文件名
	const int iLineNum,		///行号
	const char *strCatName,	///category名
	const int iPriority,	///日志记录级别
	const char *strFormat,	///日志内容格式
	...						///日志内容
	)
{
	const log4c_category_t* a_category = log4c_category_get(strCatName);
	if (log4c_category_is_priority_enabled(a_category, iPriority)) 
	{
		va_list va;
		va_start(va, strFormat);
		log4c_category_vlog(a_category, iPriority, strFormat, va);
		va_end(va);
	}	
}


/**宏参数抽取format函数
本函数接受LOG_DEBUG(X)的参数，并从该宏定义的参数中返回format的值
@return const char* : strFormat
作者:jesse  日期:2008-2-4
*/
const char* log_get_format_wrapper(
	const int iPriority,	///日志记录级别
	const char* strFormat,	///日志内容格式
	...						///日志内容
	)
{
	return strFormat;
#if 0
	char* buffer  = strdup(strFormat);
	return buffer;
#endif
}

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

/**
将大小为count的缓冲区中内容按字节以16进制字符串打印出来,
返回值即为指向相应的字符串，
该返回指向的存储区域要调用本函数的用户显示的进行删除
*/
void log4c_sprintf_data(char *buff, int count, char *dest_buffer)
{
	int i,j,c;
	int printnext=1;
	char str[10] = {0};///由于这里要进行格式输出如"%.4x "等，这里给出10个字符作为格式输出冗余


	if(count)
	{
		if(count%16)
		{
			c=count+(16-count%16);
		}
		else 
		{
			c=count;
		}
	}
	else
	{
		c=count;
	}

	for(i=0;i<c;i++)
	{
		if(printnext) 
		{ 
			printnext--; 
			snprintf(str, sizeof(str), "%.4x ",i&0xffff);
			strncat(dest_buffer, str, LOG4C_BUFFER_SIZE_MAX);
			///ostr << str;
		}

		if(i<count)

		{
			snprintf(str, sizeof(str),"%3.2x",buff[i]&0xff);
			strncat(dest_buffer, str, LOG4C_BUFFER_SIZE_MAX);
			///ostr << str;
		}
		else
		{
			snprintf(str, sizeof(str), "   ");
			strncat(dest_buffer, str, LOG4C_BUFFER_SIZE_MAX);
			///ostr << str;
		}

		if(!((i+1)%8))
		{
			if((i+1)%16)
			{
				snprintf(str,  sizeof(str), " -");
				strncat(dest_buffer, str, LOG4C_BUFFER_SIZE_MAX);
				///ostr << str;
			}
			else
			{
				snprintf(str, sizeof(str), "   ");
				strncat(dest_buffer, str, LOG4C_BUFFER_SIZE_MAX);
				///ostr << str;
				for(j=i-15;j<=i;j++)
				{
					if(j<count) 
					{
						if( (buff[j]&0xff) >= 0x20 && 
							(buff[j]&0xff)<=0x7e)
						{
							snprintf(str, sizeof(str), "%c",buff[j]&0xff);
							strncat(dest_buffer, str, LOG4C_BUFFER_SIZE_MAX);
						}
						else 
						{
							snprintf(str, sizeof(str), ".");
							strncat(dest_buffer, str, LOG4C_BUFFER_SIZE_MAX);
						}
					} 
					else 
					{
						snprintf(str, sizeof(str), " ");
						strncat(dest_buffer, str, LOG4C_BUFFER_SIZE_MAX);
						///ostr << str;
					}
				}
				snprintf(str, sizeof(str), "\n"); 
				strncat(dest_buffer, str, LOG4C_BUFFER_SIZE_MAX); 

				printnext=1;      
			}
		}
	}
}

//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
static char gs_strFileContent_InC[] = 
	"<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n"
	"<!DOCTYPE log4c SYSTEM \"\">\n"
	"\n"
	"<log4c version=\"1.2.1\">\n"
	"	<config>\n"
	"		<bufsize>0</bufsize>\n"
	"		<debug level=\"2\"/>\n"
	"		<nocleanup>0</nocleanup>\n"
	"		<reread>1</reread>\n"
	"	</config>\n"
	"\n"
	"	<category name=\"root\" priority=\"notice\"  appender=\"aname\"/>\n"
	"\n"
	"	<rollingpolicy name=\"a_policy_name\" type=\"sizewin\" maxsize=\"1048576\" maxnum=\"15\" />\n"
	"	<appender name=\"aname\" type=\"rollingfile\"  logdir=\".\" prefix=\"log\" layout=\"dated_threadid\" rollingpolicy=\"a_policy_name\" />\n"
	"\n"
	"	<appender name=\"stdout\" type=\"stream\" layout=\"dated_threadid\"/>\n"
	"	<appender name=\"stderr\" type=\"stream\" layout=\"dated\"/>\n"
	"	<appender name=\"syslog\" type=\"syslog\" layout=\"basic\"/>\n"
	"</log4c>\n";

static char gs_strDefualtFileName[] = "log4crc";

int log_init_with_string(
	const char *strFileContent,
	const char *strFileName 
	)
{
	int iResult = FAILURE;
	const char * strLocalFileContent = NULL;
	const char * strLocalFileName = NULL;

	PAssertNotNull_ReturnWithValue(strFileContent, FAILURE);
	PAssertNotNull_ReturnWithValue(strFileName, FAILURE);

	strLocalFileContent = (strlen(strFileContent) > 0 ? strFileContent:gs_strFileContent_InC);
	strLocalFileName = (strlen(strFileName) > 0 ? strFileName:gs_strDefualtFileName);

	/**
	若文件已存在则不重新生成配置文件了
	否则生成新的配置文件
	*/
	if (OK != SD_ACCESS_READ(strLocalFileName))
	{
		///文件不存在新建
		FILE *file = fopen(strLocalFileName, "wb");	
		if (NULL != file)
		{
			fwrite(strLocalFileContent, 1, strlen(strLocalFileContent), file);
			fclose(file);
		}		
	}
	else
	{
		///文件存在,do nothing，使用原来的配置文件就OK了。
	}	

	//////////////////////////////////////////////////////////////////////////	
	///调用Init函数进行实际的日志模块初始化工作
	iResult = log_init_with_cfg_file_wrapper(strLocalFileName);

	return iResult;
}

int log_init_with_cfg_file_wrapper(const char * strConfigFile)
{
	int iResult = FAILURE;

	PAssertNotNull_ReturnWithValue(strConfigFile, FAILURE);

	///调用log4c的函数来初始化日志
	if (strlen(strConfigFile) > 0)
	{
		iResult = log_init_with_cfg_file(strConfigFile);
	}

	if ( OK != iResult)
	{
		iResult = log_init();
	}

	return iResult;
}

/*****************************新增的一些日志模块配置属性设置类****************/
#define MAX_FILE_NAME_LEN 512
struct ST_LogProperty
{
	char m_strLogCfgFileName[MAX_FILE_NAME_LEN];
	char m_strLogFileName[MAX_FILE_NAME_LEN];
	int m_iLogFileSize;
	char m_strLogLevel[128];
	int m_iLogFileNum;
	BOOL m_bReReadLogCfgFile;
};
typedef struct ST_LogProperty LogProperty;

static LogProperty gs_st_LogProperty = 
{
	"log4crc",
	"log",
	1048576,
	"notice",
	15,
	TRUE
};

static char gs_strFileContentFormat[] = 
	"<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n"
	"<!DOCTYPE log4c SYSTEM \"\">\n"
	"\n"
	"<log4c version=\"1.2.1\">\n"
	"	<config>\n"
	"		<bufsize>0</bufsize>\n"
	"		<debug level=\"2\"/>\n"
	"		<nocleanup>0</nocleanup>\n"
	"		<reread>%d</reread>\n"
	"	</config>\n"
	"\n"
	"	<category name=\"root\" priority=\"%s\"  appender=\"aname\"/>\n"
	"\n"
	"	<rollingpolicy name=\"a_policy_name\" type=\"sizewin\" maxsize=\"%d\" maxnum=\"%d\" />\n"
	"	<appender name=\"aname\" type=\"rollingfile\"  logdir=\".\" prefix=\"%s\" layout=\"dated_threadid\" rollingpolicy=\"a_policy_name\" />\n"
	"\n"
	"	<appender name=\"stdout\" type=\"stream\" layout=\"dated_threadid\"/>\n"
	"	<appender name=\"stderr\" type=\"stream\" layout=\"dated\"/>\n"
	"	<appender name=\"syslog\" type=\"syslog\" layout=\"basic\"/>\n"
	"</log4c>\n";

static char gs_strFileContentBuffer[4096] = {0};

void log_set_log_cfg_file_name(const char *strFileName)
{
	PAssertNotNull_Return(strFileName);
	strncpy(gs_st_LogProperty.m_strLogCfgFileName, strFileName, sizeof(gs_st_LogProperty.m_strLogCfgFileName));
}

void log_set_log_file_name(const char *strFileName)
{
	PAssertNotNull_Return(strFileName);
	strncpy(gs_st_LogProperty.m_strLogFileName, strFileName, sizeof(gs_st_LogProperty.m_strLogFileName));
}

void log_set_log_level(const char *strLogLevel)
{
	strncpy(gs_st_LogProperty.m_strLogLevel, strLogLevel, 
		sizeof(gs_st_LogProperty.m_strLogLevel));
}

void log_set_log_file_size(const int iFileSize)
{
	gs_st_LogProperty.m_iLogFileSize = iFileSize;
}

void log_set_log_file_num(const int iFileNum)
{
	gs_st_LogProperty.m_iLogFileNum = iFileNum;
}

void log_set_reread_log_cfg_file(const BOOL bReReadLogCfgFile)
{
	gs_st_LogProperty.m_bReReadLogCfgFile = bReReadLogCfgFile;
}

int log_init_with_param()
{
	snprintf(gs_strFileContentBuffer, sizeof(gs_strFileContentBuffer),
		gs_strFileContentFormat, 
		gs_st_LogProperty.m_bReReadLogCfgFile,
		gs_st_LogProperty.m_strLogLevel,
		gs_st_LogProperty.m_iLogFileSize,
		gs_st_LogProperty.m_iLogFileNum,
		gs_st_LogProperty.m_strLogFileName
		);

	return log_init_with_string(gs_strFileContentBuffer, gs_st_LogProperty.m_strLogCfgFileName);
}
/************************************************************************/

/************************************************************************/
// Instruct the compiler to put the g_lModuleUsage data
// variable in its own data section, called Shared. We
// then instruct the linker that we want the data in this
// section to be shared by all instances of this application.
#ifdef WIN32
#pragma data_seg("LogShared")
/** 数据库日志模块运行的实例个数
避免多个日志模块的运行实例使用同一个配置文件，避免使用同一个log文件来记录日志而产生冲突
*/
long g_lLogModuleUsage = -1;
#pragma data_seg()
// Instruct the linker to make the Shared section 
// readable, writable, and shared.
#pragma comment(linker, "/section:LogShared,rws")
#else 
// long g_lLogModuleUsage __attribute__((section ("shared"), shared)) = -1;
// int g_lLogModuleUsage __attribute__((section ("shared"), shared)) = -1;
// extern long GetModuleUsage();
// long g_lLogModuleUsage = GetModuleUsage();
long g_lLogModuleUsage = -1;
#endif

int log_init_with_param_multi_process()
{
	char strLogCfgFileName[MAX_FILE_NAME_LEN] = {0};
	char strLogFileName[MAX_FILE_NAME_LEN] = {0};
	char strLogModuleUsageNum[MAX_FILE_NAME_LEN] = {0};

	IncreaseLogModuleUsage();
	//snprintf(gs_st_LogProperty.m_strLogCfgFileName, sizeof(gs_st_LogProperty.m_strLogCfgFileName), 
	//	"%s%d", gs_st_LogProperty.m_strLogCfgFileName, g_lLogModuleUsage);
	//snprintf(gs_st_LogProperty.m_strLogFileName, sizeof(gs_st_LogProperty.m_strLogFileName), 
	//	"%s%d", gs_st_LogProperty.m_strLogFileName, g_lLogModuleUsage);
	snprintf(strLogModuleUsageNum, sizeof(strLogModuleUsageNum), "%d", g_lLogModuleUsage);
	strcat(gs_st_LogProperty.m_strLogCfgFileName, strLogModuleUsageNum);
	strcat(gs_st_LogProperty.m_strLogFileName, strLogModuleUsageNum);

	return log_init_with_param();
}

extern long GetModuleUsage();
extern void SetModuleUsage(long lModuleUsage);
void IncreaseLogModuleUsage()
{
#ifdef WIN32
	InterlockedIncrement((long*) &g_lLogModuleUsage);
#else
	g_lLogModuleUsage = GetModuleUsage();
	g_lLogModuleUsage ++;
	SetModuleUsage(g_lLogModuleUsage);
#endif
}

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


/************************************************************************/
///下面为LOG4C_BLOCK_XXX相关宏定义的实现代码
///进行LOG4C_BLOCK_BEGIN和LOG4C_BLOCK_END宏定义使用的Block结构
struct ST_Block
{
#define BLOCK_FREE 0
#define BLOCK_BUSY 1
	///标志是否被使用
	int iUseStatus;
	///线程ID
	TASK_ID threadId;
	///Block的层次
	int iBlockLevel;

	void (*Init)(struct ST_Block *ptrThis);
	void (*Reset)(struct ST_Block *ptrThis);

	int (*GetUseStatus)(struct ST_Block *ptrThis);
	TASK_ID (*GetThreadId)(struct ST_Block *ptrThis);
	int (*GetBlockLevel)(struct ST_Block *ptrThis);

	void (*SetUseStatus)(struct ST_Block *ptrThis, int iUseStatus);
	void (*SetThreadId)(struct ST_Block *ptrThis, TASK_ID threadId);
	void (*SetBlockLevel)(struct ST_Block *ptrThis, int iBlockLevel);
};
typedef struct ST_Block Block;

/**一个ST_BlockGroup包含5个ST_Block
ST_BlockGroup中作为ST_BlockManager中管理的节点
*/
struct ST_BlockGroup
{
#define BLOCK_GROUP_BLOCK_NUM (5)
	Block aBlock[BLOCK_GROUP_BLOCK_NUM];
	struct ST_BlockGroup *ptrBlockGroupPre;
	struct ST_BlockGroup *ptrBlockGroupNext;

	void (*Init)(struct ST_BlockGroup *ptrThis);
	Block *(*GetThreadBlock)(struct ST_BlockGroup *ptrThis, TASK_ID threadId);
	Block *(*GetFreeBlock)(struct ST_BlockGroup *ptrThis);
};
typedef struct ST_BlockGroup BlockGroup;

struct ST_BlockManager
{	
	BlockGroup *ptrBlockGroupHeader;
	BlockGroup *ptrBlockGroupTail;

	Block *(*GetThreadBlock)(struct ST_BlockManager *ptrThis, TASK_ID threadId);
	Block *(*GetFreeBlock)(struct ST_BlockManager *ptrThis);
};
typedef struct ST_BlockManager BlockManager;

extern Block *BlockManager_GetThreadBlock(BlockManager *ptrThis, TASK_ID threadId);
extern Block *BlockManager_GetFreeBlock(BlockManager *ptrThis);

BlockManager g_blockManager = 
{
	NULL,
	NULL,
	BlockManager_GetThreadBlock,
	BlockManager_GetFreeBlock
};

extern void Block_Reset(Block *ptrThis);
extern int Block_GetUseStatus(Block *ptrThis);
extern TASK_ID Block_GetThreadId(Block *ptrThis);
extern int Block_GetBlockLevel(Block *ptrThis);
extern void Block_SetUseStatus(Block *ptrThis, int iUseStatus);
extern void Block_SetThreadId(Block *ptrThis, TASK_ID threadId);
extern void Block_SetBlockLevel(Block *ptrThis, int iBlockLevel);

/**ST_Block的初始化代码
@param :Block *ptrThis
@rerurn void.
*/
void Block_Init(Block *ptrThis)
{
	PAssert_Return(ptrThis);
	memset(ptrThis, 0, sizeof(*ptrThis));

	///设置本结构的成员函数
	ptrThis->Init = Block_Init;
	ptrThis->Reset = Block_Reset;

	ptrThis->SetBlockLevel = Block_SetBlockLevel;
	ptrThis->GetBlockLevel = Block_GetBlockLevel;
	ptrThis->SetThreadId = Block_SetThreadId;
	ptrThis->GetThreadId = Block_GetThreadId;
	ptrThis->SetUseStatus = Block_SetUseStatus;
	ptrThis->GetUseStatus = Block_GetUseStatus;
	return;
}

/**ST_Block的重置代码
@param :Block *ptrThis
@rerurn void.
*/
void Block_Reset(Block *ptrThis)
{
	PAssert_Return(ptrThis);
	Block_Init(ptrThis);
	return;
}

/**ST_Block的获取成员变量iUseStatus的函数
其实直接引用成员变量就可以了，这里为了练习C实现C++而特意实现的
@param :int
@rerurn void.
*/
int Block_GetUseStatus(Block *ptrThis)
{
	PAssert_ReturnWithValue(ptrThis, 0);
	return ptrThis->iUseStatus;
}

/**ST_Block的获取成员变量threadId的函数
其实直接引用成员变量就可以了，这里为了练习C实现C++而特意实现的
@param :TASK_ID.
@rerurn void.
*/
TASK_ID Block_GetThreadId(Block *ptrThis)
{
	PAssert_ReturnWithValue(ptrThis, 0);
	return ptrThis->threadId;
}

/**ST_Block的获取成员变量iBlockLevel的函数
其实直接引用成员变量就可以了，这里为了练习C实现C++而特意实现的
@param :int.
@rerurn void.
*/
int Block_GetBlockLevel(Block *ptrThis)
{
	PAssert_ReturnWithValue(ptrThis, 0);
	return ptrThis->iBlockLevel;
}

/**ST_Block的设置成员变量iUseStatus的函数
其实直接引用成员变量就可以了，这里为了练习C实现C++而特意实现的
@param :Block *ptrThis
@param :int
@rerurn void.
*/
void Block_SetUseStatus(Block *ptrThis, int iUseStatus)
{
	PAssert_Return(ptrThis);
	ptrThis->iUseStatus = iUseStatus;
}

/**ST_Block的设置成员变量threadId的函数
其实直接引用成员变量就可以了，这里为了练习C实现C++而特意实现的
@param :Block *ptrThis
@param :TASK_ID.
@rerurn void.
*/
void Block_SetThreadId(Block *ptrThis, TASK_ID threadId)
{
	PAssert_Return(ptrThis);
	ptrThis->threadId = threadId;
}

/**ST_Block的设置成员变量iBlockLevel的函数
其实直接引用成员变量就可以了，这里为了练习C实现C++而特意实现的
@param :Block *ptrThis
@param :int.
@rerurn void.
*/
void Block_SetBlockLevel(Block *ptrThis, int iBlockLevel)
{
	PAssert_Return(ptrThis);
	ptrThis->iBlockLevel = iBlockLevel;
}

extern Block *BlockGroup_GetThreadBlock(BlockGroup *ptrThis, TASK_ID threadId);
extern Block *BlockGroup_GetFreeBlock(BlockGroup *ptrThis);

/**ST_BlockGroup的初始化代码
@param :Block *ptrThis
@rerurn void.
*/
void BlockGroup_Init(BlockGroup *ptrThis)
{
	int i = 0;
	PAssert_Return(ptrThis);
	memset(ptrThis, 0, sizeof(*ptrThis));

	ptrThis->Init = BlockGroup_Init;
	ptrThis->GetThreadBlock = BlockGroup_GetThreadBlock;
	ptrThis->GetFreeBlock = BlockGroup_GetFreeBlock;

	///初始化每个Block
	for (i = 0; i < BLOCK_GROUP_BLOCK_NUM; i++)
	{
		Block *ptrBlock = &ptrThis->aBlock[i];
		ptrBlock->Init = Block_Init;

		ptrBlock->Init(ptrBlock);
	}

	return;
}

/**从ST_BlockGroup中获取给定线程的Block的指针
@param :Block *ptrThis
@param :TASK_ID threadId
@rerurn Block *.
*/
Block *BlockGroup_GetThreadBlock(BlockGroup *ptrThis, TASK_ID threadId)
{
	Block *ptrBlockReturn = NULL;
	int i = 0;
	PAssert_ReturnWithValue(ptrThis, NULL);

	for (i = 0; i < BLOCK_GROUP_BLOCK_NUM; i++)
	{
		Block *ptrBlock = &ptrThis->aBlock[i];

		if (ptrBlock->GetThreadId(ptrBlock) == threadId)
		{
			ptrBlockReturn = ptrBlock;
			break;
		}
	}	

	return ptrBlockReturn;
}

/**从ST_BlockGroup中获取空闲的Block的指针
@param :BlockGroup *ptrThis
@rerurn Block *.
*/
Block *BlockGroup_GetFreeBlock(BlockGroup *ptrThis)
{
	Block *ptrBlockReturn = NULL;
	int i = 0;
	PAssert_ReturnWithValue(ptrThis, NULL);

	for (i = 0; i < BLOCK_GROUP_BLOCK_NUM; i++)
	{
		Block *ptrBlock = &ptrThis->aBlock[i];

		if (ptrBlock->GetUseStatus(ptrBlock) == BLOCK_FREE)
		{
			ptrBlockReturn = ptrBlock;
			break;
		}
	}	

	return ptrBlockReturn;
}

Block *BlockManager_GetThreadBlock(BlockManager *ptrThis, TASK_ID threadId)
{
	Block *ptrBlockReturn = NULL;
	BlockGroup *ptrBlockGroup = NULL;
	PAssert_ReturnWithValue(ptrThis, NULL);

	if (NULL == ptrThis->ptrBlockGroupHeader)
	{
		BlockGroup *ptrGroupBlock = (BlockGroup *)malloc(sizeof(BlockGroup)); 
		ptrGroupBlock->Init = BlockGroup_Init;
		ptrGroupBlock->Init(ptrGroupBlock);
		ptrThis->ptrBlockGroupHeader = ptrGroupBlock;
		ptrThis->ptrBlockGroupTail = ptrGroupBlock;
	}

	PAssert_ReturnWithValue(ptrThis->ptrBlockGroupHeader, NULL);

	ptrBlockGroup = ptrThis->ptrBlockGroupHeader;
	do 
	{
		ptrBlockReturn = ptrBlockGroup->GetThreadBlock(ptrBlockGroup, threadId);
		if (NULL != ptrBlockReturn)
		{
			break;
		}
		else
		{
			ptrBlockGroup = ptrBlockGroup->ptrBlockGroupNext;
		}
	} while (NULL != ptrBlockGroup);

	///此时找遍所有的链表都没有找到相应的Block，则重新找块没用的Block
	if (NULL == ptrBlockReturn)
	{
		ptrBlockReturn = ptrThis->GetFreeBlock(ptrThis);
	}

	return ptrBlockReturn;
}

Block *BlockManager_GetFreeBlock(BlockManager *ptrThis)
{
	Block *ptrBlockReturn = NULL;
	PAssert_ReturnWithValue(ptrThis, NULL);

	if(NULL == ptrThis->ptrBlockGroupHeader)
	{
		///原来没有空间则动态分配
		BlockGroup *ptrGroupBlock = (BlockGroup *)malloc(sizeof(BlockGroup)); 
		ptrGroupBlock->Init = BlockGroup_Init;
		ptrGroupBlock->Init(ptrGroupBlock);
		ptrThis->ptrBlockGroupHeader = ptrGroupBlock;
		ptrThis->ptrBlockGroupTail = ptrGroupBlock;

		ptrBlockReturn = ptrGroupBlock->GetFreeBlock(ptrGroupBlock);
	}
	else
	{
		BlockGroup *ptrBlockGroup = ptrThis->ptrBlockGroupHeader;
		do 
		{
			ptrBlockReturn = ptrBlockGroup->GetFreeBlock(ptrBlockGroup);
			if (NULL != ptrBlockReturn)
			{
				break;
			}
			else
			{
				ptrBlockGroup = ptrBlockGroup->ptrBlockGroupNext;
			}
		} while (NULL != ptrBlockGroup);

		///此时找遍所有的链表都没有找到空闲空间,则进行动态分配
		if(NULL == ptrBlockReturn)
		{
			BlockGroup *ptrBlockGroup = (BlockGroup *)malloc(sizeof(BlockGroup)); 
			ptrBlockGroup->Init = BlockGroup_Init;
			ptrBlockGroup->Init(ptrBlockGroup);

			ptrThis->ptrBlockGroupTail->ptrBlockGroupNext = ptrBlockGroup;
			ptrBlockGroup->ptrBlockGroupPre = ptrThis->ptrBlockGroupTail;
			ptrThis->ptrBlockGroupTail = ptrBlockGroup;

			ptrBlockReturn = ptrBlockGroup->GetFreeBlock(ptrBlockGroup);
		}
	}

	return ptrBlockReturn;
}

void log4c_block_begin(const char * fileName, int lineNum, const char * traceName)
{
	TASK_ID threadId = VOS_GetSelfTaskID();
	int i = 0;
	Block *ptrBlock = NULL;
	PAssert_Return(fileName);
	PAssert_Return(traceName);

	ptrBlock = g_blockManager.GetThreadBlock(&g_blockManager, threadId);
	if (NULL != ptrBlock)
	{
		int iBlockLevel = 0;
		char strMsgBuffer[LOG4C_BUFFER_SIZE_MAX] = {0};

		if (ptrBlock->GetUseStatus(ptrBlock) == BLOCK_FREE)
		{
			ptrBlock->SetUseStatus(ptrBlock, BLOCK_BUSY);
			ptrBlock->SetThreadId(ptrBlock, threadId);
			ptrBlock->SetBlockLevel(ptrBlock, 0);
		}

		if (ptrBlock->GetThreadId(ptrBlock) != threadId)
		{
			ptrBlock->SetThreadId(ptrBlock, threadId);
			ptrBlock->SetBlockLevel(ptrBlock, 0);
		}

		///ptrBlock->SetThreadId(ptrBlock, threadId);
		///ptrBlock->SetBlockLevel(ptrBlock, 0);

		iBlockLevel = ++(ptrBlock->iBlockLevel) ;

		strncat(strMsgBuffer, "B-Entry\t", sizeof(strMsgBuffer));
		for (i = 0; i < iBlockLevel; i++)
		{
			strncat(strMsgBuffer, "==", sizeof(strMsgBuffer));
		}
		strncat(strMsgBuffer, "> ", sizeof(strMsgBuffer));
		strncat(strMsgBuffer, traceName, sizeof(strMsgBuffer));

		///调用log4c的函数来记录日志
		log_msg(fileName, lineNum, "", LOG4C_PRIORITY_TRACE, strMsgBuffer);
	}
}

void log4c_block_end(const char * fileName, int lineNum, const char * traceName)
{
	TASK_ID threadId = VOS_GetSelfTaskID();
	int i = 0;
	Block *ptrBlock = NULL;
	PAssert_Return(fileName);
	PAssert_Return(traceName);

	ptrBlock = g_blockManager.GetThreadBlock(&g_blockManager, threadId);
	if (NULL != ptrBlock)
	{
		int iBlockLevel = ptrBlock->GetBlockLevel(ptrBlock);
		char strMsgBuffer[LOG4C_BUFFER_SIZE_MAX] = {0};

		strncat(strMsgBuffer, "B-Exit\t", sizeof(strMsgBuffer));
		strncat(strMsgBuffer, "<", sizeof(strMsgBuffer));
		for (i = 0; i < iBlockLevel; i++)
		{
			strncat(strMsgBuffer, "==", sizeof(strMsgBuffer));
		}
		strncat(strMsgBuffer, " ", sizeof(strMsgBuffer));
		strncat(strMsgBuffer, traceName, sizeof(strMsgBuffer));

		///调用log4c的函数来记录日志
		log_msg(fileName, lineNum, "", LOG4C_PRIORITY_TRACE, strMsgBuffer);

		iBlockLevel = --ptrBlock->iBlockLevel ;
		if (ptrBlock->iBlockLevel == 0)
		{
			ptrBlock->SetThreadId(ptrBlock, 0);
			ptrBlock->SetBlockLevel(ptrBlock, 0);
			ptrBlock->SetUseStatus(ptrBlock, BLOCK_FREE);
		}
	}
}
/************************************************************************/
/************** End of log.c *******************************************/