#include "cli.h"

extern void *cli_cmd$$Base;
extern void *cli_cmd$$Limit;

void cli_write(cli_t *p_cli)
{
	for (int i = 0; i < p_cli->chartemplen; i++)
		p_cli->char_put(p_cli->tempbuf[i]);
}

int ringbufcmp(unsigned char *ringbuf, unsigned char ringbufis, const char *cr, int len)
{
	unsigned char i = ringbufis;
	for (int j = 0; j < len; j++)
	{
		if (ringbuf[i] != cr[j])
			return 1;
		i++;
	}
	return 0;
}

/**
 * @brief CLI colors for @ref nrf_cli_fprintf function.
 */
#define NRF_CLI_DEFAULT NRF_CLI_VT100_COLOR_DEFAULT /**< Turn off character attributes. */
#define NRF_CLI_NORMAL NRF_CLI_VT100_COLOR_WHITE	/**< Normal color printf.           */
#define NRF_CLI_INFO NRF_CLI_VT100_COLOR_GREEN		/**< Info color printf.             */
#define NRF_CLI_OPTION NRF_CLI_VT100_COLOR_CYAN		/**< Option color printf.           */
#define NRF_CLI_WARNING NRF_CLI_VT100_COLOR_YELLOW	/**< Warning color printf.          */
#define NRF_CLI_ERROR NRF_CLI_VT100_COLOR_RED		/**< Error color printf.            */
static void vt100_color_set(cli_t *p_cli, nrf_cli_vt100_color_t color)
{
	if (p_cli->col.col == color)
	{
		return;
	}
	p_cli->col.col = color;
	cli_printf(p_cli, "\033[3%dm", color); //设置颜色
}

static void vt100_bgcolor_set(cli_t *p_cli, nrf_cli_vt100_color_t bgcolor)
{
	if (p_cli->col.bgcol == bgcolor)
	{
		return;
	}
	p_cli->col.bgcol = bgcolor;
	cli_printf(p_cli, "\033[4%dm", bgcolor); //设置颜色
}

static inline void vt100_colors_store(cli_t *p_cli,
									  nrf_cli_vt100_colors_t *p_color)
{
	memcpy(p_color, &p_cli->col, sizeof(nrf_cli_vt100_colors_t));
}

static void vt100_colors_restore(cli_t *p_cli,
								 nrf_cli_vt100_colors_t const *p_color)
{
	vt100_color_set(p_cli, p_color->col);
	vt100_bgcolor_set(p_cli, p_color->bgcol);
}

#define print_name cli_fprintf(p_cli, NRF_CLI_VT100_COLOR_GREEN, "\033[1m \r%s", p_cli->p_name)

void Tab_pcs(cli_t *p_cli)
{
	int temp = 0;
	cli_section_cmd_t *stmy;
	if (p_cli->cmdwp == p_cli->cmdrp)
	{
		cli_printf(p_cli, "\n\r\t");
		for (int p = (unsigned int)&cli_cmd$$Base; p < (unsigned int)&cli_cmd$$Limit; p += sizeof(cli_section_cmd_t))
		{
			stmy = ((cli_section_cmd_t *)p);
			cli_fprintf(p_cli, NRF_CLI_VT100_COLOR_CYAN, "%s\t", stmy->_p_cmd_str);
			temp++;
			if (temp % 5 == 0)
				cli_printf(p_cli, "\n\r\t");
		}
		cli_printf(p_cli, "\n");
		print_name;
	}
	else
	{
		for (int p = (unsigned int)&cli_cmd$$Base; p < (unsigned int)&cli_cmd$$Limit; p += sizeof(cli_section_cmd_t))
		{
			stmy = ((cli_section_cmd_t *)p);
			if (ringbufcmp(p_cli->cmdbuf, p_cli->cmdrp, stmy->_p_cmd_str, p_cli->cmdwp - p_cli->cmdrp) == 0)
			{
				for (int i = p_cli->cmdwp - p_cli->cmdrp; i < strlen(stmy->_p_cmd_str); i++)
					p_cli->cmdbuf[p_cli->cmdwp++] = stmy->_p_cmd_str[i];
				cli_printf(p_cli, "\n\r");
				print_name;
				cli_printf(p_cli, "%s", stmy->_p_cmd_str);
				break;
			}
		}
	}
}
void Backspace_pcs(cli_t *p_cli)
{
	if (p_cli->cmdwp != p_cli->cmdrp)
	{
		NRF_CLI_VT100_CMD(p_cli, NRF_CLI_VT100_CLEAREOL); //清除光标后面的内容
		p_cli->cmdwp--;
	}
	else
	{
		cli_printf(p_cli, "\033[1C"); //光标右移动
	}
}
void Delete_pcs(cli_t *p_cli)
{
	
}

#define Historyshowlen 50
void Up_pcs(cli_t *p_cli)
{
	unsigned char showH_p = 0;
	unsigned char fir = 1;
	nrf_cli_vt100_colors_t col;
	if (p_cli->cmdbuf[(unsigned char)(p_cli->historyrp - 1)] != '*')
		return;
	if (p_cli->historyrp != p_cli->cmdwp)
	{
		p_cli->cmdwp = p_cli->cmdrp;
		cli_printf(p_cli, "\r");
		print_name;
		cli_printf(p_cli, "\033[K");
	}
	for (unsigned char i = (unsigned char)p_cli->historyrp - 2; i != (unsigned char)(p_cli->historyrp - Historyshowlen); i--)
	{
		if (p_cli->cmdbuf[i] == '*')
		{
			if (fir)
			{
				for (int j = 0; j < showH_p; j++)
				{
					p_cli->char_put(p_cli->cmdbuf[(unsigned char)(i + j + 1)]);
					p_cli->cmdbuf[p_cli->cmdwp++] = p_cli->cmdbuf[(unsigned char)(i + j + 1)];
				}
				cli_printf(p_cli, "\033[s");
				p_cli->char_put(' ');
				p_cli->historyrp = i + 1;
				fir = 0;
				vt100_colors_store(p_cli, &col);
				vt100_color_set(p_cli, NRF_CLI_VT100_COLOR_CYAN);
				p_cli->char_put('[');
			}
			else
			{
				for (int j = 0; j < showH_p; j++)
					p_cli->char_put(p_cli->cmdbuf[(unsigned char)(i + j + 1)]);
				p_cli->char_put(' ');
			}

			showH_p = 0;
		}
		else
			showH_p++;
		if ((p_cli->cmdbuf[i] == 0) || (i == p_cli->cmdwp))
			break;
	}
	if (fir == 0)
	{
		p_cli->char_put(']');
		vt100_colors_restore(p_cli, &col);
		cli_printf(p_cli, "\033[u");
	}
}

void Down_pcs(cli_t *p_cli)
{
	for (unsigned char j = 0; j < p_cli->cmdwp; j++)
		p_cli->char_put(p_cli->cmdbuf[j]);
}

void Left_pcs(cli_t *p_cli)
{
	cli_printf(p_cli, "\033[1D"); 
}

void Right_pcs(cli_t *p_cli)
{
	cli_printf(p_cli, "\033[1C");
}
#define ARGVCUNMAX 25
char *cmd_argv[ARGVCUNMAX]; //最多存放25个参数的指针

void cmd_pcs(cli_t *p_cli)
{
	cli_section_cmd_t *stmy;
	int stmy_len = 0;
	char sgv_tag = 0;
	unsigned short agvc = 0;
	char argvtrg = 0;
	for (int p = (unsigned int)&cli_cmd$$Base; p < (unsigned int)&cli_cmd$$Limit; p += sizeof(cli_section_cmd_t))
	{
		stmy = ((cli_section_cmd_t *)p);
		stmy_len = strlen(stmy->_p_cmd_str);
		if (
				((unsigned char)stmy_len == (unsigned char)(p_cli->cmdwp - p_cli->cmdrp))||
				(((unsigned char)stmy_len < (unsigned char)(p_cli->cmdwp - p_cli->cmdrp))&&(p_cli->cmdbuf[(unsigned char)(p_cli->cmdrp + stmy_len)] == ' '))
			 )
		{
			if (ringbufcmp(p_cli->cmdbuf, p_cli->cmdrp, stmy->_p_cmd_str, stmy_len) == 0)
			{
				cli_printf(p_cli, "\r\n");
				if ((unsigned char)stmy_len == (unsigned char)(p_cli->cmdwp - p_cli->cmdrp))
				{
					(*(cli_cmd_t *)(&(stmy->_p_cmd_hander)))(p_cli, 0, NULL); //调用没参数的命令
				}
				else 
				{
					agvc = 0;
					p_cli->cmdbuf[p_cli->cmdwp++] = ' ';
					//找出所有参数的指针
					for (unsigned char i = (unsigned char)(p_cli->cmdrp + stmy_len); (unsigned char)i != p_cli->cmdwp; i++)
					{
						switch (sgv_tag)
						{
						case 0:
							if (p_cli->cmdbuf[i] != ' ')
							{
								cmd_argv[agvc++] = (char *)(&(p_cli->cmdbuf[i]));
								sgv_tag++;
							}
							break;
						default:
							if (p_cli->cmdbuf[i] == ' ')
							{
								p_cli->cmdbuf[i] = 0;
								sgv_tag = 0;
							}
							else if ((i == 255) && (p_cli->cmdbuf[0] != ' ')) //参数不连续
							{
								argvtrg = 1;
							}
							break;
						}
					}

					if (argvtrg == 0) //没有出现参数不连续的情况
					{
						//调用命令，带参数					
						(*(cli_cmd_t *)(&(stmy->_p_cmd_hander)))(p_cli, agvc, cmd_argv);
					}
					else
					{
						cli_fprintf(p_cli, NRF_CLI_ERROR, "\tPlase try once again! ");
					}
					if(agvc>0)p_cli->cmdwp = (unsigned char)((unsigned int)(&cmd_argv[agvc - 1][strlen(cmd_argv[agvc - 1])]) - (unsigned int)&p_cli->cmdbuf[0]);
					for (int i = 0; i < agvc; i++)
					{
						cmd_argv[i][strlen(cmd_argv[i])] = ' ';
					}
				}
				cli_printf(p_cli, "\n");
				print_name;		
				p_cli->cmdbuf[p_cli->cmdwp++] = '*';	
				for(unsigned char i=p_cli->cmdwp-1;i>p_cli->cmdrp-1;i--)
				{
					if(p_cli->cmdbuf[i]!= p_cli->cmdbuf[(unsigned char)(i-(p_cli->cmdwp-p_cli->cmdrp))])
					{	
						//添加到运行历史
						p_cli->cmdrp = p_cli->cmdwp;						
						return ;
					}
				}
				p_cli->cmdwp = p_cli->cmdrp;
				return;
			}
		}
	}
	p_cli->cmdbuf[p_cli->cmdwp] = 0;
	cli_fprintf(p_cli, NRF_CLI_ERROR, "\tCan not find cmd [");
	for (unsigned char i = p_cli->cmdrp; i != p_cli->cmdwp; i++)
		p_cli->char_put(p_cli->cmdbuf[i]);
	cli_fprintf(p_cli, NRF_CLI_ERROR, "]\n");
	print_name;
	p_cli->cmdwp = p_cli->cmdrp;
}

void Enter_pcs(cli_t *p_cli)
{
	if (p_cli->cmdwp == p_cli->cmdrp)
	{
		print_name;
	}
	else
	{
		cmd_pcs(p_cli);
	}
	p_cli->historyrp = p_cli->cmdwp;
}

void F4_pcs(cli_t *p_cli)
{
	NRF_CLI_VT100_CMD(p_cli, NRF_CLI_VT100_CURSORHOME);
	NRF_CLI_VT100_CMD(p_cli, NRF_CLI_VT100_CLEARSCREEN);
	print_name;
}
void F5_pcs(cli_t *p_cli)
{
	Up_pcs(p_cli);
	cli_printf(p_cli, "\r\n");
	Enter_pcs(p_cli);
}

void cli_process(cli_t *p_cli)
{
	static unsigned char FN = 0;
	unsigned char key = 0;
	if (p_cli->char_ok())
	{
		key = p_cli->char_get();
		switch (key)
		{
#if 1
		case 0x08: //Backspace
			Backspace_pcs(p_cli);
			break;
		case 0x09: //Tab
			Tab_pcs(p_cli);
			break;

		case 0x0d:
			FN = 20;
			break;
		case 0x0a: //Enter
			if (FN == 20)
			{
				Enter_pcs(p_cli);
				FN = 0;
			}

			break;

		case 0x1B: //Esc
			FN = 1;
			break;

		case 'A':
			if (FN == 1)
			{
				Up_pcs(p_cli);
				FN = 0;
			}
			else
				p_cli->cmdbuf[p_cli->cmdwp++] = key;
			break;
		case 'B':
			if (FN == 1)
			{
				Down_pcs(p_cli);
				FN = 0;
			}
			else
				p_cli->cmdbuf[p_cli->cmdwp++] = key;
			break;
		case 'C':
			if (FN == 1)
			{
				Right_pcs(p_cli);
				FN = 0;
			}
			else
				p_cli->cmdbuf[p_cli->cmdwp++] = key;
			break;
		case 'D':
			if (FN == 1)
			{
				Left_pcs(p_cli);
				FN = 0;
			}
			else
				p_cli->cmdbuf[p_cli->cmdwp++] = key;
			break;
		case 'O': //
			if (FN == 1)
				FN = 2;
			else
				p_cli->cmdbuf[p_cli->cmdwp++] = key;
			break;

		case 'P':
			if (FN == 2)
			{
				FN = 0;
				p_cli->char_put('F');
				p_cli->char_put('1');
			}
			else
				p_cli->cmdbuf[p_cli->cmdwp++] = key;
			break;

		case 'Q':
			if (FN == 2)
			{
				FN = 0;
				p_cli->char_put('F');
				p_cli->char_put('2');
			}
			else
				p_cli->cmdbuf[p_cli->cmdwp++] = key;
			break;

		case 'R':
			if (FN == 2)
			{
				FN = 0;
				p_cli->char_put('F');
				p_cli->char_put('3');
			}
			else
				p_cli->cmdbuf[p_cli->cmdwp++] = key;
			break;

		case 'S':
			if (FN == 2)
			{
				FN = 0;
				F4_pcs(p_cli); //F4按钮
			}
			else
				p_cli->cmdbuf[p_cli->cmdwp++] = key;
			break;

		case '[':
			FN = 1;
			break;
		case '0':
			if (FN == 2)
				FN = 9;
			else
				p_cli->cmdbuf[p_cli->cmdwp++] = key;
			break;
		case '1':
			if (FN == 2)
				FN = 10;
			else if (FN == 1)
				FN = 2;
			else
				p_cli->cmdbuf[p_cli->cmdwp++] = key;
			break;
		case '2':
			if (FN == 1)
				FN = 2;
			else
				p_cli->cmdbuf[p_cli->cmdwp++] = key;
			break;
		case '3':
			if (FN == 2)
				FN = 11;
			else
				p_cli->cmdbuf[p_cli->cmdwp++] = key;
			break;
		case '4':
			if (FN == 2)
				FN = 12;
			else
				p_cli->cmdbuf[p_cli->cmdwp++] = key;
			break;
		case '5':
			if (FN == 2)
			{
				FN = 5;
			}
			else
				p_cli->cmdbuf[p_cli->cmdwp++] = key;
			break;

		case '7':
			if (FN == 2)
			{
				FN = 6;
			}
			else
				p_cli->cmdbuf[p_cli->cmdwp++] = key;
			break;

		case '8':
			if (FN == 2)
			{
				FN = 7;
			}
			else
				p_cli->cmdbuf[p_cli->cmdwp++] = key;
			break;

		case '9':
			if (FN == 2)
			{
				FN = 8;
			}
			else
				p_cli->cmdbuf[p_cli->cmdwp++] = key;
			break;

		case '~':
			switch (FN)
			{
			case 5:
				F5_pcs(p_cli);
				break;
			case 6:
				p_cli->char_put('F');
				p_cli->char_put('6');
				FN = 0;
				break;
			case 7:
				p_cli->char_put('F');
				p_cli->char_put('7');
				FN = 0;
				break;
			case 8:
				p_cli->char_put('F');
				p_cli->char_put('8');
				FN = 0;
				break;
			case 9:
				p_cli->char_put('F');
				p_cli->char_put('9');
				FN = 0;
				break;
			case 10:
				p_cli->char_put('F');
				p_cli->char_put('1');
				p_cli->char_put('0');
				FN = 0;
				break;
			case 11:
				p_cli->char_put('F');
				p_cli->char_put('1');
				p_cli->char_put('1');
				FN = 0;
				break;
			case 12:
				p_cli->char_put('F');
				p_cli->char_put('1');
				p_cli->char_put('2');
				FN = 0;
				break;
			default:
				SEGGER_RTT_Write(0, &key, 1);
				break;
			}
			break;

		case 0x7f: //Delete
			Delete_pcs(p_cli);
			break;
#endif
		default:
			p_cli->cmdbuf[p_cli->cmdwp++] = key;
			break;
		}
	}
extern 	void recall_cmd_pcs(cli_t *p_cli);
	recall_cmd_pcs(p_cli);
}

void cli_exe_cmd(cli_t *p_cli,char *cmd)
{
	int len =strlen(cmd);
	if(len>128)return;
	for(unsigned char i= 0;i<len;i++)
	{
		p_cli->cmdbuf[p_cli->cmdwp++]=cmd[i];
	}
	Enter_pcs(p_cli);
}

void clc_pcs(cli_t *p_cli, unsigned short argc, char **argv)
{
	NRF_CLI_VT100_CMD(p_cli, NRF_CLI_VT100_CURSORHOME);
	NRF_CLI_VT100_CMD(p_cli, NRF_CLI_VT100_CLEARSCREEN);
}

CLI_CMD_REGISTER(clc, "clear sereen", clc_pcs);
CLI_CMD_REGISTER(clear, "clear sereen", clc_pcs);

void History_pcs(cli_t *p_cli, unsigned short argc, char **argv)
{
	cli_fprintf(p_cli, NRF_CLI_VT100_COLOR_CYAN, "[1]History");
}
CLI_CMD_REGISTER(history, "Cli cmd history", History_pcs);
void print_param_pcs(cli_t *p_cli, unsigned short argc, char **argv)
{
	for (int i = 0; i < argc; i++)
	{
		cli_fprintf(p_cli, NRF_CLI_VT100_COLOR_CYAN, "%s\r\n", argv[i]);
	}
}
CLI_CMD_REGISTER(print_param, "Cli cmd history", print_param_pcs);

#define RECALL_CMD_LEN_MAX 30
unsigned char recall_cmd_buff[RECALL_CMD_LEN_MAX];
static int recall_cmd_buff_len=0;
static unsigned int recall_cmd_pcs_interval = 0;
static int recall_cmd_times = 0;
static char allcall=0;
void recall_cmd_pcs(cli_t *p_cli)
{
	static unsigned int cun = 0;
	if ((recall_cmd_times > 0)||(allcall))
	{
		if (cun >= recall_cmd_pcs_interval)
		{
			cun = 0;			
			for(int i=0;i<recall_cmd_buff_len;i++)
			{
				p_cli->cmdbuf[p_cli->cmdwp++]=recall_cmd_buff[i];
			}
			cli_fprintf(p_cli, NRF_CLI_VT100_COLOR_CYAN, "recall times %d ...\r\n",recall_cmd_times);
			Enter_pcs(p_cli);
			if(!allcall)recall_cmd_times--;
		}
		cun++;
	}
}
void recall_pcs(cli_t *p_cli, unsigned short argc, char **argv)
{
	if (argc == 0)
	{
		recall_cmd_times = 0;
		allcall=0;
		cli_fprintf(p_cli, NRF_CLI_VT100_COLOR_CYAN, "help: recall interval times cmd ...");
	}
	else if (argc >= 3)
	{
		recall_cmd_pcs_interval = atoi(argv[0]);
		recall_cmd_times = atoi(argv[1]);
		if((recall_cmd_times==0)||(recall_cmd_pcs_interval==0))
		{
			if((recall_cmd_times==0)&&(recall_cmd_pcs_interval!=0)&&(argv[1][0]=='*'))
			{
				allcall=1;				
			}
			else
			{
				cli_fprintf(p_cli, NRF_CLI_VT100_COLOR_CYAN, "help: recall interval times cmd ...\r\n");
				cli_fprintf(p_cli, NRF_CLI_VT100_COLOR_CYAN, "interval and times is a number\r\n");
				return ;
			}
		}
		recall_cmd_buff_len=0;
		for (int i = 2; i < argc; i++)
		{
			memcpy(&recall_cmd_buff[recall_cmd_buff_len],argv[i],strlen(argv[i]));
			recall_cmd_buff_len+=strlen(argv[i]);
			recall_cmd_buff[recall_cmd_buff_len++]=' ';
		}
		cli_printf(p_cli, "recall [ ");			
		for(int i=0;i<recall_cmd_buff_len;i++)
		{
			p_cli->char_put(recall_cmd_buff[i]);
		}
		if(allcall){cli_printf(p_cli, " ] interval =%d times= **** success\r\n",recall_cmd_pcs_interval);	
		}else {cli_printf(p_cli, " ] interval =%d times= %d success\r\n",recall_cmd_pcs_interval,recall_cmd_times);	
		}SEGGER_RTT_Write(0,recall_cmd_buff,recall_cmd_buff_len);
	}
	else
	{
		cli_printf(p_cli, "recall_pcs -> param err");
	}
}
CLI_CMD_REGISTER(recall, "Cli cmd history", recall_pcs);

char rttok(void)
{
	if (SEGGER_RTT_HasKey())
		return 1;
	return 0;
}
unsigned char rttget(void)
{
	unsigned char buf[60];
	SEGGER_RTT_Read(0, buf, 60);
	return buf[0];
}
void rttput(unsigned char p)
{
	unsigned char buf[60];
	buf[0] = p;
	SEGGER_RTT_Write(0, buf, 1);
}

CLI_DEFINE(clirtt, "CLI^$:", rttok, rttget, rttput);

int mai5n(void)
{
	while (1)
		cli_process(&clirtt);
}
