#ifndef __SSE_ENTRY_MANAGE_UTIL_H__
#define __SSE_ENTRY_MANAGE_UTIL_H__

#include "tz_log.h"
#include "sse_status.h"
#include "ssp_service.h"
#include "sec_apdu.h"
#include "sse.h"

#define MEMSET_BUF_BUFSIZE( buf, bufSize ) \
    { \
        memset((uint8_t*)buf, 0, bufSize); \
        bufSize = 0; \
    }

#define MEMCPY_BUF_BUFSIZE( buf, src, bufSize, srcSize ) \
    { \
        memcpy((uint8_t*)buf, (uint8_t*)src, srcSize); \
        bufSize = srcSize; \
    }

#define BUF_FILL_TLV( inTag, inLen, inValue, outBuf, outBufSize ) \
    { \
        outBuf[0] = inTag; \
        outBuf[1] = inLen; \
        memcpy( (uint8_t*)outBuf + 1 + 1, (uint8_t*)inValue, inLen ); \
        outBufSize = 1 + 1 + inLen; \
    }

#define BUF_APPEND( frontBuf, frontBufSize, backBuf, backBufSize ) \
    { \
        memcpy( (uint8_t*)frontBuf + frontBufSize, (uint8_t*)backBuf, backBufSize ); \
        frontBufSize += backBufSize; \
    }

#define APPEND_VALUE( tempBuf, parentBuf, parentBufSize, childBuf, childBufSize ) \
    { \
        memcpy( (uint8_t*)tempBuf, parentBuf, parentBufSize ); \
        memcpy( (uint8_t*)tempBuf + parentBufSize, childBuf, childBufSize ); \
        parentBufSize += childBufSize; \
        memcpy( (uint8_t*)parentBuf, tempBuf, parentBufSize); \
    }

// DATA field tags definition
#define TAG_E0_DATA_PROPERTIES                  0xE0
#define TAG_E1_DATA_ENTRY_LENGTH                0xE1
#define TAG_E2_ENTRY_ID                         0xE2
#define TAG_E3_ACCESS_RULE                      0xE3
#define TAG_E4_APPLET                           0xE4
#define TAG_E5_AID                              0xE5
#define TAG_E6_TA_ID                            0xE6
#define TAG_E7_AUTH_TYPE_INFO                   0xE7
#define TAG_E8_RETRY_COUNT                      0xE8
#define TAG_E9_AUTH_TYPE_PASSWRD                0xE9
#define TAG_EA_PASSWORD                         0xEA
#define TAG_EB_ITERATION_COUNT1                 0xEB
#define TAG_EC_ITERATION_COUNT2                 0xEC
#define TAG_ED_LENGTH_OF_DEK                    0xED
#define TAG_EE_AUTH_TYPE_BIO                    0xEE
#define TAG_EF_TEMPLATE_ID                      0xEF
#define TAG_F2_NEW_AUTH_TYPE_INFO               0xF2
            
#define ENTRY_DATA_TYPE_PRIVATE                 0x0000 // reference count is stricted (SSE v1.0 : 0~128 max , v1.1 : 0~30 max)
#define ENTRY_DATA_TYPE_PUBLIC                  0x0001 // reference count doesn't exits


// Length definition
#define LEN_TA_ID                               0x10
#define LEN_ENTRY_ID                            0x04
#define LEN_TEMPLATE_ID                         0x20


// MAX definition
#define MAX_ENTRY_TEMPLATE_ID                   0x03
#define MAX_ENTRY_ACCESSABLE_APPLET_CNT         0x05
#define MAX_ENTRY_COMAND_DATAFIELD_SIZE         300 // max 258 <- 0xff + len size 2 + tag size 1
#define MAX_AVAILABLE_PROPERTY_PART_LEN         258
#define MAX_ENTRY_SIZE                          5120 // 0x1400
#define MAX_ENTRY_DATA_SIZE                     (16*16*16) // 4096

///////////// CPDU /////////////
//GET ENTRY DATA
#define CLA_GED                                 0x80
#define INS_GED                                 0xCA
#define P1_GED_FIRST                            0x00
#define P1_GED_NEXT                             0x01
#define P2_GED_ZERO                             0x00
#define LE_GED                                  0x00
#define LE_TYPE_GED                             0x01

//PUT ENTRY DATA
#define CLA_PED                                 0x80
#define INS_PED                                 0xDA
#define P1_PED_CREATE_PUT_FIRST                 0x00 // P1 bit 6~5
#define P1_PED_FIRST                            0x20 // P1 bit 6~5
#define P1_PED_NEXT                             0x40 // P1 bit 6~5
#define P2_PED_ZERO                             0x00 // P2 bit7
#define CPDU_TYPE_PED                           0x00
#define LE_PED                                  0x00
#define LE_TYPE_PED                             0x00

//DELETE ENTRY DATA
#define CLA_DED                                 0x80
#define INS_DED                                 0xE4
#define P1_DED                                  0x00
#define P2_DED                                  0x00
#define LC_DED                                  0x04
#define CPDU_TYPE_DED                           0x00
#define LE_DED                                  0x00
#define LE_TYPE_DED                             0x00

//DELETE ALL ENTRIES
#define CLA_DAE                                 0x80
#define INS_DAE                                 0xE5
#define P1_DAE                                  0x00
#define P2_DAE                                  0x00
#define LC_DAE                                  0x00
#define CPDU_TYPE_DAE                           0x00
#define LE_DAE                                  0x00
#define LE_TYPE_DAE                             0x00

//UPDATE AUTH
#define CLA_UA                                  0x80
#define INS_UA                                  0xC6
#define CPDU_TYPE_UA                            0x00
#define LE_UA                                   0x00
#define LE_TYPE_UA                              0x00

///////////// RPDU /////////////
#define RES_OK_SW1 0x90 // Incorrect values in the command data.
#define RES_OK_SW2 0x00 // Incorrect values in the command data.

#define RES_MORE_DATA_AVAILABLE_SW1 0x63 // More data available
#define RES_MORE_DATA_AVAILABLE_SW2 0x10 // More data available


#define RES_INCORRECT_VALUE_SW1 0x6A // Incorrect values in the command data.(if the defined title already exists) only for b4=1 of P1
#define RES_INCORRECT_VALUE_SW2 0x80 // Incorrect values in the command data.(if the defined title already exists) only for b4=1 of P1

#define RES_SECURITY_STATUS_NOT_SATISFIED_SW1 0x69 // Security status not satisfied.
#define RES_SECURITY_STATUS_NOT_SATISFIED_SW2 0x82 // Security status not satisfied.

#define RES_WRONG_LENGH_IN_LC_SW1 0x67 // Wrong length in LC
#define RES_WRONG_LENGH_IN_LC_SW2 0x00 // Wrong length in LC

#define RES_INCORRECT_P1P2_SW1 0x6A // Incorrect P1 P2(if the defined P1/P2 are invalid or cannot be applied)
#define RES_INCORRECT_P1P2_SW2 0x86 // Incorrect P1 P2(if the defined P1/P2 are invalid or cannot be applied)

#define RES_INVALID_INS_SW1 0x6D // Invalid instruction
#define RES_INVALID_INS_SW2 0x00 // Invalid instruction

#define RES_INVALID_CLA_SW1 0x6E // Invalid class
#define RES_INVALID_CLA_SW2 0x00 // Invalid class

#define RES_MEMORY_FAILURE_SW1 0x65 // Memory failure(if the input data exceeds the defined size or a size wasn't defined)
#define RES_MEMORY_FAILURE_SW2 0x81 // Memory failure(if the input data exceeds the defined size or a size wasn't defined)

#define RES_NOT_ENOUGH_MEMORY_SW1 0x6A // Not enough memory space(if not enough memory resources are available)
#define RES_NOT_ENOUGH_MEMORY_SW2 0x84 // Not enough memory space(if not enough memory resources are available)

#define RES_SSP_NOT_AVAILABLE_SW1 0x6A // SSP is not available
#define RES_SSP_NOT_AVAILABLE_SW2 0x81 // SSP is not available

#define RES_REF_DATA_NOT_FOUND_SW1 0x6A // Referenced data not found(if no SS entry currently selected)
#define RES_REF_DATA_NOT_FOUND_SW2 0x88 // Referenced data not found(if no SS entry currently selected)

#define RES_SSP_UNDER_PROCESS_SW1 0x69 // Condition of use not satisfied
#define RES_SSP_UNDER_PROCESS_SW2 0x85 // Condition of use not satisfied

#define RES_AID_NOT_EXIST_SW1 0x6A // AID doesnt exist
#define RES_AID_NOT_EXIST_SW2 0x82 // AID doesnt exist

#define RES_COMMAND_NOT_ALLOWED_SW1 0x69 // Command not allowed
#define RES_COMMAND_NOT_ALLOWED_SW2 0x00 // Command not allowed

#define RES_VERIFY_FAIL_SW1 0x6F // verify failed. SW2 is remain verify count.

typedef struct sse_tlv {
    uint8_t Tag;
    uint8_t tlvFormatLen[5];
    uint8_t Len_size;
    uint8_t Value[MAX_ENTRY_COMAND_DATAFIELD_SIZE];
} sse_tlv_t;

uint32_t secure_cmp(uint8_t *data1, const uint8_t *data2, uint16_t data_size );

SSESTATUS getSseStBySspSt(SSPSTATUS ssp_ret);
SSESTATUS getSseStBySspRapdu(uint8_t r_sw1, uint8_t r_sw2);
SSESTATUS getSseStByIsoSt(ESESTATUS iso_ret);

void tlvToBytearr(sse_tlv_t* inTLV, uint8_t* out, uint32_t* outLen);
SSESTATUS makeupTLV(uint8_t tag, uint8_t* data, uint32_t dataLen, sse_tlv_t* outTLV);
void formatTLVLength(uint32_t inLen, uint8_t* tlvFormattedLen, uint8_t* tlvFormattedLenSize);
void getSSEVersion(uint8_t in_up, uint8_t in_down, uint8_t* outMajor, uint8_t* outMinor, uint8_t* outRelease);

#endif //__SSE_ENTRY_MANAGE_UTIL_H__


