#ifdef DEBUG_LOW
#include "tz_log.h"
#include "sec_apdu.h"
#include "apdu_test.h"
#include "sem.h"
#include "iso7816_self_test.h"
#if defined (OT) && !defined (OTV5)
#include "spi_state.h"
#endif

#ifdef USE_BLOWFISH
#include <tee_internal_api.h>
#include <stdio.h>
#include <string.h>
#endif

uint8_t SCRS_AID[9] = {0xA0, 0x00, 0x00, 0x01, 0x51, 0x43, 0x52, 0x53, 0x00};
uint8_t master_AID[7] = {0xA0, 0x00, 0x00, 0x00, 0x04, 0x10, 0x10};
uint8_t transit_AID[9] = {0xA0, 0x00, 0x00, 0x00, 0x03, 0x86, 0x98, 0x07, 0x01};
//uint8_t default_wallet[10]={0x63, 0x6F, 0x6D, 0x2E, 0x74, 0x65, 0x73, 0x74, 0x2E, 0x73};
uint8_t default_wallet[33]={0x63, 0x6F, 0x6D, 0x2E, 0x73, 0x61, 0x6D, 0x73, 0x75, 0x6E
	                      , 0x67, 0x2E, 0x61, 0x70, 0x70, 0x2E, 0x6E, 0x66, 0x63, 0x74
	                      , 0x6F, 0x6F, 0x6C, 0x2E, 0x65, 0x73, 0x65, 0x74, 0x65, 0x73
	                      , 0x74, 0x65, 0x72};
uint8_t VCM_TLV[18] = {0x4F, 0x10, 0xA0, 0x00, 0x00, 0x00, 0x77, 0x01, 0x00, 0x00, 0x11, 0x01, 0x02, 0x03, 0x04, 0x05, 0x05, 0x09};

void start_use_card(p_secEse_7816_cpdu_t cmd_data) {
    cmd_data->cla = 0x80;
    cmd_data->ins = 0xF0;
    cmd_data->p1 = 0x38;
    cmd_data->p2 = 0x01;
    cmd_data->lc = 0x07;
    cmd_data->le = 0x00;
    cmd_data->le_type = 0x00;
    cmd_data->pdata = master_AID;
    cmd_data->cpdu_type = 0x00;
}
void end_use_card(p_secEse_7816_cpdu_t cmd_data) {
    cmd_data->cla = 0x80;
    cmd_data->ins = 0xF0;
    cmd_data->p1 = 0x38;
    cmd_data->p2 = 0x00;
    cmd_data->lc = 0x07;
    cmd_data->le = 0x00;
    cmd_data->le_type = 0x00;
    cmd_data->pdata = master_AID;
    cmd_data->cpdu_type = 0x00;
}
void set_default_card(p_secEse_7816_cpdu_t cmd_data) {
    cmd_data->cla = 0x80;
    cmd_data->ins = 0xF0;
    cmd_data->p1 = 0x28;
    cmd_data->p2 = 0x01;
    cmd_data->lc = 0x09;
    cmd_data->le = 0x00;
    cmd_data->le_type = 0x00;
    cmd_data->pdata = transit_AID;
    cmd_data->cpdu_type = 0x00;
}
void get_default_card(p_secEse_7816_cpdu_t cmd_data) {
    cmd_data->cla = 0x80;
    cmd_data->ins = 0xF2;
    cmd_data->p1 = 0x28;
    cmd_data->p2 = 0x00;
    cmd_data->lc = 0x21;
    cmd_data->le = 0x00;
    cmd_data->le_type = 0x01;
    cmd_data->pdata = default_wallet;
    cmd_data->cpdu_type = 0x00;
}
void set_default_wallet(p_secEse_7816_cpdu_t cmd_data) {
    cmd_data->cla = 0x80;
    cmd_data->ins = 0xF0;
    cmd_data->p1 = 0x18;
    cmd_data->p2 = 0x00;
    cmd_data->lc = 0x21;
    cmd_data->le = 0x00;
    cmd_data->le_type = 0x00;
    cmd_data->pdata = default_wallet;
    cmd_data->cpdu_type = 0x00;
}
void get_default_wallet(p_secEse_7816_cpdu_t cmd_data) {
    cmd_data->cla = 0x80;
    cmd_data->ins = 0xF2;
    cmd_data->p1 = 0x18;
    cmd_data->p2 = 0x00;
    cmd_data->lc = 0x00;
    cmd_data->le = 0x00;
    cmd_data->le_type = 0x01;
    cmd_data->pdata = NULL;
    cmd_data->cpdu_type = 0x00;
}
void get_wallet_list(p_secEse_7816_cpdu_t cmd_data) {
    cmd_data->cla = 0x80;
    cmd_data->ins = 0xF2;
    cmd_data->p1 = 0x19;
    cmd_data->p2 = 0x01;
    cmd_data->lc = 0x00;
    cmd_data->le = 0x00;
    cmd_data->le_type = 0x01;
    cmd_data->pdata = NULL;
    cmd_data->cpdu_type = 0x00;
}
void set_status_activated(p_secEse_7816_cpdu_t cmd_data) {
    cmd_data->cla = 0x80;
    cmd_data->ins = 0xF0;
    cmd_data->p1 = 0x01;
    cmd_data->p2 = 0x01;
    cmd_data->lc = 0x12;
    cmd_data->le = 0x00;
    cmd_data->le_type = 0x01;
    cmd_data->pdata = VCM_TLV;
    cmd_data->cpdu_type = 0x00;
}
void set_status_deactivated(p_secEse_7816_cpdu_t cmd_data) {
    cmd_data->cla = 0x80;
    cmd_data->ins = 0xF0;
    cmd_data->p1 = 0x01;
    cmd_data->p2 = 0x00;
    cmd_data->lc = 0x12;
    cmd_data->le = 0x00;
    cmd_data->le_type = 0x01;
    cmd_data->pdata = VCM_TLV;
    cmd_data->cpdu_type = 0x00;
}

void scrs_command_operation(SCRS_CMD_TYPE cmd_num, p_cmd_t cmd, p_rsp_t rsp) {
    uint8_t channel = 0;
    uint8_t rdata[255] = {0,};
    secEse_7816_rpdu_t rsp_data;
    secEse_7816_cpdu_t cmd_data;
    ESESTATUS result = ESESTATUS_OK;

    (void)cmd;

    result = secEseOpen(&channel);
    if (result != ESESTATUS_OK){
        LOGE("scrs_command_operation %d secEseOpen fail %04x", cmd_num, result);
        rsp->ret = RET_ERR_TZ;
        goto error;
    } else {
        LOGD("scrs_command_operation %d secEseOpen success %04x", cmd_num, result);
    }

    memset(&rsp_data, 0, sizeof(secEse_7816_rpdu_t));
    rsp_data.pdata = rdata;
    result = secEseSelect(channel,SCRS_AID,0,9,&rsp_data);
    if (result != ESESTATUS_OK){
        LOGE("scrs_command_operation %d secEseSelect fail %04x", cmd_num, result);
        rsp->ret = RET_ERR_TZ;
        goto error;
    } else {
        if ((rsp_data.sw1 != 0x90) || (rsp_data.sw2 != 0x00)) {
            result = (rsp_data.sw1 << 8)|(rsp_data.sw2) ;
            LOGE("secEseSelect Abnormal Status Word %04x", result);
            rsp->ret = RET_ERR_TZ;
            goto error;
        } else {
            LOGD("scrs_command_operation %d secEseSelect success %04x", cmd_num, result);
        }
    }

    memset(&rsp_data, 0, sizeof(secEse_7816_rpdu_t));
    memset(&cmd_data, 0, sizeof(secEse_7816_cpdu_t));
    switch(cmd_num)
    {
        case CMD_SCRS_START_USE_CARD:
            LOGD("scrs_command_operation CMD_SCRS_START_USE_CARD");
            start_use_card(&cmd_data);
            break;
        case CMD_SCRS_END_USE_CARD:
            LOGD("scrs_command_operation CMD_SCRS_END_USE_CARD");
            end_use_card(&cmd_data);
            break;
        case CMD_SCRS_SET_DEFAULT_CARD:
            LOGD("scrs_command_operation CMD_SCRS_SET_DEFAULT_CARD");
            set_default_card(&cmd_data);
            break;
        case CMD_SCRS_GET_DEFAULT_CARD:
            LOGD("scrs_command_operation CMD_SCRS_GET_DEFAULT_CARD");
            get_default_card(&cmd_data);
            break;
        case CMD_SCRS_SET_DEFAULT_WALLET:
            LOGD("scrs_command_operation CMD_SCRS_SET_DEFAULT_WALLET");
            set_default_wallet(&cmd_data);
            break;
        case CMD_SCRS_GET_DEFAULT_WALLET:
            LOGD("scrs_command_operation CMD_SCRS_GET_DEFAULT_WALLET");
            get_default_wallet(&cmd_data);
            break;
        case CMD_SCRS_GET_WALLET_LIST:
            LOGD("scrs_command_operation CMD_SCRS_GET_WALLET_LIST");
            get_wallet_list(&cmd_data);
            break;
        case CMD_SCRS_SET_STATUS_ACTIVATED:
            LOGD("scrs_command_operation CMD_SCRS_SET_STATUS_ACTIVATED");
            set_status_activated(&cmd_data);
            break;
        case CMD_SCRS_SET_STATUS_DEACTIVATED:
            LOGD("scrs_command_operation CMD_SCRS_SET_STATUS_DEACTIVATED");
            set_status_deactivated(&cmd_data);
            break;
        default:
            LOGE("scrs_command_operation %d command is not matched", cmd_num);
            rsp->ret = RET_ERR_TZ;
            return;
    }
    rsp_data.pdata = rdata;

    result = secEseTransmit(channel,&cmd_data,&rsp_data);
    if (result != ESESTATUS_OK){
        LOGE("scrs_command_operation %d secEseTransmit fail %04x", cmd_num, result);
        rsp->ret = RET_ERR_TZ;
        goto error;
    } else {
        if ((rsp_data.sw1 != 0x90) || (rsp_data.sw2 != 0x00)) {
            result = (rsp_data.sw1 << 8)|(rsp_data.sw2) ;
            LOGE("secEseTransmit Abnormal Status Word %04x", result);
            rsp->ret = RET_ERR_TZ;
            goto error;
        } else {
            LOGD("scrs_command_operation %d secEseTransmit success %04x", cmd_num, result);
        }
    }
error:
    result = secEseClose(channel);
    if (result != ESESTATUS_OK){
        LOGE("scrs_command_operation %d secEseClose fail %04x", cmd_num, result);
        rsp->ret = RET_ERR_TZ;
    } else {
        LOGD("scrs_command_operation %d secEseClose success %04x", cmd_num, result);
    }

    if (rsp->ret == ESESTATUS_OK){
        LOGD("scrs_command_operation %d return RET_SUCCESS", cmd_num);
    }else{
        LOGD("scrs_command_operation %d return RET_ERR_TZ", cmd_num);
    }
}

void ta_test(p_cmd_t cmd, p_rsp_t rsp) {
    (void)cmd;

    LOGD("success ta_test");
    rsp->data[0] = 7;
    rsp->dataLen = 1;
    rsp->ret = RET_SUCCESS;
    rsp->status = 8;
}

void ChannelTest() {
    uint8_t channelId;
    ESESTATUS result;
//    uint8_t ISD_AID[8] = {0xA0, 0x00, 0x00, 0x01, 0x51, 0x00, 0x00, 0x00};
	uint8_t test_applet[9] = {0x4D,0x79,0x54,0x65,0x73,0x74,0x41,0x70,0x70};
	uint8_t testapdu[5] = {0x80,0x02,0x00,0x00,0x00};

    uint8_t rspdata[256] = {0,};
    secEse_7816_rpdu_t rsp;
    rsp.pdata = rspdata;
    rsp.len = 256;

    result = secEseOpen(&channelId);
    if (result != 0) {
        LOGD("secEseOpen fail !! result = %04x", result);
    } else {
        LOGD("secEseOpen successresult = %04x", result);
    }
    LOGD("channelId is = %02x", channelId);

    result = secEseSelect(channelId,test_applet,0,9,&rsp);
    secEseAPDUTransmit(channelId,testapdu,5,&rsp);
    result = secEseClose(channelId);
    if (result != 0) {
        LOGD("secEseClose fail !! result = %04x", result);
    } else {
        LOGD("secEseClose result = %04x", result);
    }
}

void StressTest1(p_rsp_t pRsp) {
    uint8_t channelId;
    ESESTATUS result;
    uint8_t TEST_AID[11] = {0xA0, 0x00, 0x00, 0x02, 0x20, 0x72, 0x45, 0x63, 0x68, 0x6F, 0x01};
    uint8_t rspdata[256] = {0,};
    secEse_7816_rpdu_t rsp;

    secEse_7816_rpdu_t rsp_data;
    secEse_7816_cpdu_t cmd_data;

    rsp.pdata = rspdata;
    rsp.len = 256;

    result = secEseOpen(&channelId);
    if (result != 0) {
        LOGE("StressTest1 secEseOpen fail !! result = %04x", result);
		pRsp->ret = -1;
        return;
    } else {
        LOGD("StressTest1 secEseOpen successresult = %04x", result);
        LOGD("StressTest1 channelId is = %02x", channelId);
    }

    result = secEseSelect(channelId,TEST_AID,0,11,&rsp);
    if (result != 0) {
        LOGE("StressTest1 secEseSelect fail !! result = %04x", result);
		pRsp->ret = -1;
        result = secEseClose(channelId);
        return;
    } else {
        LOGD("StressTest1 secEseSelect successresult = %04x", result);
    }

    memset(&rsp_data, 0, sizeof(secEse_7816_rpdu_t));
    rsp_data.pdata = rspdata;
    cmd_data.cla = 0x00;
    cmd_data.ins = 0x11;
    cmd_data.p1 = 0x22;
    cmd_data.p2 = 0x33;
    cmd_data.lc = 0x00;
    cmd_data.le = 0x00;
    cmd_data.le_type = 0x01;
    cmd_data.pdata = NULL;
    cmd_data.cpdu_type = 0x00;

    result = secEseTransmit(channelId,&cmd_data,&rsp_data);
    if (result != 0) {
        LOGE("StressTest1 secEseTransmit fail !! result = %04x", result);
		pRsp->ret = -1;
        result = secEseClose(channelId);
        return;
    } else {
        LOGD("StressTest1 secEseTransmit successresult = %04x", result);
    }

    result = secEseClose(channelId);
    if (result != 0) {
        LOGE("StressTest1 secEseClose fail !! result = %04x", result);
		pRsp->ret = -1;
    } else {
        LOGD("StressTest1 secEseClose result = %04x", result);
    }
}

void StressTest2(p_rsp_t pRsp) {
    uint8_t channelId;
    ESESTATUS result;
    uint8_t TEST_AID[16] = {0xA0, 0x00, 0x00, 0x03, 0x96, 0x4D, 0x34, 0x4D, 0x15, 0x04, 0x01, 0x81, 0x9F, 0x5A, 0x00, 0x04};
    uint8_t rspdata[256] = {0,};
    secEse_7816_rpdu_t rsp;
    rsp.pdata = rspdata;
    rsp.len = 256;

    (void) pRsp;

    result = secEseOpen(&channelId);
    if (result != 0) {
        LOGE("StressTest2 secEseOpen fail !! result = %04x", result);
        return;
    } else {
        LOGD("StressTest2 secEseOpen successresult = %04x", result);
        LOGD("StressTest2 channelId is = %02x", channelId);
    }

    result = secEseSelect(channelId,TEST_AID,0,16,&rsp);
    if (result != 0) {
        LOGE("StressTest2 secEseSelect fail !! result = %04x", result);
        result = secEseClose(channelId);
        return;
    } else {
        LOGD("StressTest2 secEseSelect successresult = %04x", result);
    }

    result = secEseClose(channelId);
    if (result != 0) {
        LOGE("StressTest2 secEseClose fail !! result = %04x", result);
    } else {
        LOGD("StressTest2 secEseClose result = %04x", result);
    }
}

void attackTest() {
    int i=0;
    uint8_t cn = 0;
    uint8_t isd_aid[] = {0xA0, 0x00, 0x00, 0x01, 0x51, 0x00, 0x00, 0x00};
    uint8_t data[MAX_RAPDU_DATA_SIZE] = {0,};
    uint8_t APDU_INIT_UPDATE[14] = {0x80, 0x50, 0x30 , 0x00 , 0x08 , 0xAB , 0x7D , 0x94 , 0x4E , 0x20 , 0x6D , 0x4D , 0x64 , 0x00};
    uint8_t APDU_EXT_AUTH[21] = {0x84, 0x82, 0x01, 0x00, 0x10, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF};

    secEse_7816_rpdu_t rpdu;;


    LOGD("init-update start");


    for (i=0;i<15;i++)
    {
        //secEseOpen(&cn);

        memset(&rpdu, 0, sizeof(secEse_7816_rpdu_t));
        rpdu.pdata = data;
        secEseSelect(cn, isd_aid, 0, 8, &rpdu);

        memset(&rpdu, 0, sizeof(secEse_7816_rpdu_t));
        memset(data, 0, MAX_RAPDU_DATA_SIZE);
        rpdu.pdata = data;
        LOGD("init-update count %d",i);
        secEseAPDUTransmit(cn, APDU_INIT_UPDATE, 14, &rpdu);
        secEseAPDUTransmit(cn, APDU_EXT_AUTH, 21, &rpdu);

        //secEseClose(cn);
    }

    //secEseOpen(&cn);

}

void restirctedCheck() {
    //int i=0;
    uint8_t cn = 0;
    uint8_t GET_MEMORY[] = {0x80, 0xCA, 0xFF, 0x21, 0x00};
    uint8_t data[MAX_RAPDU_DATA_SIZE] = {0,};
    secEse_7816_rpdu_t rpdu;;

    memset(&rpdu, 0, sizeof(secEse_7816_rpdu_t));
    rpdu.pdata = data;

    memset(&rpdu, 0, sizeof(secEse_7816_rpdu_t));
    memset(data, 0, MAX_RAPDU_DATA_SIZE);
    rpdu.pdata = data;

    secEseAPDUTransmit(cn, GET_MEMORY, 5, &rpdu);

    LOGD("Result is %02x %02x",rpdu.sw1,rpdu.sw2);

}

#endif

