#include "process_cmd.h"
#include "tz_dk_cmds.h"
#include "tz_dk_errors.h"
#include "shared/Initialize_tl.h"
#include "shared/Finalize_tl.h"
// #include "shared/Open_Secure_Channel.h"
// #include "shared/Send_APDU.h"
// #include "shared/Close_Secure_Channel.h"
#include "dk_attn.h"
#include "dk_scp_common.h"
#include "SCP03lib.h"

#ifdef DK_DEBUG
#include "dk_test.h"
#endif

uint32_t process_cmd(
    tl_dk_ctx_t * ctx,
    uint32_t commandId,
    tciMessage_t * sendmsg,
    tciMessage_t * respmsg
)
{
    uint32_t ret;
    uint8_t flag;
    TTY_LOG("process_cmd for commandid : %x", commandId);
    respmsg->dkheader.header.len  = 0;

    /* Process command message */
    if (CMD_TZ_DK_Open_Secure_Channel < commandId &&
            CMD_TZ_DK_Close_Secure_Channel > commandId) {

        ret = process_scp03_open_session(ctx, sendmsg->payload.scp03_transceive.payload.cmd, &respmsg->payload.scp03_open_session);
        if (!ret && respmsg->payload.scp03_open_session.payload.resp.sw == ISO7816_SW_NO_ERROR) {
            switch (commandId) {
                case CMD_TZ_DK_Create_CA:
                    ret = process_scp03_create_ca(ctx, &sendmsg->payload.scp03_create_ca, &respmsg->payload.scp03_create_ca);
                    break;
                case CMD_TZ_DK_Invoke_Read:
                    ret = process_scp03_invoke_read(ctx, &sendmsg->payload.scp03_invoke_read, &respmsg->payload.scp03_invoke_read);
                    break;
                case CMD_TZ_DK_Write_Invoke_Read:
                    ret = process_scp03_write_invoke_read(ctx, &sendmsg->payload.scp03_write_invoke_read, &respmsg->payload.scp03_write_invoke_read);
                    break;
                case CMD_TZ_DK_Write_Invoke:
                    ret = process_scp03_write_invoke(ctx, &sendmsg->payload.scp03_write_invoke, &respmsg->payload.scp03_write_invoke);
                    break;
                case CMD_TZ_DK_Send_APDU:
                    ret = process_apdu_transceive(ctx, &sendmsg->payload.scp03_transceive, &respmsg->payload.scp03_transceive);
                    break;
                case CMD_TZ_DK_SET_PRIVATE_DATA:
                    ret = process_scp03_set_private_data(ctx, &sendmsg->payload.scp03_set_private_data, &respmsg->payload.scp03_set_private_data);
                    break;
                case CMD_TZ_DK_GET_PRIVATE_DATA:
                    ret = process_scp03_get_private_data(ctx, &sendmsg->payload.scp03_get_private_data, &respmsg->payload.scp03_get_private_data);
                    break;
                default :
                    DK_LOG_ERR("Command unknown");
                    ret = DK_ERROR_NOT_SUPPORTED;
                    break;
            }
            ret |= process_scp03_close_session(ctx, &respmsg->payload.scp03_close_session);
        }
        else if (!ret && respmsg->payload.scp03_open_session.payload.resp.sw != ISO7816_SW_NO_ERROR) {
            ret |= process_scp03_close_session(ctx, &respmsg->payload.scp03_close_session);
        }

        // set response length to avoid exception on application
        switch (commandId) {
            case CMD_TZ_DK_Create_CA:
                respmsg->dkheader.header.len = sizeof(tz_scp03_create_ca_resp_t);
                break;
            case CMD_TZ_DK_Invoke_Read:
                respmsg->dkheader.header.len = sizeof(tz_scp03_invoke_read_resp_t);
                break;
            case CMD_TZ_DK_Write_Invoke_Read:
                respmsg->dkheader.header.len = sizeof(tz_scp03_write_invoke_read_resp_t);
                break;
            case CMD_TZ_DK_Write_Invoke:
                respmsg->dkheader.header.len = sizeof(tz_scp03_write_invoke_resp_t);
                break;
            case CMD_TZ_DK_Send_APDU:
                respmsg->dkheader.header.len = sizeof(tz_scp03_transceive_resp_t);
                break;
            case CMD_TZ_DK_SET_PRIVATE_DATA:
                respmsg->dkheader.header.len = sizeof(tz_scp03_set_private_data_resp_t);
                break;
            case CMD_TZ_DK_GET_PRIVATE_DATA:
                respmsg->dkheader.header.len = sizeof(tz_scp03_get_private_data_resp_t);
                break;
        }
    } else if (CMD_TZ_DK_Open_Non_Secure_Channel < commandId &&
            CMD_TZ_DK_Send_In_Session >= commandId) {

        TTY_LOG("Digitalkey : enter non scp03 block");

        switch (commandId) {
            case CMD_TZ_DK_Open_Select:
                ret = process_non_scp03_open_session(ctx, &respmsg->payload.scp03_open_session);
                respmsg->dkheader.header.len = sizeof(tz_scp03_transceive_resp_t);
                break;
            case CMD_TZ_DK_Send_In_Session:
                ctx->channel.is_open = 1;
                ctx->channel.id = sendmsg->payload.scp03_transceive.payload.cmd.channel_id;
                ret = process_apdu_transceive(ctx, &sendmsg->payload.scp03_transceive, &respmsg->payload.scp03_transceive);
                respmsg->dkheader.header.len = sizeof(tz_scp03_transceive_resp_t);
                break;
            case CMD_TZ_DK_Close:
                ctx->channel.is_open = 1;
                ctx->channel.id = sendmsg->payload.close_secure_channel.payload.cmd.channel_id;
                ret = process_non_scp03_close_session(ctx, &respmsg->payload.scp03_close_session);
                respmsg->dkheader.header.len = sizeof(tz_scp03_transceive_resp_t);
                break;
            case CMD_TZ_DK_Non_Scp_Send_APDU:
                ret = process_non_scp03_open_session(ctx, &respmsg->payload.scp03_open_session);
                TTY_LOG("open session ret %d", ret);
                if (!ret && respmsg->payload.scp03_open_session.payload.resp.sw == ISO7816_SW_NO_ERROR) {
                    ret = process_apdu_transceive(ctx, &sendmsg->payload.scp03_transceive, &respmsg->payload.scp03_transceive);
                    ret |= process_non_scp03_close_session(ctx, &respmsg->payload.scp03_close_session);
                }
                else if (!ret && respmsg->payload.scp03_open_session.payload.resp.sw != ISO7816_SW_NO_ERROR) {
                    ret |= process_non_scp03_close_session(ctx, &respmsg->payload.scp03_close_session);
                }
                respmsg->dkheader.header.len = sizeof(tz_scp03_transceive_resp_t);
                break;
            case CMD_TZ_CRS_SEND_CMD:
                ret = process_crs_open_session(ctx, &respmsg->payload.scp03_open_session);
                if (!ret && respmsg->payload.scp03_open_session.payload.resp.sw == ISO7816_SW_NO_ERROR) {
                    ret = process_apdu_transceive(ctx, &sendmsg->payload.scp03_transceive, &respmsg->payload.scp03_transceive);
                    ret |= process_non_scp03_close_session(ctx, &respmsg->payload.scp03_close_session);
                }
                else if (!ret && respmsg->payload.scp03_open_session.payload.resp.sw != ISO7816_SW_NO_ERROR) {
                    ret |= process_non_scp03_close_session(ctx, &respmsg->payload.scp03_close_session);
                }
                respmsg->dkheader.header.len = sizeof(tz_scp03_transceive_resp_t);
                break;
            default :
                DK_LOG_ERR("Command unknown");
                ret = DK_ERROR_NOT_SUPPORTED;
                break;
        }
    } else {
        switch (commandId) {
            case CMD_TZ_DK_Scp_Credential_Re_Wrap:
                TTY_LOG("scp03 crendential re wrap %d ", sendmsg->payload.scp03_setup_keys.payload.cmd.key_blob_size);
                ret = process_scp03_re_wrap(ctx, &sendmsg->payload.scp03_setup_keys, &respmsg->payload.scp03_setup_keys);
                respmsg->dkheader.header.len = sizeof(tz_scp03_setup_keys_resp_t);
                break;
            case CMD_TZ_DK_Test:
                TTY_LOG("TZ_DIGITALKEY: process_cmd: CMD_TZ_DK_Test:");
                ret = DK_SUCCESS;
                break;
#ifdef DK_DEBUG
            case CMD_TZ_DK_run_tests:
                TTY_LOG("running tests");
                ret = run_all_tests();
                break;
#endif
            default:
                // TODO: return UNKNOW_COMMAND error
                TTY_LOG("Command unknown");
                ret = DK_ERROR_NOT_SUPPORTED;
                break;
        }
    }
  
    TTY_LOG("end ret %d", ret);

    return ret;
}
