/** @brief Interface to simple parser.
 *
 * @copyright 2020 Remsdaq Ltd.
 * @file c4_parser.h
 *
 * @date 20 May 2020
 * @author Dan Smithers <dwhs@remsdaq.com>
 *
 */

#ifndef C4_PARSER_H_
#define C4_PARSER_H_

/*******************************************************************************
 * Includes
 ******************************************************************************/

#include "c4_error_codes.h"
#include "stdint.h"

/*******************************************************************************
 * Defines
 ******************************************************************************/

/** @def CALLISTO_PARSER
 * @brief X-Macro function to construct enumeration, Text string array, description string array and example array.
 *
 * @param[in] Id   Identifier
 * @param[in] Text Config file string.
 * @param[in] Desc Descriptive string.
 * @param[in] Exa  Example string
 */

/** @brief definition of parser keywords. */
#define PARSER_KEYWORDS \
    CALLISTO_PARSER(START,    "Callisto4BootConfig", \
                    "this specifies the file as applying to the Remsdaq Callisto 4 bootloader and contains a version identifier in maj.min form.", \
                    "=0.1") \
    CALLISTO_PARSER(CURRENT,  "CurrentApp",          \
                    "this specifies the address the current application image is stored at in QSPI flash. It also implicitly specifies the location of the configuration file for the current application.\n\tThis appears exactly once.", \
                    "=0x60120000")  \
    CALLISTO_PARSER(RECOVERY, "RecoveryApp",         \
                    "this specifies the address the recovery application image is stored at in QSPI flash. It also implicitly specifies the location of the configuration file for the recovery application.\n\tThis appears zero or one time.", \
                    "=0x601B0000")  \
    CALLISTO_PARSER(UPDATE, "UpdateApp",         \
                    "this specifies the address the update application image is stored at in QSPI flash. It also implicitly specifies the location of the configuration file for the recovery application.\n\tThis appears zero or one time.", \
                    "=0x60230000")  \
    CALLISTO_PARSER(FAULTY,   "FaultyApp",           \
                    "this specifies a location containing a known faulty application.\n\tThis appears zero or more times. Multiple definitions are combined.", \
                    "=0x60230000")  \
    CALLISTO_PARSER(ARGS,     "Args",                \
                    "Optional field for arguments to be passed t all applications.\n\t This may appear zero or more times. Multiple definitions are concatenated.", \
                    "=--colour=CYAN --rate=250\nArgs=--ratio=2")  \
    CALLISTO_PARSER(END,      "EndConfig",           \
                    "This marks the end of the configuration file and is followed by a checksum to verify the integrity of the boot configuration and a terminating Null which enables the file to be parsed as a string.", \
                    "\n0x########\n\\0\n")


/*******************************************************************************
 * Structures
 ******************************************************************************/

/** @brief Enumeration of parser items. */
typedef enum
{
#define CALLISTO_PARSER(Id, Text, Desc, Exa) \
    C4_BOOT_CONFIG_PARSER_##Id,
    PARSER_KEYWORDS
#undef CALLISTO_PARSER
    NUM_PARSE_TERMS
} E_parseIndices_t;

/** @brief file operation type.
 */
typedef enum {
    E_NOOP,    //< @brief Null operation so op can be replaced in parser processing.
    E_REPLACE, //< @brief Replace existing field only if present, otherwise return error.
    E_APPEND,  //< @brief Replace existing field if present, or append new field of this name.
    E_EXTEND,  //< @brief Extend existing field if present or append new field of this name.
    E_REMOVE   //< @brief Remove existing field if present with specified value.
} file_op_t;

/*******************************************************************************
 * Prototypes
 ******************************************************************************/

/** @brief Parse the specified memory location.
 *
 * Search from the memory location for the specified field and return the
 * value stored there in pVal
 *
 * @param[in] mem Memory location for start of file.
 * @param[in] mem_len Length of data at location
 * @param[in] field Field identifier
 * @param[out] pVal Pointer to return field value.
 *
 * @return Exit code.
 * @retval ERR_OK Success.
 * @retval ERR_FILE_NOT_FOUND Memory file not found.
 * @retval ERR_FIELD_NOT_FOUND Memory field not found.
 * @retval ERR_SYNTAX Memory file does not parse.
 */
exit_code_t GetConfig(const char *mem, uint32_t mem_len, E_parseIndices_t field, char *pVal);

/** @brief Set value in the specified memory location.
 *
 * Search from the memory location for the specified field and return the
 *
 * @param[in] mem Memory location for start of file.
 * @param[in] mem_len Length of data at location
 * @param[in] field Field identifying string
 * @param[in] val New field value.
 * @param[in] op Flag to denote whether the value should be replaced only, used to extend existing field, or appended if not found
 *
 * @return Exit code.
 * @retval ERR_OK Success.
 * @retval ERR_FILE_NOT_FOUND Memory file not found.
 * @retval ERR_FIELD_NOT_FOUND Memory field not found.
 * @retval ERR_NOT_IMPLEMENTED Operation not implemented.
 * @retval ERR_SYNTAX Memory file does not parse.
 */
exit_code_t SetConfig(const char *mem, uint32_t mem_len, E_parseIndices_t field, const char *val, file_op_t op);

/*******************************************************************************
 * Variables
 ******************************************************************************/

/** @brief Array of strings to use in parser. */
extern const char C4_parseStrings[NUM_PARSE_TERMS+1][32];

#endif /* C4_PARSER_H_ */
