/**
@file log_bufferappender.c.
@brief Data storage and data reading.
*/

/********************************************************************************************
Debug Switch Definition Section
********************************************************************************************/


/********************************************************************************************
Include File Section
********************************************************************************************/
#include <stdbool.h>
#include "shell_inode.h"
#include "shell_file.h"
#include "ecarx_queue.h"
#include "string.h"
#include "ecarx_ringbuffer.h"
#include "log.h"
#include "log_manager_task.h"
#include "shell_char.h"
#include "log_bufferappender.h"
#include "log_creat.h"
//#include "task_init.h"
#include "log_manager_task.h"

/********************************************************************************************
Macro Definition Section
********************************************************************************************/
#define BUFFER_APPENDER_LOG_SIZE            (200)
#define BUFFER_APPENDER_GAGE				ERR
//#define LOG_TABLE_SIZE         (sizeof(LogBufferInfo)/sizeof(LogBufferInfo[0]))
#define LOG_NAME_MAX         10

/********************************************************************************************
Prototype Declaration Section
********************************************************************************************/
uint8_t ucLogRBPrint(uint8_t buffID,const uint8_t *format, ...);
static RB_STATUS xLogRBGetOne(uint8_t *buf, uint32_t bufsize,uint8_t buffID);
uint16_t usLog_RB_MCU_GetOne(uint8_t *buf, uint8_t bufsize,uint8_t buffID);
uint8_t ucBufferAppenderAppend(const uint8_t *logstr, int32_t priority,const uint8_t *logname);
static void vLogRbInit(uint8_t index);

static int32_t lLogOpen(struct inode * i_node, struct file * fp,uint8_t buffID);
static int32_t lLogIoctl(struct file * fp, uint32_t pdata, unsigned long arg);
static uint32_t ulLogRead(struct file *fp, uint8_t  *pbuf, uint32_t size, uint32_t *lofft,uint8_t buffID);
static uint32_t ulLogWrite(struct file *fp, const uint8_t  *pbuf, uint32_t size, uint32_t *lofft);
static void vLogClose(struct file *fp,uint8_t buffID);
int32_t lModeLogInodeInit(void);


/********************************************************************************************
Const Global Variable Definition Section
********************************************************************************************/

/********************************************************************************************
Global Variable Definition Section
********************************************************************************************/

/********************************************************************************************
Static Variable Definition Section
********************************************************************************************/
static uint8_t s_ucInitReasult = 0;
/********************************************************************************************
Structure Type Definition Section
********************************************************************************************/

static struct file_operations s_xLogFileOps=\
{
	.open = lLogOpen,
	.close = vLogClose,
	.read = ulLogRead,
	.write = ulLogWrite,
	.ioctl = lLogIoctl,
};

static NODE_MODE s_xLogMode = \
{
	.i_mode_root = LOG_ROOT_MODE,
	.i_mode_user = LOG_USER_MODE,
};



/********************************************************************************************
Function Definition Section
********************************************************************************************/
void vSignCheck(uint8_t *format)
{
    for(uint8_t i = 0;i < strlen((const char *)format);i++)
    {
       // printk("%s\n",format);
        if(format[i] == ',')
        {     
            format[i] = ';';
            //printk("format:%s\n",format);
        }
    }
}
/**
@brief Data storage
@param buffID [in] buffer ID
@param format [in] data format
@param ... [in] log data
@return status
*/
uint8_t ucLogRBPrint(uint8_t buffID,const uint8_t *format, ...)
{
	va_list ap;
	int32_t rv;
	RB_STATUS status = RB_OK;
	//uint16_t buffsize = 0;
	Log_Buffer_Param *log_cfg;

	log_cfg = &g_pxLogCfg->log_cfg[buffID];
	if((log_cfg != SAF_NULL) && (log_cfg->LOG_RBbuf != SAF_NULL))
	{
		memset(log_cfg->LOG_RBbuf, 0, LOG_RB_BUF_SIZE);	
	}
	
	va_start(ap, format);	
	rv = vsnprintf((char *)log_cfg->LOG_RBbuf, LOG_RB_BUF_SIZE, (const char *)format, ap);
	va_end(ap);
	//vSignCheck(log_cfg->LOG_RBbuf);	
	if(rv< (LOG_RB_BUF_SIZE - 2))
	{
		log_cfg->LOG_RBbuf[rv] = '\r';		
		log_cfg->LOG_RBbuf[rv +1] = '\n';
	}
	else
	{
		log_cfg->LOG_RBbuf[LOG_RB_BUF_SIZE-2]='\r';
		log_cfg->LOG_RBbuf[LOG_RB_BUF_SIZE-1]='\n';
	}
		
	if(rv > 0)
	{
		do
		{
			status = xRBPush(&log_cfg->RB_Log, (uint8_t *)log_cfg->LOG_RBbuf, strlen((const char *)log_cfg->LOG_RBbuf));
			if(RB_FULL == status)
			{
				xRBPop(&log_cfg->RB_Log, SAF_NULL ,0);
			}
			else
			{
				break;/*do nothing*/
			}
		}while(1);
		
		if(SAF_TRUE == log_cfg->open_flag)
		{			   
			status = xRBPush(&log_cfg->RB_cpy, SAF_NULL, strlen((const char *)log_cfg->LOG_RBbuf));				
			xRBPushCpyCheck(&log_cfg->RB_cpy,&log_cfg->RB_Log,status);
		}
		/*for AP log output*/
		status = xRBPush(&log_cfg->RB_AP_cpy, SAF_NULL, strlen((const char *)log_cfg->LOG_RBbuf));
		xRBPushCpyCheck(&log_cfg->RB_AP_cpy,&log_cfg->RB_Log,status);
	}
	else
	{
		status = RB_OS_ERR;
	}
	log_cfg->log_status_flag = LOG_WRITE_IDLE;
	return status;
}

static RB_STATUS xLogRBGetOne(uint8_t *buf, uint32_t bufsize,uint8_t buffID)
{
	RB_STATUS status = RB_OK;
	Log_Buffer_Param *log_cfg;

	log_cfg = &g_pxLogCfg->log_cfg[buffID];
	if(log_cfg->isvalid == SAF_TRUE)
	{
		xRBPopCpyCheck(&log_cfg->RB_cpy,&log_cfg->RB_Log);
		status= xRBPopMultiple(&log_cfg->RB_cpy, (uint8_t *)buf, (uint32_t)bufsize);
	}
	else
	{
		;//printk("%s\r\n",LOGCAT_BUFFER_ERR);
	}
	return status;
}

uint16_t usLog_RB_MCU_GetOne(uint8_t *buf, uint8_t bufsize,uint8_t buffID)
{	
	static uint8_t apgetinit = 0;
	uint32_t buflength = 0;
	RB_STATUS status = RB_OK;
	Log_Buffer_Param *log_cfg; 
	
	if(apgetinit == 0)
	{
		for(uint8_t i = 0;i < g_ucLogNum; i++)
		{
			log_cfg = &g_pxLogCfg->log_cfg[i];
			if((log_cfg->logname != SAF_NULL) && (s_ucInitReasult == 1))
			{
				memcpy((void *)&log_cfg->RB_AP_cpy, (void *)&log_cfg->RB_Log, sizeof(RB));	
			}
			else
			{
				;
			}
		}
		apgetinit = 1;
	}
	log_cfg = &g_pxLogCfg->log_cfg[buffID];
	if ((log_cfg->logname != SAF_NULL) && (s_ucInitReasult == 1))
	{
		if(log_cfg->isvalid == SAF_TRUE)
		{
			xRBPopCpyCheck(&log_cfg->RB_AP_cpy,&log_cfg->RB_Log);
			status= xRBPop(&log_cfg->RB_AP_cpy, (uint8_t *)buf, (uint8_t)bufsize);
		}
	}
	
	if(RB_OK == status)
	{
		buflength = strlen((char *)buf);
	}
	else
	{
		;
	}
	return buflength;   
}

/**
@brief Read the stored log data.
@param logstr [in] log data
@param priority [in] priority
@param logname [in] module name.
@return status
*/
uint8_t ucBufferAppenderAppend(const uint8_t *logstr, int32_t priority,const uint8_t *logname)
{
	uint8_t buffID = 0;	
	uint8_t ret = SAF_FALSE;
	Log_Buffer_Param *log_cfg;
	(void)priority;
    if(BUFFER_APPENDER_LOG_SIZE < strlen((const char *)logstr))
    {
        ret = SAF_FALSE;
    }

	for(buffID = 0;buffID < g_ucLogNum; buffID++)
	{
		log_cfg = &g_pxLogCfg->log_cfg[buffID];
		if((log_cfg->logname != SAF_NULL) && (logname != SAF_NULL))
		{
			if(log_cfg->isvalid == SAF_TRUE)
			{
				if((strlen((const char *)log_cfg->logname) == strlen((const char *)logname)) && (0 == strncmp((const char *)logname,(const char *)log_cfg->logname ,strlen((const char *)log_cfg->logname))))
				{
					//MUTEX_TAKE (log_mutex_input,SAFETYOS_MAX_DELAY );
					ucLogRBPrint(buffID,(const uint8_t *)"%s", (uint8_t *)logstr);
					//MUTEX_GIVE ( log_mutex_input );
					ret = SAF_TRUE;
					break;
				}
			}
		}
		else
		{
			;
		}
	}
    return ret;
}
/**
@brief log RB init.
@param index [in] module ID
@return void
*/

static void vLogRbInit(uint8_t buffID)
{
	uint16_t maxsize = 0;
	uint8_t status_init = 0;
	Log_Buffer_Param *log_cfg;
		
	log_cfg = &g_pxLogCfg->log_cfg[buffID];
	maxsize = *(log_cfg->buffsize);
	status_init = xRBInit(&log_cfg->RB_Log, log_cfg->RB_LogData, maxsize, log_cfg->SEM_ID_LogRb);
	if(status_init == RB_OK)
	{
		s_ucInitReasult = 1;
	}
	
	
}
/**
@brief log open.
@param i_node [in] inode
@param fp [in] fp
@param buffID [in] module ID
@return status
*/

static int32_t lLogOpen(struct inode * i_node, struct file * fp,uint8_t buffID)
{
	(void)i_node;
	(void)fp;
	Log_Buffer_Param *log_cfg;
		
	log_cfg = &g_pxLogCfg->log_cfg[buffID];
	memcpy((void *)&log_cfg->RB_cpy, (void *)&log_cfg->RB_Log, sizeof(RB));
	log_cfg->open_flag = SAF_TRUE;
	return 0;
}

/**
@brief reserve.
*/

static int32_t lLogIoctl(struct file * fp, uint32_t pdata, unsigned long arg)
{
	(void)pdata;
	(void)fp;
	(void)arg;
	return 0;
}

/**
@brief log read.
@param i_node [in] inode
@param fp [in] fp
@param buffID [in] module ID
@return status
*/

static uint32_t ulLogRead(struct file *fp, uint8_t  *pbuf, uint32_t size, uint32_t *lofft,uint8_t buffID)
{
	uint32_t ret = 0;
	(void)lofft;
	(void)fp;
	if(size >= 256)
	{
		size  = 256;
	}
	
	if(RB_OK == xLogRBGetOne((uint8_t *)pbuf, (uint32_t)size,buffID))
	{
		
		ret = strlen((const char *)pbuf);
	}
	else
	{
		;
	}
	return ret;
}

/**
 * Convert address to strange block format that freescale likes.
 *
 * @param addr
 * @param size
 * @param fb
 * @return
 */
static uint32_t ulLogWrite(struct file *fp, const uint8_t  *pbuf, uint32_t size, uint32_t *lofft)
{
	(void)size;
	(void)pbuf;
	(void)lofft;
	(void)fp;
	return 0;
}

/**
 * Convert address to strange block format that freescale likes.
 *
 * @param addr
 * @param size
 * @param fb
 * @return
 */
static void vLogClose(struct file *fp,uint8_t buffID)
{
	Log_Buffer_Param *log_cfg;
	(void)fp;
	log_cfg = &g_pxLogCfg->log_cfg[buffID];
	memcpy((void *)&log_cfg->RB_cpy, (void *)&log_cfg->RB_Log, sizeof(RB));
	log_cfg->open_flag = SAF_FALSE;

}

int32_t lModeLogInodeInit(void)
{
	INODE_STATUS ret = INODE_SUCESS;
	int32_t retvalue = 0;
	Log_Buffer_Param *log_cfg;
		
	
	for(uint8_t i = 0; i < g_ucLogNum; i++)
	{
		log_cfg = &g_pxLogCfg->log_cfg[i];
		if((SAF_NULL != log_cfg->RB_LogData) && (log_cfg->logname!=SAF_NULL))
		{
			vLogRbInit(i);
			ret = xShellInodeCreate(log_cfg->logname, &s_xLogMode, &s_xLogFileOps);
		}
	}
	if(INODE_SUCESS == ret)
	{

		retvalue = 0;
	}
	else
	{
		retvalue =  -1;
	}
	return retvalue;
}

//INODE_INIT(lModeLogInodeInit)
