/**
 *******************************************************************************
 * @file  console_cmdline.c
 * @brief This file provides firmware functions to manage the command line.
 @verbatim
   Change Logs:
   Date             Author          Notes
   2022-06-30       CDT             First version
   2023-01-17       CDT             Typo: Initalize -> Initialize, charaters -> characters
 @endverbatim
 *******************************************************************************
 * Copyright (C) 2022-2023, Xiaohua Semiconductor Co., Ltd. All rights reserved.
 *
 * This software component is licensed by XHSC under BSD 3-Clause license
 * (the "License"); You may not use this file except in compliance with the
 * License. You may obtain a copy of the License at:
 *                    opensource.org/licenses/BSD-3-Clause
 *
 *******************************************************************************
 */

/*******************************************************************************
 * Include files
 ******************************************************************************/
#include "console_conf.h"
#include "console_dev.h"
#include "console_cmdline.h"

/**
 * @addtogroup CLI_Console
 * @{
 */

/**
 * @defgroup Console_Command_Line Console Command Line
 * @{
 */

/*******************************************************************************
 * Local type definitions ('typedef')
 ******************************************************************************/

/*******************************************************************************
 * Local pre-processor symbols/macros ('#define')
 ******************************************************************************/

/*******************************************************************************
 * Global variable definitions (declared in header file with 'extern')
 ******************************************************************************/

/*******************************************************************************
 * Local function prototypes ('static')
 ******************************************************************************/
/**
 * @defgroup Console_Command_Line_Local_Functions
 * @{
 */
static void CONSOLE_InitCmdLineBuf(stc_console_cmd_buf_t *pstcCmdBuf, char *pcData, uint32_t u32Size);
static void CONSOLE_ResetCmdLineBuf(stc_console_cmd_buf_t *pstcCmdBuf);
static void CONSOLE_WriteCmdLineBuf(stc_console_cmd_buf_t *pstcCmdBuf, char cData);
/**
 * @}
 */

/*******************************************************************************
 * Local variable definitions ('static')
 ******************************************************************************/

/*******************************************************************************
 * Function implementation - global ('extern') and local ('static')
 ******************************************************************************/
/**
 * @defgroup Console_Command_Line_Local_Functions Console Command Line Local Functions
 * @{
 */

/**
 * @brief  Initialize buffer.
 * @param  [in] pstcLineBuf         Pointer to a @ref stc_console_cmd_buf_t structure
 * @param  [in] pcData              Pointer to buffer
 * @param  [in] u16Size             Buffer size
 * @retval None
 */
void CONSOLE_InitCmdLineBuf(stc_console_cmd_buf_t *pstcCmdBuf, char *pcData, uint32_t u32Size)
{
    pstcCmdBuf->pcData = pcData;
    pstcCmdBuf->u32Size = u32Size;
    pstcCmdBuf->u32Count = 0UL;
}

/**
 * @brief  Reset buffer.
 * @param  [in] pstcLineBuf         Pointer to a @ref stc_console_cmd_buf_t structure
 * @retval None
 */
void CONSOLE_ResetCmdLineBuf(stc_console_cmd_buf_t *pstcCmdBuf)
{
    pstcCmdBuf->u32Count = 0UL;
}

/**
 * @brief  Write character to buffer.
 * @param  [in] pstcLineBuf         Pointer to a @ref stc_console_cmd_buf_t structure
 * @param  [in] cData               Character to write.
 * @retval None
 */
void CONSOLE_WriteCmdLineBuf(stc_console_cmd_buf_t *pstcCmdBuf, char cData)
{
    if (pstcCmdBuf->u32Count < pstcCmdBuf->u32Size) {
        pstcCmdBuf->pcData[pstcCmdBuf->u32Count++] = cData;
    }
}

/**
 * @}
 */

/**
 * @defgroup Console_Command_Line_Global_Functions Console Command Line Global Functions
 * @{
 */

/**
 * @brief  Create console command line instance.
 * @param  [in] u32CmdBufSize       Console command line buffer size
 * @retval Pointer of a @ref stc_console_cmd_line_t_t structure
 */
stc_console_cmd_line_t *CONSOLE_CreateCommandLine(uint32_t u32CmdBufSize)
{
    stc_console_cmd_buf_t *pstcCmdBuf;
    stc_console_cmd_line_t *pstcCmdLine = NULL;

    if (u32CmdBufSize > 0UL) {
        pstcCmdLine = (stc_console_cmd_line_t *)malloc(u32CmdBufSize +
                                                       ALIGN_WORD(sizeof(stc_console_cmd_line_t)) +
                                                       ALIGN_WORD(sizeof(stc_console_cmd_buf_t)));
        if (pstcCmdLine != NULL) {
            pstcCmdBuf = (stc_console_cmd_buf_t *)((char *)pstcCmdLine + ALIGN_WORD(sizeof(stc_console_cmd_line_t)));
            CONSOLE_InitCmdLineBuf(pstcCmdBuf, (char *)pstcCmdBuf +
                                   ALIGN_WORD(sizeof(stc_console_cmd_buf_t)), u32CmdBufSize);
            pstcCmdLine->pstcCmdBuf = pstcCmdBuf;
        }
    }

    return pstcCmdLine;
}

/**
 * @brief  Read line characters.
 * @param  [in] pstcCmdLine         Pointer to a @ref stc_console_cmd_line_t_t structure
 * @retval bool:
 *           - true:                Read successfully.
 *           - false:               Read unsuccessfully.
 */
bool CONSOLE_ReadLine(stc_console_cmd_line_t *pstcCmdLine)
{
    int32_t ch;
    bool bRet = false;

    if (pstcCmdLine != NULL) {
        ch = CONSOLE_GetChar();
        if (ch != -1) {
            if (((char)ch == '\n') || ((char)ch == '\r')) {
                CONSOLE_WriteCmdLineBuf(pstcCmdLine->pstcCmdBuf, '\0');
                CONSOLE_ResetCmdLineBuf(pstcCmdLine->pstcCmdBuf);
                (void)printf("\r\n");
                bRet = true;
            } else {
                (void)CONSOLE_OutputChar((char)ch);
                CONSOLE_WriteCmdLineBuf(pstcCmdLine->pstcCmdBuf, (char)ch);
            }
        }
    }

    return bRet;
}

/**
 * @brief  CLI prompt.
 * @param  [in] pstcCLI                 Pointer to a @ref stc_cli_t structure
 * @retval None
 */
void CONSOLE_Prompt(void)
{
    (void)printf(CONSOLE_PROMPT);
}

/**
 * @brief  CLI parse line characters.
 * @param  [in]  pcLine                 Pointer to characters.
 * @param  [out] argv                   Pointer to argument array.
 * @retval Argument count
 */
int32_t CONSOLE_ParseCommandLine(char *pcLine, char *argv[])
{
    int32_t argc = 0;

    while (argc < CONSOLE_CMD_ARGV_MAX) {
        /* skip any white space */
        while ((*pcLine == ' ') || (*pcLine == '\t')) {
            ++pcLine;
        }

        if (*pcLine == '\0') {    /* end of line, no more args */
            argv[argc] = NULL;
            return argc;
        }

        argv[argc++] = pcLine;    /* begin of argument string   */

        /* find end of string */
        while ((*pcLine != '\0') && (*pcLine != ' ') && (*pcLine != '\t')) {
            ++pcLine;
        }

        if (*pcLine == '\0') {    /* end of line, no more args  */
            argv[argc] = NULL;
            return argc;
        }

        *pcLine = '\0';     /* terminate current arg   */
        pcLine++;
    }

    return argc;
}

/**
 * @brief  Get key number.
 * @param  [in] pstcCmdLine         Pointer to a @ref stc_console_cmd_line_t_t structure
 * @retval Key number
 */
int32_t CONSOLE_GetKeyNum(stc_console_cmd_line_t *pstcCmdLine)
{
    char *pcEndPtr;
    int32_t i32Key;

    if (true == CONSOLE_ReadLine(pstcCmdLine)) {
        if ('\0' == *pstcCmdLine->pstcCmdBuf->pcData) {
            i32Key = CONSOLE_CMD_KEY_ENTER;
        } else {
            i32Key = strtol(pstcCmdLine->pstcCmdBuf->pcData, &pcEndPtr, 10);
            if (('\0' != *pcEndPtr) || (i32Key <= CONSOLE_CMD_KEY_ENTER)) {
                i32Key = CONSOLE_CMD_KEY_INVALID;
            }
        }
    } else {
        i32Key = CONSOLE_CMD_KEY_NONE;
    }

    return i32Key;
}

/**
 * @}
 */

/**
 * @}
 */

/**
 * @}
 */

/*******************************************************************************
 * EOF (not truncated)
 ******************************************************************************/
