#include "dk_cmd_get_response.h"

DK_Result generate_get_response_cpdu(byte* buf, size_t* buflen) {
    if (!buf) {
        return DK_ERROR_GENERIC;
    }

    buf[APDU_OFFSET_CLA] = SCP03_GET_RESPONSE_CLA;
    buf[APDU_OFFSET_INS] = SCP03_GET_RESPONSE_INS;
    buf[APDU_OFFSET_P1] = SCP03_GET_RESPONSE_P1;
    buf[APDU_OFFSET_P2] = SCP03_GET_RESPONSE_P2;
    // Lc is absent
    buf[APDU_OFFSET_LC] = SCP03_GET_RESPONSE_LE;

    // TODO this might cause error; Samsung internal structure does not omit fields
    *buflen = 5;
    
    return DK_SUCCESS;
}

DK_Result handle_get_response_response(secEse_7816_rpdu_t* rpdu, byte* response_data, size_t* response_data_len) {
    if (*response_data_len + rpdu->len > MAX_FULL_RESPONSE_SIZE) {
        DK_LOG_ERR("handle_get_response_response(): max val reached");
        return DK_ERROR_GENERIC;
    }

    dk_memcpy(response_data + *response_data_len, rpdu->pdata, rpdu->len);
    *response_data_len += rpdu->len;

    return DK_SUCCESS;
}

DK_Result handle_fragmented_response(secEse_7816_rpdu_t *rpdu, byte* response_data, size_t* response_data_len, channel_t* channel) {
    DK_Result rc;

    byte get_response_buf[MAX_BUFFER_SIZE] = {0};
    size_t get_response_buflen = 0;

    int next_len = 0;
    uint8_t done = FALSE;

    *response_data_len = 0;

    rc  = generate_get_response_cpdu(get_response_buf, &get_response_buflen);
    if (rc) {
        DK_LOG_ERR("error handle_fragmented_response()");
        return rc;
    }

    rc = handle_get_response_response(rpdu, response_data, response_data_len);
    if (rc) {
        return rc;
    }

    while (!done) {
        if (get_sw(rpdu) == ISO7816_SW_CMD_SUCCESSFULLY_EXECUTED_THERE_IS_REMINDER) {
            rc = transmit(get_response_buf, get_response_buflen, rpdu, channel);

            if ((next_len & LAST_BYTE_MASK) != 0 && (rpdu->len) != (next_len & LAST_BYTE_MASK)) {
                DK_LOG_ERR("error on command()");
                rc = DK_ERROR_GENERIC;
                goto catch_error;
            }

            rc = handle_get_response_response(rpdu, response_data, response_data_len);
            if (rc) {
                return rc;
            }

            next_len = rpdu->sw2;
        }
        else {
            if (get_sw(rpdu) == ISO7816_SW_NO_ERROR) {
                if ((*response_data_len + APDU_SW_SIZE) > MAX_FULL_RESPONSE_SIZE) {
                    DK_LOG_ERR("error, max val reached");
                    return DK_ERROR_GENERIC;
                }
                response_data[*response_data_len] = rpdu->sw1;
                response_data[*response_data_len + 1] = rpdu->sw2;
                *response_data_len += APDU_SW_SIZE;

                rc = DK_SUCCESS;
            }
            else {
                rc = DK_ERROR_GENERIC;
            }

            done = TRUE;
        }
    }

catch_error:
    return rc;
}

