
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "command.h"
#include "symbol.h"

#define COMMAND_TABLE_SIZE		20

UINT32	DefaultUserSymbolNum = 0;
UserSymbolStruct UserSymbolTable[MAX_USER_SYMBOL_SIZE];
INT8 DefaultStrDelimit[] = {' ', 0x0A, 0x0D, '\0'}; 

CommandTableStruct_T fLib_CmdTable[COMMAND_TABLE_SIZE+1] =
{
	{{"help", "?", "h"}, "help [command]\n",
		0, 0, 1, 0, 0, 0, 
		HelpCmd, 0, 0,
		{
			{IS_STR, NULL, 0, FALSE, "command - Give help for specified command.\n"},
		},
	},
	{{NULL},
	},
};

UINT32 fLib_InsertCommand(CommandTableStruct_T CmdTable[])
{
	UINT32	i;
	UINT32	Ucmd_index = 0;
	
  for(i = 1; i < COMMAND_TABLE_SIZE; i++)
	{
    fLib_CmdTable[i].Name[0] = NULL;
	}	
	

	for(i = 0; i <= COMMAND_TABLE_SIZE; i++)
	{			
  	if(CmdTable[Ucmd_index].Name[0] == NULL)
			return TRUE;
		
    if(fLib_CmdTable[i].Name[0] == NULL)
		{
			memcpy(&fLib_CmdTable[i], &CmdTable[Ucmd_index], sizeof(CommandTableStruct_T));
			Ucmd_index++;
		}
	}  

	return FALSE;
}

void fLib_InitUserSymbol(UserSymbolStruct symbol[])
{
	UINT32	i;

	for(i = 0; i < MAX_USER_SYMBOL_SIZE; i++)
		UserSymbolTable[i].IsFree = TRUE;
		
	if(symbol != NULL)
	{
		i = 0;
		while(strlen(symbol[i].SymName) > 0)
		{
			NewUserSymbol(symbol[i].SymName);
			WriteUserSymbol(i, symbol[i].SymValue);
			DefaultUserSymbolNum++;
			i++;
		}
	}
}

UINT32 fLib_ExecuteCommand(INT8 *CommandStr)
{
	UINT32	CommandNum, CmdIndex, CmdResult, i;
	INT8	*CmdList[MAX_COMMAND_NUM], DupCommandStr[MAX_COMMAND_NUM], *cmd, TempStr[MAX_COMMAND_LEN + 3];

	if(CommandStr[0] == 0)
		return FALSE;
		
	CommandNum = 0;
	strcpy(DupCommandStr, CommandStr);
	cmd = strtok(DupCommandStr, ";");
	do
	{
		if(strlen(cmd) > 0)
		{
			CmdList[CommandNum] = cmd;
			CommandNum++;
		}
	}while((cmd = strtok(NULL, ";")) != NULL);

	for(i = 0; i < CommandNum; i++)
	{
		printf("<command>: %s\n", CmdList[i]);
		
		strcpy(TempStr ,CmdList[i]);
		
		if((CmdIndex = ParseCommand(TempStr, fLib_CmdTable)) == -1)
		{
			printf("<Unrecognised command>: %s\n", TempStr);
			break;
		}
		FreeCmdArgumentOption(CmdIndex, fLib_CmdTable);

		if(!ParseCommandParameter(TempStr, CmdIndex, fLib_CmdTable))
		{
			printf(fLib_CmdTable[CmdIndex].HelpStr);
			break;
		}

		CmdResult = fLib_CmdTable[CmdIndex].pf(&fLib_CmdTable[CmdIndex]);

		switch(CmdResult)
		{
			case WHILE_COMMAND:
				i = -1;
				break;
			case NEED_HELP_COMMAND:
				printf(fLib_CmdTable[CmdIndex].HelpStr);
				return FALSE;
			case IF_ERROR_COMMAND:
				return TRUE;
			case ERROR_COMMAND:
				return FALSE;
			case OK_COMMAND:  
			default:
			    return CmdResult;  
				break;
		}
#if 1	
		if(IsCommandBreak())
		{
			printf("User break!!!!!\n");
			break;
		}
#endif		
	}

	return TRUE;

}

UINT32 ParseCommand(INT8 *cmd, CommandTableStruct_T CmdTable[])
{
	INT8	*str, TempStr[MAX_COMMAND_LEN];
	UINT32	i, j;
	UINT32	SymbolIndex;
	
	strcpy(TempStr, cmd);
	str = strtok(TempStr, " ;\0");

	i = 0;
	while(CmdTable[i].Name[0] != NULL)
	{
		j = 0;
		do
		{
			if(!strcmp(str, CmdTable[i].Name[j]))
			{
				return i;
			}
			j++;
		}while((CmdTable[i].Name[j] != NULL) && (j < COMMAND_NAME_COUNT));
		i++;
	}

	if(ParameterIsUserSymbol(str, &SymbolIndex, NULL))
	{
		CmdTable[USER_SYMBOL_COMMAND].Key = SymbolIndex;
		return USER_SYMBOL_COMMAND;
	}
	
	return -1;
}


BOOL IsCommandBreak(void)
{
	INT8 ch = 0; 

	if (ch == ESC)
		return TRUE;

	return FALSE;
}

UINT32 NewUserSymbol(INT8 *str)
{
	UINT32	i;

	for(i = 0; i < MAX_USER_SYMBOL_SIZE; i++)
	{
		if(UserSymbolTable[i].IsFree == TRUE)
		{
			strcpy(UserSymbolTable[i].SymName, str);
			UserSymbolTable[i].SymValue = 0;
			UserSymbolTable[i].IsFree = FALSE;
			return TRUE;
		}
		
	}
	return FALSE;
}

void WriteUserSymbol(UINT32 SymIndex, UINT32 NewValue)
{
	if(SymIndex >= MAX_USER_SYMBOL_SIZE)
		return;
	if(UserSymbolTable[SymIndex].IsFree == TRUE)
		return;

	UserSymbolTable[SymIndex].SymValue = NewValue;
}

UINT32 ParameterIsUserSymbol(INT8 *str, UINT32 *SymIndex, UINT32 *SymValue)
{
	UINT32	i;

	for(i = 0; i < MAX_USER_SYMBOL_SIZE; i++)
	{
		if(UserSymbolTable[i].IsFree == FALSE)
		{
			if(!strcmp(str, UserSymbolTable[i].SymName))
			{
				if(SymIndex != NULL)
					*SymIndex = i;
				if(SymValue != NULL)
					*SymValue = UserSymbolTable[i].SymValue;
				return TRUE;
			}
		}
	}

	return FALSE;
}

UINT32 ParameterIsLogicalOperation(INT8 *str, UINT32 *ul)
{
	if(str == NULL)
		return FALSE;

	if(!strcmp(str, ">"))
	{
		if(ul != NULL)
			*ul = IS_HIGHER;
		return TRUE;
	}
	else if(!strcmp(str, ">="))
	{
		if(ul != NULL)
			*ul = IS_HIGHER_SAME;
		return TRUE;
	}
	else if(!strcmp(str, "=="))
	{
		if(ul != NULL)
			*ul = IS_EQUAL;
		return TRUE;
	}
	else if(!strcmp(str, "<="))
	{
		if(ul != NULL)
			*ul = IS_LOWER_SAME;
		return TRUE;
	}
	else if(!strcmp(str, "<"))
	{
		if(ul != NULL)
			*ul = IS_LOWER;
		return TRUE;
	}
	else if(!strcmp(str, "!="))
	{
		if(ul != NULL)
			*ul = IS_NOT_EQUAL;
		return TRUE;
	}
	return FALSE;
}

UINT32 ParameterIsArithmeticOperation(INT8 *str, UINT32 *ul)
{
	if(str == NULL)
		return FALSE;

	if(!strcmp(str, "="))
	{
		if(ul != NULL)
			*ul = EQUAL_CMD;
		return TRUE;
	}
	else if(!strcmp(str, "+="))
	{
		if(ul != NULL)
			*ul = ADD_CMD;
		return TRUE;
	}
	else if(!strcmp(str, "-="))
	{
		if(ul != NULL)
			*ul = SUB_CMD;
		return TRUE;
	}
	else if(!strcmp(str, "*="))
	{
		if(ul != NULL)
			*ul = MUL_CMD;
		return TRUE;
	}
	else if(!strcmp(str, "/="))
	{
		if(ul != NULL)
			*ul = DIV_CMD;
		return TRUE;
	}
	else if(!strcmp(str, "%="))
	{
		if(ul != NULL)
			*ul = MOD_CMD;
		return TRUE;
	}
	return FALSE;
}

BOOL IsDigit(INT8 ch)
{
	if((ch >= '0') && (ch <= '9'))
		return TRUE;
	return FALSE;
}

BOOL IsXDigit(INT8 ch)
{
	if((ch >= '0') && (ch <= '9'))
		return TRUE;
	if((ch >= 'A') && (ch <= 'F'))
		return TRUE;
	if((ch >= 'a') && (ch <= 'f'))
		return TRUE;
	return FALSE;
}

UINT32 ParameterIsConstant(INT8 *str, UINT32 *ul)
{	
	UINT32	i;

	if(str == NULL)
		return FALSE;

	if(!strncmp(str, "0x", 2))
	{
		for(i = 2; str[i] != '\0'; i++)
		{
			if(!IsXDigit(str[i]))
				return FALSE;
		}
		if(ul != NULL)
			*ul = strtoul(str+2, NULL, 16);
	}
	else
	{
		for(i = 0; str[i] != '\0'; i++)
		{
			if(!IsDigit(str[i]))
				return FALSE;
		}
		if(ul != NULL)
			*ul = strtoul(str, NULL, 10);
	}

	return TRUE;
}

UINT32 ParameterIsMemory(INT8 *str, UINT32 *MemValue)
{
	INT8	ptr[MAX_COMMAND_LEN], *addr_ptr;
	UINT32	addr;

	strcpy(ptr, str);

	if(ptr[strlen(ptr) - 1] != ')')
		return FALSE;

	ptr[strlen(ptr) - 1] = '\0';
	addr_ptr = ptr + 3;

	if(!ParameterIsUserSymbol(addr_ptr, NULL, &addr))
		if(!ParameterIsConstant(addr_ptr, &addr))
			return FALSE;

	if(!strncmp(ptr, "mw(", 3))
	{
		*MemValue = (UINT32)(*((UINT32 *)addr));
		return TRUE;
	}
	else if(!strncmp(ptr, "mh(", 3))
	{
		*MemValue = (UINT32)(*((UINT16 *)addr));
		return TRUE;
	}
	else if(!strncmp(ptr, "mb(", 3))
	{
		*MemValue = (UINT32)(*((UINT8 *)addr));
		return TRUE;
	}
	return FALSE;
}	

UINT32 ParameterToNumber(INT8 *para, UINT32 para_type, UINT32 *value)
{
	if(para_type & IS_NUM)
	{
		if(ParameterIsConstant(para, value))
			return TRUE;
	}

	if(para_type & IS_MEM)
	{
		if(ParameterIsMemory(para, value))
			return TRUE;
	}

	if(para_type & IS_USER_SYMBOL)
	{
		if(ParameterIsUserSymbol(para, NULL, value))
			return TRUE;
	}

	return FALSE;
}

UINT32 ParseCommandParameter(INT8 *cmd, UINT32 index, CommandTableStruct_T CmdTable[])
{
	INT8 *CmdName, *token, *token1;
	UINT32 OptionIndex, SubOptionIndex;

	CmdName = strtok(cmd, DefaultStrDelimit);

	while((token = strtok(NULL, DefaultStrDelimit)) != NULL)
	{
		if((OptionIndex = FindOption(index, token, CmdTable)) != -1)
		{
			if(CmdTable[index].Opt[OptionIndex].Type != IS_NULL)
			{
				if((token1 = strtok(NULL, DefaultStrDelimit)) == NULL)
					return FALSE;
				CmdTable[index].Opt[OptionIndex].Str = token1;
				if((CmdTable[index].Opt[OptionIndex].Type & (IS_NUM | IS_REG | IS_MEM)) != 0)
				{
					if(!ParameterToNumber(token1, CmdTable[index].Opt[OptionIndex].Type, &CmdTable[index].Opt[OptionIndex].Value))
						return FALSE;
				}
				else if((CmdTable[index].Opt[OptionIndex].Type & IS_STR_WITH_OPTION) == IS_STR_WITH_OPTION)
				{
					if((SubOptionIndex = FineSubOption(token1, CmdTable[index].Opt[OptionIndex].SubName)) == -1)
						return FALSE;
					CmdTable[index].Opt[OptionIndex].Value = SubOptionIndex;
	 			}
			}
			else
			{
				CmdTable[index].Opt[OptionIndex].Value = TRUE;
			}

			CmdTable[index].Opt[OptionIndex].IsSet = TRUE;
			CmdTable[index].OptCount++;
		}
		else
		{
			if(!SaveArgument(index, token, CmdTable))
				return FALSE;
		}
	}

	if(CmdTable[index].ArguCount < CmdTable[index].ArguMinCount)
		return FALSE;

	if(CmdTable[index].OptCount < CmdTable[index].OptMinCount)
		return FALSE;

	return TRUE;
}

UINT32 SaveArgument(UINT32 index, INT8 *ArgumentStr, CommandTableStruct_T CmdTable[])
{
	UINT32 i;

	if(CmdTable[index].ArguCount >= CmdTable[index].ArguMaxCount)
		return FALSE;

	i = CmdTable[index].ArguCount;
	CmdTable[index].Argu[i].Str = ArgumentStr;
	if(CmdTable[index].Argu[i].Type == IS_ARITHMETIC_OP_STR)
	{
		if(!ParameterIsArithmeticOperation(CmdTable[index].Argu[i].Str, &CmdTable[index].Argu[i].Value))
			return FALSE;
	}
	else if(CmdTable[index].Argu[i].Type == IS_LOGICAL_OP_STR)
	{
		if(!ParameterIsLogicalOperation(CmdTable[index].Argu[i].Str, &CmdTable[index].Argu[i].Value))
			return FALSE;
	}
	else if((CmdTable[index].Argu[i].Type & (IS_NUM | IS_REG | IS_MEM)) != 0)
	{
		if(!ParameterToNumber(CmdTable[index].Argu[i].Str, CmdTable[index].Argu[i].Type, &CmdTable[index].Argu[i].Value))
			return FALSE;
	}
	CmdTable[index].Argu[i].IsSet = TRUE;
	CmdTable[index].ArguCount++;
	return TRUE;
}

UINT32 FindOption(UINT32 index, INT8 *OptionName, CommandTableStruct_T CmdTable[])
{
	UINT32 i;

	for(i = 0; i < CmdTable[index].OptMaxCount; i++)
	{
		if(!strcmp(CmdTable[index].Opt[i].Name, OptionName))
		{
			return i;
		}
	}
	return -1;
}

UINT32 FineSubOption(INT8 *Str, INT8 *SubOption[])
{
	UINT32 i;

	for(i = 0; i < CMD_STR_SUB_OPTION_COUNT; i++)
	{
		if(SubOption[i] == NULL)
			break;

		if(!strcmp(Str, SubOption[i]))
			return i;
	}
	return -1;
}

void FreeCmdArgumentOption(UINT32 index, CommandTableStruct_T CmdTable[])
{
	UINT32 i;

	CmdTable[index].ArguCount = 0;
	for(i = 0; i < CmdTable[index].ArguMaxCount; i++)
	{
		CmdTable[index].Argu[i].Str = NULL;
		CmdTable[index].Argu[i].Value = 0;
		CmdTable[index].Argu[i].IsSet = FALSE;
	}

	CmdTable[index].OptCount = 0;
	for(i = 0; i < CmdTable[index].OptMaxCount; i++)
	{
		CmdTable[index].Opt[i].Str = NULL;
		CmdTable[index].Opt[i].Value = 0;
		CmdTable[index].Opt[i].IsSet = FALSE;
	}
}


UINT32 HelpCmd(CommandTableStruct_T *CmdTable)
{
	UINT32 Index, i;
	CommandTableStruct_T *pCmd;	 
		 
	if(CmdTable->Argu[0].IsSet)
	{
		if((Index = ParseCommand(CmdTable->Argu[0].Str, fLib_CmdTable)) != -1)
		{
			pCmd = &fLib_CmdTable[Index];
			printf(pCmd->HelpStr);
			
			for(i = 0; i < pCmd->ArguMaxCount; i++)
				printf(pCmd->Argu[i].HelpStr);
				
			for(i = 0; i < pCmd->OptMaxCount; i++)
				printf(pCmd->Opt[i].HelpStr);

			return OK_COMMAND;
		}
	}
	else
	{
		i = 0;
		while(fLib_CmdTable[i].Name[0] != NULL)
		{
			printf(fLib_CmdTable[i].HelpStr);
			i++;
		}
		return OK_COMMAND;
	}
	return NEED_HELP_COMMAND;
}

