#ifndef __EM_CONTEXT_H
#define __EM_CONTEXT_H

/*
 * It will be shared em_tlc.so
 */
#ifdef EM_REE
#pragma pack(push, 1)
#endif
typedef struct em_context_t {
	uint32_t cmd;
	uint64_t flags[EM_LEN_PAYLOAD_FLAGS];

	uint8_t did[EM_LEN_DID];
	uint8_t imei[EM_LEN_IMEI];
	uint8_t single_id[EM_LEN_SINGLE_ID];
	uint8_t model_name[EM_LEN_MODEL_NAME];
	uint8_t otp[EM_LEN_OTP];
	uint8_t date[EM_LEN_DATE];

	uint8_t client_proc_name[EM_LEN_CLIENT_PROC_NAME];
	uint8_t client_pkg_name[EM_LEN_CLIENT_PKG_NAME];
	uint32_t client_uid;
	uint32_t client_signature;

	uint16_t cnt_mode;
	uint16_t modes[EM_LEN_MODE_BUFFER];

	uint32_t cnt_validity;
	uint8_t osversion[EM_LEN_OSVERSION];
	uint8_t swversion[EM_LEN_SWVERSION];
	uint8_t blversion[EM_LEN_BLVERSION];
	uint32_t tss;
	uint32_t activated;
	uint8_t serial[EM_LEN_UNIQUE];
	uint8_t smsn[EM_LEN_SMSN]; // 934
	uint8_t fuse[EM_LEN_FUSE];
	uint8_t openday[EM_LEN_OPENDAY];

	uint8_t reserved[202]; // Don't add item to above

	uint8_t token[EM_LEN_TOKEN];

	uint32_t len_message;
	uint8_t message[EM_LEN_MESSAGE];

	uint32_t len_cert;
	uint8_t cert[EM_LEN_CERTIFICATE];

	uint32_t len_ess_prefixbody;
	uint8_t ess_prefixbody[EM_LEN_ESS_PREFIX_BODY];
	uint8_t ess_nonce[EM_LEN_NONCE];
	uint8_t ess_iv_b64[EM_LEN_ESS_IV_B64];
	uint8_t ess_etoken_b64[EM_LEN_TOKEN];
	uint8_t ess_command_type[1 + 1];
	uint8_t token_id[EM_LEN_TOKEN_ID];

	uint8_t recovery_data[EM_LEN_RECOVERY_DATA];

	uint8_t esi[EM_LEN_ESI];

	uint8_t em_version;
	uint8_t is_provision;
	uint8_t key[EM_LEN_KEY_CORE_V20];
	em_keeping_item keep;
	uint32_t ret_temp;
	uint64_t mode_bits[EM_LEN_GET_MODES_BIT_BUFFER];
	uint8_t iin[EM_LEN_IIN];
	uint8_t priority[EM_LEN_PRIORITY_TIME];
	uint8_t omc_id[EM_LEN_OMC_ID];
	em_core_v20 core_v20;
	em_parsed_token *parsed_token;
	em_token_ptr token_ptr;
} em_context;

#define EM_STRUCT_REQ_PAYLOAD_PRIMARY_SIZE    (sizeof(((em_req_payload_primary *)0)->cmd) + \
						sizeof(((em_req_payload_primary *)0)->flags) + \
						sizeof(((em_req_payload_primary *)0)->did) + \
						sizeof(((em_req_payload_primary *)0)->imei) + \
						sizeof(((em_req_payload_primary *)0)->single_id) + \
						sizeof(((em_req_payload_primary *)0)->model_name) + \
						sizeof(((em_req_payload_primary *)0)->otp) + \
						sizeof(((em_req_payload_primary *)0)->date) + \
						sizeof(((em_req_payload_primary *)0)->client_proc_name) + \
						sizeof(((em_req_payload_primary *)0)->client_pkg_name) + \
						sizeof(((em_req_payload_primary *)0)->client_uid) + \
						sizeof(((em_req_payload_primary *)0)->client_signature) + \
						sizeof(((em_req_payload_primary *)0)->cnt_mode) + \
						sizeof(((em_req_payload_primary *)0)->modes) + \
						sizeof(((em_req_payload_primary *)0)->cnt_validity) + \
						sizeof(((em_req_payload_primary *)0)->osversion) + \
						sizeof(((em_req_payload_primary *)0)->swversion) + \
						sizeof(((em_req_payload_primary *)0)->blversion) + \
						sizeof(((em_req_payload_primary *)0)->tss) + \
						sizeof(((em_req_payload_primary *)0)->activated) + \
						sizeof(((em_req_payload_primary *)0)->serial) + \
						sizeof(((em_req_payload_primary *)0)->smsn) + \
						sizeof(((em_req_payload_primary *)0)->keep) + \
						sizeof(((em_req_payload_primary *)0)->req_cnt) + \
						sizeof(((em_req_payload_primary *)0)->fuse) + \
						sizeof(((em_req_payload_primary *)0)->openday) + \
						sizeof(((em_req_payload_primary *)0)->iin) + \
						sizeof(((em_req_payload_primary *)0)->priority) + \
						sizeof(((em_req_payload_primary *)0)->omc_id) + \
						sizeof(((em_req_payload_primary *)0)->reserved))
/* Must update EM_STRUCT_REQ_PAYLOAD_PRIMARY_SIZE when adding new field */
typedef struct em_req_payload_primary_t {
	uint32_t cmd;
	uint64_t flags[EM_LEN_PAYLOAD_FLAGS];

	uint8_t did[EM_LEN_DID];
	uint8_t imei[EM_LEN_IMEI];
	uint8_t single_id[EM_LEN_SINGLE_ID];
	uint8_t model_name[EM_LEN_MODEL_NAME];
	uint8_t otp[EM_LEN_OTP];
	uint8_t date[EM_LEN_DATE];

	uint8_t client_proc_name[EM_LEN_CLIENT_PROC_NAME];
	uint8_t client_pkg_name[EM_LEN_CLIENT_PKG_NAME];
	uint32_t client_uid;
	uint32_t client_signature;

	uint16_t cnt_mode;
	uint16_t modes[EM_LEN_MODE_BUFFER]; // 808

	uint32_t cnt_validity; // 812

	uint8_t osversion[EM_LEN_OSVERSION];
	uint8_t swversion[EM_LEN_SWVERSION];
	uint8_t blversion[EM_LEN_BLVERSION]; // 878
	uint32_t tss;
	uint32_t activated;
	uint8_t serial[EM_LEN_UNIQUE];
	uint8_t smsn[EM_LEN_SMSN]; // 934

	em_keeping_item keep;
	uint32_t req_cnt;
	uint8_t fuse[EM_LEN_FUSE];
	uint8_t openday[EM_LEN_OPENDAY];
	uint8_t iin[EM_LEN_IIN];
	uint8_t priority[EM_LEN_PRIORITY_TIME];
	uint8_t omc_id[EM_LEN_OMC_ID];
	uint8_t reserved[129]; // 1152 - 938
} em_req_payload_primary;

#define EM_STRUCT_REQ_PAYLOAD_SECONDARY_SIZE    (sizeof(((em_req_payload_secondary *)0)->flags) + \
						sizeof(((em_req_payload_secondary *)0)->token) + \
						sizeof(((em_req_payload_secondary *)0)->len_message) + \
						sizeof(((em_req_payload_secondary *)0)->message) + \
						sizeof(((em_req_payload_secondary *)0)->len_cert) + \
						sizeof(((em_req_payload_secondary *)0)->cert) + \
						sizeof(((em_req_payload_secondary *)0)->len_ess_prefixbody) + \
						sizeof(((em_req_payload_secondary *)0)->ess_prefixbody) + \
						sizeof(((em_req_payload_secondary *)0)->ess_nonce) + \
						sizeof(((em_req_payload_secondary *)0)->ess_iv_b64) + \
						sizeof(((em_req_payload_secondary *)0)->esi))
/* Must update EM_STRUCT_REQ_PAYLOAD_PRIMARY_SIZE when adding new field */
typedef struct em_req_payload_secondary_t {
	uint64_t flags[EM_LEN_PAYLOAD_FLAGS];

	uint8_t token[EM_LEN_TOKEN];

	uint32_t len_message;
	uint8_t message[EM_LEN_MESSAGE];

	uint32_t len_cert;
	uint8_t cert[EM_LEN_CERTIFICATE];

	uint32_t len_ess_prefixbody;
	uint8_t ess_prefixbody[EM_LEN_ESS_PREFIX_BODY];

	uint8_t ess_nonce[EM_LEN_NONCE];
	uint8_t ess_iv_b64[EM_LEN_ESS_IV_B64];

	uint8_t esi[EM_LEN_ESI];
} em_req_payload_secondary;

#define EM_STRUCT_RSP_PAYLOAD_PRIMARY_SIZE    (sizeof(((em_rsp_payload_primary *)0)->cmd) + \
						sizeof(((em_rsp_payload_primary *)0)->flags) + \
						sizeof(((em_rsp_payload_primary *)0)->keep) + \
						sizeof(((em_rsp_payload_primary *)0)->mode_bits) + \
						sizeof(((em_rsp_payload_primary *)0)->priority) + \
						sizeof(((em_rsp_payload_primary *)0)->reserved))
/* Must update EM_STRUCT_RSP_PAYLOAD_PRIMARY_SIZE when adding new field */
typedef struct em_rsp_payload_primary_t {
	uint32_t cmd;
	uint64_t flags[EM_LEN_PAYLOAD_FLAGS];

	em_keeping_item keep;
	uint64_t mode_bits[EM_LEN_GET_MODES_BIT_BUFFER];
	uint8_t priority[EM_LEN_PRIORITY_TIME];
	uint8_t reserved[959];
} em_rsp_payload_primary;

#define EM_STRUCT_RSP_PAYLOAD_SECONDARY_SIZE    (sizeof(((em_rsp_payload_secondary *)0)->flags) + \
						sizeof(((em_rsp_payload_secondary *)0)->esi) + \
						sizeof(((em_rsp_payload_secondary *)0)->token) + \
						sizeof(((em_rsp_payload_secondary *)0)->type_message) + \
						sizeof(((em_rsp_payload_secondary *)0)->len_message) + \
						sizeof(((em_rsp_payload_secondary *)0)->message))
/* Must update EM_STRUCT_RSP_PAYLOAD_SECONDARY_SIZE when adding new field */
typedef struct em_rsp_payload_secondary_t {
	uint64_t flags[EM_LEN_PAYLOAD_FLAGS];

	uint8_t esi[EM_LEN_ESI];

	uint8_t token[EM_LEN_TOKEN];

	uint32_t type_message;
	uint32_t len_message;
	uint8_t message[EM_LEN_MESSAGE];
} em_rsp_payload_secondary;

#define EM_STRUCT_REQ_PAYLOAD_SIZE    (1 + EM_STRUCT_REQ_PAYLOAD_PRIMARY_SIZE + \
						EM_STRUCT_REQ_PAYLOAD_SECONDARY_SIZE)
typedef struct em_req_payload_t {
	uint8_t version;
	em_req_payload_primary primary;
	em_req_payload_secondary secondary;
} em_req_payload;

#define EM_STRUCT_RSP_PAYLOAD_SIZE    (4 + 1 + EM_STRUCT_RSP_PAYLOAD_PRIMARY_SIZE + \
						EM_STRUCT_RSP_PAYLOAD_SECONDARY_SIZE)
typedef struct em_rsp_payload_t {
	uint32_t ret;
	uint8_t version;
	em_rsp_payload_primary primary;
	em_rsp_payload_secondary secondary;
} em_rsp_payload;
#ifdef EM_REE
#pragma pack(pop)
#endif

int em_context_make_request(uint8_t *req_buf, em_context *ctx);
int em_context_make_response(uint8_t *rsp_buf, em_context *ctx, uint32_t result);

#include "em_common.h"

#endif
