/** \file
 *  \brief This file implements utility functions used by the command interpreter.
 */

/**
 *  \ingroup CONSOLE
 */

/* Include Files */
#include "KTag.h"

#if (CONFIG__FEATURE_COMM_CONSOLE == CONFIG__FEATURE_ENABLED)

/* Local Definitions and Constants */

/* Public Variables */

/* Private Variables */

/* Private Function Prototypes */

/* Public Functions */

//! Find the start location of the nth parameter in the buffer.
/*!
 *  \note The command itself is parameter 0.
 */
COMM_Console_Parameter_Result_T COMM_Console_FindNthParameter(const char * const buffer, const uint8_t parameterNumber, const char ** parameterLocation)
{
	uint32_t buffer_index = 0;
	uint32_t parameter_index = 0;
	COMM_Console_Parameter_Result_T result = COMM_CONSOLE_PARAMETER_RESULT_SUCCESS;

	while (parameterNumber != parameter_index)
	{
		if (buffer[buffer_index] == COMM_CONSOLE_PARAMETER_DELIMITER)
		{
			parameter_index++;
		}
        else if (buffer[buffer_index] == COMM_CONSOLE_END_OF_MESSAGE)
        {
            result = COMM_CONSOLE_PARAMETER_RESULT_PARAMETER_ERROR;
            break;
        }
        else if (buffer[buffer_index] == COMM_CONSOLE_STRING_TERMINATOR)
        {
            result = COMM_CONSOLE_PARAMETER_RESULT_PARAMETER_ERROR;
            break;
        }
		buffer_index++;
	}
    
    if (result == COMM_CONSOLE_PARAMETER_RESULT_SUCCESS)
	{
		*parameterLocation = &buffer[buffer_index];
	}
    
	return result;
}


COMM_Console_Parameter_Result_T COMM_Console_DecodeParameterUInt8(const char * const buffer, uint8_t * const parameterUInt8)
{
    uint8_t value = 0;
	COMM_Console_Parameter_Result_T result = COMM_CONSOLE_PARAMETER_RESULT_PARAMETER_ERROR;
    
    // Strings containing uint8s range from "0" to "255".  The large number has three characters.
    uint_fast16_t MAX_CHARACTERS = 3;
    uint_fast16_t index = 0;
    
    while (index < (MAX_CHARACTERS + 1))
    {
        if ((buffer[index] >= '0') && (buffer[index] <= '9'))
        {
            value *= 10;
            value += buffer[index] - '0';
            index++;
        }
    	else if ( (buffer[index] == COMM_CONSOLE_PARAMETER_DELIMITER) ||
                  (buffer[index] == COMM_CONSOLE_STRING_TERMINATOR) ||
                  (buffer[index] == COMM_CONSOLE_END_OF_MESSAGE) )
    	{
    		result = COMM_CONSOLE_PARAMETER_RESULT_PARAMETER_END;
            break;
    	}
        else
        {
            result = COMM_CONSOLE_PARAMETER_RESULT_PARAMETER_ERROR;
            break;
        }
    }
    
	if  (result == COMM_CONSOLE_PARAMETER_RESULT_PARAMETER_END)
	{
		result = COMM_CONSOLE_PARAMETER_RESULT_SUCCESS;
        *parameterUInt8 = value;
	}
    
    return result;
}


COMM_Console_Parameter_Result_T COMM_Console_DecodeParameterUInt16(const char * const buffer, uint16_t * const parameterUInt16)
{
    uint16_t value = 0;
	COMM_Console_Parameter_Result_T result = COMM_CONSOLE_PARAMETER_RESULT_PARAMETER_ERROR;
    
    // Strings containing uint16s range from "0" to "65535".  The large number has five characters.
    uint_fast16_t MAX_CHARACTERS = 5;
    uint_fast16_t index = 0;
    
    while (index < (MAX_CHARACTERS + 1))
    {
        if ((buffer[index] >= '0') && (buffer[index] <= '9'))
        {
            value *= 10;
            value += buffer[index] - '0';
            index++;
        }
    	else if ( (buffer[index] == COMM_CONSOLE_PARAMETER_DELIMITER) ||
                  (buffer[index] == COMM_CONSOLE_STRING_TERMINATOR) ||
                  (buffer[index] == COMM_CONSOLE_END_OF_MESSAGE) )
    	{
    		result = COMM_CONSOLE_PARAMETER_RESULT_PARAMETER_END;
            break;
    	}
        else
        {
            result = COMM_CONSOLE_PARAMETER_RESULT_PARAMETER_ERROR;
            break;
        }
    }
    
	if  (result == COMM_CONSOLE_PARAMETER_RESULT_PARAMETER_END)
	{
		result = COMM_CONSOLE_PARAMETER_RESULT_SUCCESS;
        *parameterUInt16 = value;
	}
    
    return result;
}

COMM_Console_Parameter_Result_T COMM_Console_DecodeParameterInt32(const char * const buffer, int32_t * const parameterInt32)
{
    int32_t value = 0;
	COMM_Console_Parameter_Result_T result = COMM_CONSOLE_PARAMETER_RESULT_PARAMETER_ERROR;
    bool is_negative = false;
    
    // Strings containing int32s range from "-2147483648" to "2147483647".  The negative number has eleven characters.
    uint_fast16_t MAX_CHARACTERS = 11;
    uint_fast16_t index = 0;
    
    if (buffer[index] == '-')
    {
        is_negative = true;
        index++;
    }
    
    while (index < (MAX_CHARACTERS + 1))
    {
        if ((buffer[index] >= '0') && (buffer[index] <= '9'))
        {
            value *= 10;
            value += buffer[index] - '0';
            index++;
        }
    	else if ( (buffer[index] == COMM_CONSOLE_PARAMETER_DELIMITER) ||
                  (buffer[index] == COMM_CONSOLE_STRING_TERMINATOR) ||
                  (buffer[index] == COMM_CONSOLE_END_OF_MESSAGE) )
    	{
    		result = COMM_CONSOLE_PARAMETER_RESULT_PARAMETER_END;
            break;
    	}
        else
        {
            result = COMM_CONSOLE_PARAMETER_RESULT_PARAMETER_ERROR;
            break;
        }
    }
    
    if (is_negative == true)
    {
        value *= -1;
    }
    
	if  (result == COMM_CONSOLE_PARAMETER_RESULT_PARAMETER_END)
	{
		result = COMM_CONSOLE_PARAMETER_RESULT_SUCCESS;
        *parameterInt32 = value;
	}
    
    return result;
}

COMM_Console_Parameter_Result_T COMM_Console_DecodeParameterUInt32(const char * const buffer, uint32_t * const parameterUInt32)
{
    uint32_t value = 0;
	COMM_Console_Parameter_Result_T result = COMM_CONSOLE_PARAMETER_RESULT_PARAMETER_ERROR;
    
    // Strings containing uint32s range from "0" to "4294967296".  The large number has ten characters.
    uint_fast16_t MAX_CHARACTERS = 10;
    uint_fast16_t index = 0;
    
    while (index < (MAX_CHARACTERS + 1))
    {
        if ((buffer[index] >= '0') && (buffer[index] <= '9'))
        {
            value *= 10;
            value += buffer[index] - '0';
            index++;
        }
    	else if ( (buffer[index] == COMM_CONSOLE_PARAMETER_DELIMITER) ||
                  (buffer[index] == COMM_CONSOLE_STRING_TERMINATOR) ||
                  (buffer[index] == COMM_CONSOLE_END_OF_MESSAGE) )
    	{
    		result = COMM_CONSOLE_PARAMETER_RESULT_PARAMETER_END;
            break;
    	}
        else
        {
            result = COMM_CONSOLE_PARAMETER_RESULT_PARAMETER_ERROR;
            break;
        }
    }
    
	if  (result == COMM_CONSOLE_PARAMETER_RESULT_PARAMETER_END)
	{
		result = COMM_CONSOLE_PARAMETER_RESULT_SUCCESS;
        *parameterUInt32 = value;
	}
    
    return result;
}

COMM_Console_Parameter_Result_T COMM_Console_DecodeHexParameterUInt64(const char * const buffer, uint64_t * const parameterUInt64)
{
    COMM_Console_Parameter_Result_T result = COMM_CONSOLE_PARAMETER_RESULT_SUCCESS;
    struct _reent context;
    
    context._errno = 0;
    
    *parameterUInt64 = _strtoull_r(&context, buffer, NULL, 16);
    
    if (context._errno != 0)
    {
        result = COMM_CONSOLE_PARAMETER_RESULT_PARAMETER_ERROR;
    }
    
    return result;
}

/* Private Functions */

#endif // (CONFIG__FEATURE_COMM_CONSOLE == CONFIG__FEATURE_ENABLED)
