#include "macro_common.h"
#include "uart.h"
#include "trace.h"
#include "console.h"

/*TRACE模式使用的输出函数，cli模块借用trace模块的输出函数进行输出，cli初始化时根据
指定uart端口指定输出函数*/
extern trace_msg_send g_msg_msg_send;

/*console口的命令信息*/
console_cmd_info g_cmd_info;

/*记录上一个输入的命令，用于上箭头时重复执行，目前只支持一条历史命令*/
char g_cmd_last_cmd[CMD_LINE_LEN_MAX];

/*存储console使用的串口ID*/
u8 Console_UID;


/*用于保存用户注册的所有命令的数据结构*/
S_CLI_CMD_LIST	g_cli_cmd_list;

/*功能*/
const u32 escape_sequences[] =
{
    0x001B4F50,                 /* PF1 */
    0x001B4F51,                 /* PF2 */
    0x001B4F52,                 /* PF3 */
    0x001B4F53,                 /* PF4 */
    0x001B5B41,                 /* UP */
    0x001B5B42,                 /* DOWN */
    0x001B5B43,                 /* RIGHT */
    0x001B5B44,                 /* LEFT */
    0
};


/**************************************************************************************************
*cmd_cmdline_parse --命令行解析函数
*Input:
*	pcmd	--需要解析的命令字符串；
*	cmdlen	--需要解析的字符串的长度；
*Output:
*	argv	--解析出的参数变量
*	argc	--解析出的参数数目
*Return:
*	0		--正确解析
*	-1	--命令字符串有错误
*/
static int cmd_cmdline_parse(char *pcmd, u8 cmdlen, char **argv, u8 *argc)
{
	char *ptemp = NULL;
	u8 argnum = 0;
	
	if(pcmd == NULL || cmdlen == 0)
	{
		return -1;
	}
	
	ptemp = pcmd;

	while((*ptemp == ' ')&&(ptemp))
	{
		ptemp++;
	}

	argv[argnum++] = ptemp;
	
	ptemp = strstr(pcmd, " ");

	while(ptemp != NULL)
	{
		ptemp++;
		*(ptemp-1) = '\0';
		/*lint -save -e779*/
		while(( " " ==ptemp)&&(ptemp))
		{
			ptemp++;
		}
		/*lint -restore*/
		argv[argnum++] = ptemp;
		ptemp = strstr(ptemp, " ");
	}

	*argc = argnum;
	
	return 0;
	
}

#define CMD_CHECK_0	0	/*正确的命令*/
#define INCOMPLET_CMD	1	/*不完整的命令*/
#define UNKOWN_CMD		2	/*未知命令*/
#define UNCONFIRM_CMD	3	/*不确定命令*/

/**************************************************************************************************
*cmd_cmdstr_check --命令行参数检查
*Input:
*	argv	--解析出来的参数变量
*	argc	--解析出来的参数数量
*Output:
*	pcmdelement	--如果参数检查正确，输出对应的命令数据结构的指针
*Return:
*	CMD_CHECK_0
*	INCOMPLET_CMD
*	UNKOWN_CMD
*	UNCONFIRM_CMD
*/
/*lint -save -e818*/
static int cmd_cmdstr_check(char **argv, u8 argc, u32 *pcmdelement)
{
	u8 	i = 0,  cmdnum = 0, samecmd = 0;
	char 	*arg[CMD_PARAM_NUM_MAX] = {NULL};
	PS_CLI_CMD  pcmd = NULL;
	char buf[CMD_LINE_LEN_MAX];
	
	if(argc >= CMD_PARAM_NUM_MAX)
	{
		return UNKOWN_CMD;
	}
	memset(buf,0,sizeof(buf));
	for(i=0; i<CMD_MAX_NUM; i++)
	{
		if(g_cli_cmd_list.cmd[i]!=0)
		{	
			pcmd = (PS_CLI_CMD)g_cli_cmd_list.cmd[i];

			if(strncmp(argv[0], pcmd->cmd, strlen(argv[0])) != 0)
			{
				continue;
			}
			*pcmdelement = g_cli_cmd_list.cmd[i];
			
			samecmd++;
		}
	}
	if(samecmd == 0)
	{
		return UNKOWN_CMD;
	}
	if(samecmd > 1)
	{
		return UNCONFIRM_CMD;
	}

	pcmd = (PS_CLI_CMD)(*pcmdelement);

	strncpy(buf, pcmd->cmd, strlen(pcmd->cmd));
	(void)cmd_cmdline_parse(buf, strlen(buf), arg, &cmdnum);

	if(argc < cmdnum)
	{
		return INCOMPLET_CMD;
	}

/*	if(argc > cmdnum)
	{
		return UNKOWN_CMD;
	}
*/
		
   return 0;
	
}
/*lint -restore*/

/******************************************************************************
*cmd_run	--运行命令函数
*Input:	
*	None
*Output:
*	None
*Return:
*	None
*/
static void cmd_run(void)
{
	u8 	argc = 0;
	char 	*arg[CMD_PARAM_NUM_MAX] = {NULL};
	PS_CLI_CMD pcmd = NULL;
	u32 cmdelement = 0;
	int ret = 0;

	(void)cmd_out(NEWLINE);
	
	if( 0 == g_cmd_info.cmdLineLen)
	{
		(void)cmd_out("%s", CMD_PROMPT);
		return;
	}

	memset(g_cmd_last_cmd, 0, sizeof(g_cmd_last_cmd));
	strncpy(g_cmd_last_cmd, g_cmd_info.cmdLine, g_cmd_info.cmdLineLen);

	if( 0 != cmd_cmdline_parse(g_cmd_info.cmdLine, g_cmd_info.cmdLineLen, arg, &argc) )
	{
		(void)cmd_out(NEWLINE);
		(void)cmd_out("%%\"%s\" unknown commond"NEWLINE, g_cmd_last_cmd);
		/*szb add*/
		(void)cmd_out("%s",CMD_PROMPT);
		return;
	}

	ret = cmd_cmdstr_check(arg, argc, &cmdelement);

	if(ret == CMD_CHECK_0)
	{
		pcmd = (PS_CLI_CMD)cmdelement;
		if(pcmd->func(argc,arg) != 0)
		{
			(void)cmd_out("%%\"%s\" unknown commond"NEWLINE, g_cmd_last_cmd);
		}
	}
	else
	{
		switch(ret)
		{
			case INCOMPLET_CMD:
				(void)cmd_out("%% \"%s\" incomplete command"NEWLINE,arg[0]);
				break;
			case UNKOWN_CMD:
				(void)cmd_out("%% \"%s\" unknown command"NEWLINE,arg[0]);
				break;
			case UNCONFIRM_CMD:
				(void)cmd_out("%% \"%s\" unconfirm command"NEWLINE,arg[0]);
				break;
			default:
				break;
		}
	}
/*szb add*/
	(void)cmd_out("%s",CMD_PROMPT);
}

/*****************************************************************************
*cmd_rcv		--命令字符串接收函数	
*
*Input:
*	prt		--协议类型，固定为PRTTYPE_CONSOLE，校验用
*	pbuf	--接收到的数据缓冲头指针
*	buflen	--接收到的字符串的长度
*     version 
*Output:
*	None
*Return:
*	0		--正确执行
*	-1	--执行失败
*/
/*lint -save -e818*/
static int cmd_rcv(u8 uartid, void *arg, u8 *pbuf, u16 buflen,u8 version)
{
	u32 i = 0, j = 0;
	u8 curpos = 0;
	static u32 key = 0;

	NO_USE(uartid);
 	NO_USE(arg);
	NO_USE(version);
		
	curpos = g_cmd_info.curentpos;
		
	for(i=0; i<buflen; i++)
	{
		if(pbuf[i] == ESC_KEY)
		{
			continue;
		}
		else
		{
			key = pbuf[i];
		}
	
		switch(key)
		{/*根据需要增减case*/
			case ENTER_KEY:
			
				//if(uart_msg_send_disable(uartid)==FALSE)
				{
					cmd_run();
				}

				curpos = 0;
				memset(&g_cmd_info, 0, sizeof(g_cmd_info));
				break;
				
			case '\t':
				/*cmd_out("%c%c%c", 0x1b,0x5b,0x43);*/
				break;
			
			case BS_KEY:
				if((curpos > 0)&&(curpos == g_cmd_info.cmdLineLen))
				{
					curpos--;	
					g_cmd_info.cmdLineLen--;
					g_cmd_info.cmdLine[curpos] = '\0';
					(void)cmd_out("%c %c", pbuf[i], pbuf[i]);
				}				
				break;
			case ESC_KEY:
				break;

			case RIGHTARROW_KEY:
					
				break;
				
			case LEFTARROW_KEY:
			/*	if(curpos >0)
				{
					curpos--;
					cmd_out("%c", BS_KEY); 
				}*/
				break;
			case DOWNARROW_KEY:
			case UPARROW_KEY:			
				for(j=0; j<g_cmd_info.cmdLineLen; j++)
				{
					(void)cmd_out("%c %c", BS_KEY, BS_KEY);
				}
				g_cmd_info.cmdLineLen = 0;
				memset(g_cmd_info.cmdLine, 0, sizeof(g_cmd_info.cmdLineLen));
				strncpy(g_cmd_info.cmdLine, g_cmd_last_cmd, strlen(g_cmd_last_cmd));
				g_cmd_info.cmdLineLen = strlen(g_cmd_last_cmd);
				g_cmd_info.curentpos = strlen(g_cmd_last_cmd);
				curpos = g_cmd_info.curentpos;
				(void)cmd_out("%s", g_cmd_info.cmdLine);
				
				break;
				
			case DEL_KEY:
			
			default:
				(void)cmd_out("%c", pbuf[i]);				
				if(curpos<(CMD_LINE_LEN_MAX-1))
				{
					g_cmd_info.cmdLine[curpos++] = (char)pbuf[i];
					g_cmd_info.cmdLineLen++;
				}
				break;
		}
	}

	g_cmd_info.curentpos = curpos;
	
	return 0;
}
/*lint -restore*/
 

/************************************************************
*cmd_install --命令行安装命令函数
*
*Input:	
*	待安装的命令行结构
*Output:
*	Noen
*Return:
*	0		--安装成功
*	-1	--安装失败
*/
int cmd_install(CPS_CLI_CMD pcmdelement)
{

	if(pcmdelement == NULL)
	{
		return -1;

	}
	
	if(g_cli_cmd_list.num >= CMD_MAX_NUM)
	{/*位置不够了*/
		return -1;
	}
	if(strlen(pcmdelement->cmd) > CMD_LINE_LEN_MAX)
	{/*命令字符串太长了，不能解析*/
		return -1;
	}

	g_cli_cmd_list.cmd[g_cli_cmd_list.num] = (u32)pcmdelement;
	
	g_cli_cmd_list.num++;
	
	return 0;
}

u8 uart_redirect_cfg[UART_MAX];
DEFCLICMD(uart_redirect_cmd, uart_redirect_struct,
			"redirect uart SRC_ID to uart DST_ID","redirect")
{
	u8 src_id = 0, dst_id = 0;
	NO_USE(argc);
	NO_USE(argv);

	src_id = atoi(argv[2]);
	dst_id = atoi(argv[5]);
	if(src_id&&(src_id <= UART_MAX)&&(dst_id <= UART_MAX)) {
		(void)cmd_out(NEWLINE"redirect uart src %d to uart %d ", src_id, dst_id);
		uart_redirect_cfg[src_id - 1] = dst_id;
		(void)cmd_out(NEWLINE);
	}

	return 0;
}

DEFCLICMD(uart_redirect_show, uart_redirect_show_struct,
			"uart redirect show","show redirect")
{
	u8 id;
	NO_USE(argc);
	NO_USE(argv);

	cmd_out("%8s %8s"NEWLINE, "SrcUart", "DstUart");
	for(id = 0;id < UART_MAX;id++) {
		cmd_out("%7s%d %7s%d"NEWLINE, "Uart", id+1, "Uart", uart_redirect_cfg[id]);
	}

	return 0;
}

extern void cmd_test_install(void);
extern int uart_msg_send(u8 uartid, const char *buf, u32 buflen);
int cmd_init(u8 uartid)
{
	Console_UID=uartid;
	g_msg_msg_send = uart_msg_send;

	//ESC_check_delay_htmr=0;
	
	memset(&g_cli_cmd_list,0,sizeof(g_cli_cmd_list));
	memset(&g_cmd_info, 0, sizeof(g_cmd_info));

	cmd_test_install();
	cmd_install(&uart_redirect_struct);
	cmd_install(&uart_redirect_show_struct);
   //     uart_rs232_init(Console_UID, cmd_rcv);

	cmd_out("%s", BOOT_LOGO_INFO);	
	return 0;
}
