/**
 * @file api_resp_terminate.c
 *
 * @brief This file contains functions to extract info from telecommand frame
 *
 * The functions provided in the file helps to extract the required information
 * from the tele command frame with crc and encryptions. It also provides the
 * functionalities to unpack buffer and store it in the s_api_resp_frame
 * structure.
 *
 * @copyright Copyright 2023 Antaris, Inc.
 */
/*********************************************************************/
#include "api_resp_common.h"

/**
 * @brief This API extracts and validates the telecommand end of frame.
 *
 * @param[in] frame_ptr     : Telecommand frame pointer
 * @param[in] api_resp_orig       : Structure instance of s_api_resp_frame.
 * @param[in] curr_index    : Current parser index
 * @param[in] len           : Total length of the received data
 *
 * @return Result of API execution status
 * @retval API_REQ_RESP_LIB_OK -> Success / API_REQ_RESP_LIB_EOF_ERROR ->
 *          Error.
 */
static int32_t validate_api_resp_eof(const uint8_t *frame_ptr,
        s_api_resp_frame *api_resp_orig, uint16_t curr_index, uint16_t len);

/**
 * @brief This API stores the start of frame sof from the sof member of passed
 * in s_api_resp_frame type struct to passed in sof and value.
 */
int8_t api_resp_term_extract_sof(s_api_resp_frame *api_resp_term,uint8_t *sof1,
                                                                 uint8_t *sof2)
{
    int8_t status;

    if((NULL != api_resp_term) && (NULL != sof1) && (NULL != sof2))
    {
        *sof1 = api_resp_term->sof1;
        *sof2 = api_resp_term->sof2;
        status = API_REQ_RESP_LIB_OK;
    }
    else
    {
        status = API_REQ_RESP_LIB_NULL_PTR;
    }

    return status;
}

/**
 * @brief This API stores the start of frame (sof) from the sof member of
 * passed in s_api_resp_frame type struct to passed in sof value.
 */
int8_t api_resp_term_extract_api_resp_ctrl(s_api_resp_frame *api_resp_term,
        s_api_resp_ctrl *api_resp_ctrl)
{
    int8_t status;

    if((NULL != api_resp_term) && (NULL != api_resp_ctrl))
    {
        s_api_resp_ctrl_util info;
        info.byte = api_resp_term->api_resp_ctrl;
        api_resp_ctrl->source_dest = info.ctrl.source_dest;
        api_resp_ctrl->sync = info.ctrl.sync;
        status = API_REQ_RESP_LIB_OK;
    }
    else
    {
        status = API_REQ_RESP_LIB_NULL_PTR;
    }

    return status;
}

/**
 * @brief This API stores the api_resp_id of passed in s_api_resp_frame
 *  type struct to passed in api_resp_id value.
 */
int8_t api_resp_term_extract_api_resp_id(s_api_resp_frame *api_resp_term,
        uint8_t *api_resp_id)
{
    int8_t status;

    if((NULL != api_resp_term) && (NULL != api_resp_id))
    {
        *api_resp_id = api_resp_term->api_resp_id;
        status = API_REQ_RESP_LIB_OK;
    }
    else
    {
        status = API_REQ_RESP_LIB_NULL_PTR;
    }

    return status;
}

/**
 * @brief This API stores the api_resp_len of passed in s_api_resp_frame
 *   type struct to passed in api_resp_len value.
 */
int8_t api_resp_term_extract_api_resp_len(s_api_resp_frame *api_resp_term,
        uint16_t *api_resp_len)
{
    int8_t status;

    if((NULL != api_resp_term) && (NULL != api_resp_len))
    {
        *api_resp_len = api_resp_term->api_resp_len;
        status = API_REQ_RESP_LIB_OK;
    }
    else
    {
        status = API_REQ_RESP_LIB_NULL_PTR;
    }

    return status;
}

/**
 * @brief This API stores the end of frame (eof) from the eof member of
 * passed in s_api_resp_frame type struct to passed in eof value.
 */
int8_t api_resp_term_extract_eof(s_api_resp_frame *api_resp_term, uint8_t *eof)
{
    int8_t status;

    if((NULL != api_resp_term) && (NULL != eof))
    {
        *eof = api_resp_term->eof;
        status = API_REQ_RESP_LIB_OK;
    }
    else
    {
        status = API_REQ_RESP_LIB_NULL_PTR;
    }

    return status;
}


/**
 * @brief This API copies the structure data to the input buffer(dst) to the
 *        input structure. It also computes crc and hmac(if enabled) for the
 *         input buffer and compares it with the embedded values.
 */
int32_t api_resp_unpack(const uint8_t *dst, uint16_t len,
        s_api_resp_frame *api_resp_orig)
{
    int32_t size = 0;
    int32_t rslt = -1;
    uint8_t crc_8 = 0;

    if((NULL != dst) && (NULL != api_resp_orig))
    {
        if(API_RESP_MIN_LEN <= len)
        {
            memcpy(&api_resp_orig->sof1, &dst[size],
                                                  sizeof(api_resp_orig->sof1));
            size += sizeof(api_resp_orig->sof1);

            memcpy(&api_resp_orig->sof2, &dst[size],
                                                  sizeof(api_resp_orig->sof2));
            size += sizeof(api_resp_orig->sof2);

            if((API_REQ_RESP_LIB_SOF1 == api_resp_orig->sof1) &&
                    (API_REQ_RESP_LIB_SOF2 == api_resp_orig->sof2))
            {

                memcpy(&api_resp_orig->api_resp_ctrl, &dst[size],
                        sizeof(api_resp_orig->api_resp_ctrl));
                size += sizeof(api_resp_orig->api_resp_ctrl);

                if(api_resp_orig->api_resp_ctrl & API_REQ_RESP_SYNC_BIT)
                {
                    memcpy(&api_resp_orig->time_stamp, &dst[size],
                            sizeof(api_resp_orig->time_stamp));

                    size += sizeof(api_resp_orig->time_stamp);
                }

                memcpy(&api_resp_orig->api_resp_id,&dst[size],
                        sizeof(api_resp_orig->api_resp_id));

                size += sizeof(api_resp_orig->api_resp_id);

                memcpy(&api_resp_orig->api_resp_len,&dst[size],
                        sizeof(api_resp_orig->api_resp_len));

                size += sizeof(api_resp_orig->api_resp_len);

                rslt = validate_api_resp_eof(dst,api_resp_orig, size, len);

                if(API_REQ_RESP_LIB_OK == rslt)
                {

                    memcpy(api_resp_orig->api_resp_data, &dst[size],
                            api_resp_orig->api_resp_len);
                    size += api_resp_orig->api_resp_len;

                    rslt = size;
                    if(rslt > 0)
                    {
                        memcpy(&api_resp_orig->crc_8, &dst[size],
                                sizeof(api_resp_orig->crc_8));
                        api_resp_orig_compute_crc(dst, &crc_8, size);
                        size += sizeof(api_resp_orig->crc_8);

                        memcpy(&api_resp_orig->eof, &dst[size],
                                sizeof(api_resp_orig->eof));
                        size += sizeof(api_resp_orig->eof);

                        rslt = size;

                        if(API_REQ_RESP_LIB_EOF != api_resp_orig->eof)
                        {
                            rslt = API_REQ_RESP_LIB_SOF_EOF_ERROR;
                        }
                        else if(crc_8 != api_resp_orig->crc_8)
                        {
                            rslt = API_REQ_RESP_LIB_CRC_ERROR;
                        }
                        else
                        {
                            rslt = size;
                        }
                    }
                    else
                    {
                        /**
                         *authentication failed for some reason.
                         */
                    }
                }
                else
                {
                    /**
                     * End of frame values not matching with the expected
                     * values.
                     */
                    rslt = API_REQ_RESP_LIB_EOF_ERROR;
                }
            }
            else
            {
                /**
                 * Start of frame values not matching with the expected
                 * values.
                 */
                rslt = API_REQ_RESP_LIB_SOF_EOF_ERROR;
            }
        }
        else
        {
            rslt = API_REQ_RESP_MIN_LEN_ERROR;
        }
    }
    else
    {
        rslt = API_REQ_RESP_LIB_NULL_PTR;
    }

    return rslt;
}

/*
 * @brief This function check the telecommand EOF
 */
static int32_t validate_api_resp_eof(const uint8_t *frame_ptr,
        s_api_resp_frame *api_resp_orig, uint16_t curr_index, uint16_t len)
{
    int rslt = -1;
    uint16_t eof_index;
    uint8_t eof;

    if(curr_index < len)
    {
        eof_index = curr_index + (api_resp_orig->api_resp_len) + 1;

        if(eof_index < len)
        {
            eof = frame_ptr[eof_index];

            if(API_REQ_RESP_LIB_EOF != eof)
            {
                rslt = API_REQ_RESP_LIB_EOF_ERROR;
            }
            else
            {
                rslt = API_REQ_RESP_LIB_OK;
            }
        }
        else
        {
            /*
             * No point in checking EOF as the index is exceeding the total
             * len
             */
            rslt = API_REQ_RESP_LIB_EOF_ERROR;
        }
    }
    else
    {
        /*
         * No point in checking EOF as the index is exceeding the total len
         */
        rslt = API_REQ_RESP_LIB_EOF_ERROR;
    }

    return rslt;
}
