#ifndef __EM_DATA_STRUCTURE_H
#define __EM_DATA_STRUCTURE_H

#include "em_constants.h"
#include <stdint.h>

typedef struct em_core_v20_t {
	uint8_t magic[EM_LEN_MAGIC_CORE_V20];
	uint8_t gcm_tag[EM_LEN_GCM_TAG_CORE_V20];
	uint8_t key[EM_LEN_KEY_CORE_V20];
	uint32_t esi_ctr;
	uint32_t flags;
	uint32_t recovery_ctr;
	uint8_t iin[EM_LEN_IIN];
	uint32_t ta_rp;
	uint8_t reserved[156]; /* To make 1 RPMB block (256 Bytes) */
} em_core_v20;

#define EM_STRUCT_ESI_META_SIZE    (EM_LEN_ESI_MAGIC + \
						sizeof(((em_esi_meta *)0)->version) + \
						sizeof(((em_esi_meta *)0)->writer) + \
						sizeof(((em_esi_meta *)0)->write_counter) + \
						sizeof(((em_esi_meta *)0)->size_of_items) + \
						sizeof(((em_esi_meta *)0)->num_of_items))
/* Must update EM_STRUCT_ESI_META_SIZE when adding new field */
typedef struct em_esi_meta_t {
	uint8_t magic[EM_LEN_ESI_MAGIC];
	uint16_t version;
	uint8_t writer;
	uint32_t write_counter;
	uint32_t size_of_items;
	uint16_t num_of_items;
} em_esi_meta;

/* Checked */
typedef struct em_default_element_t {
	uint16_t type;
	uint16_t len;
} em_default_element;

/* Checked */
typedef struct em_esi_item_t {
	em_default_element elem;
	uint8_t *data;
} em_esi_item;

#define EM_STRUCT_ESI_TUC_V20_SIZE    (sizeof(((tuc_v20 *)0)->mode_index) + \
						sizeof(((tuc_v20 *)0)->flags) + \
						sizeof(((tuc_v20 *)0)->count))
/* Must update EM_STRUCT_ESI_TUC_V20_SIZE when adding new field */
typedef struct tuc_v20_t {
	uint16_t mode_index;
	uint8_t flags;
	uint32_t count;
} tuc_v20;

#define EM_STRUCT_ESI_TUC_TABLE_V20_SIZE    (sizeof(((tuc_table_v20 *)0)->num_of_tuc) + \
						(EM_STRUCT_ESI_TUC_V20_SIZE * \
						EM_LEN_MAX_MODE_TUC_V20))
/* Must update EM_STRUCT_ESI_TUC_TABLE_V20_SIZE when adding new field */
typedef struct tuc_table_v20_t {
	uint16_t num_of_tuc;
	tuc_v20 tucs[EM_LEN_MAX_MODE_TUC_V20];
} tuc_table_v20;

#define EM_STRUCT_ESI_TUC_SIZE    (sizeof(((tuc *)0)->mode_index) + \
						sizeof(((tuc *)0)->flags) + \
						sizeof(((tuc *)0)->count) + \
						sizeof(((tuc *)0)->max_count))
/* Must update EM_STRUCT_ESI_TUC_SIZE when adding new field */
typedef struct tuc_t {
	uint16_t mode_index;
	uint8_t flags;
	uint32_t count;
	uint32_t max_count;
} tuc;

#define EM_STRUCT_ESI_TUC_TABLE_SIZE    (sizeof(((tuc_table *)0)->num_of_tuc) + \
						(EM_STRUCT_ESI_TUC_SIZE * \
						EM_LEN_MAX_MODE_TUC))
/* Must update EM_STRUCT_ESI_TUC_TABLE_SIZE when adding new field */
typedef struct tuc_table_t {
	uint16_t num_of_tuc;
	tuc tucs[EM_LEN_MAX_MODE_TUC];
} tuc_table;

typedef struct em_default_meta_t {
	uint8_t magic[EM_LEN_DEFAULT_MAGIC];
	uint32_t len;
	uint32_t num_of_data;
} em_default_meta;

// TOKEN

typedef struct em_header_info_t {
	uint8_t prefix[EM_LEN_HEADER_FIELD];
	uint8_t type[EM_LEN_HEADER_FIELD];
	uint8_t version[EM_LEN_HEADER_VERSION];
} em_header_info;

typedef struct em_token_info_t {
	uint8_t id[EM_LEN_TOKEN_ID];
	uint16_t device_unique_info;
	uint16_t num_of_devices;
	uint8_t lsec_tok;
} em_token_info;

typedef struct em_device_info_t {
	char model_name[EM_LEN_MODEL_NAME];
	uint8_t did[EM_LEN_DID];
	uint8_t imei[EM_LEN_IMEI];
} em_device_info;

typedef struct em_issuer_info_t {
	char single_id[EM_LEN_SINGLE_ID + 1];
	uint8_t otp[EM_LEN_OTP + 1];
	uint8_t nonce[EM_LEN_NONCE];
	char system_id[EM_LEN_SYSTEM_ID + 1];
	char ip_addr[EM_LEN_IP_ADDR + 1];
	char mac_addr[EM_LEN_MAC_ADDR + 1];
} em_issuer_info;

typedef struct em_mode_info_t {
	uint16_t num_of_modes;
	uint16_t mode[EM_LEN_MAX_MODE];
} em_mode_info;

typedef struct em_validity_info_t {
	char issued_date[EM_LEN_DATE + 1];
	char expiry_date[EM_LEN_DATE + 1];
} em_validity_info;

typedef struct em_integrity_info_t {
	uint16_t len_signature;
	uint8_t signature[EM_LEN_SIGNATURE];
	uint16_t len_cert;
	uint8_t cert[EM_LEN_CERTIFICATE];
} em_integrity_info;

typedef struct em_modb_attr_t {
	uint16_t dui;
	uint8_t hidden;
	uint8_t is_mtuc_enabled;
	uint32_t mtuc_value;
	uint8_t exclusive;
	uint16_t used_once;
	uint16_t len_ext;
	char ext[EM_LEN_MODB_EXTENSEION];
} em_modb_attr;

typedef struct em_modb_data_t {
	uint16_t index;
	uint8_t name[32];
	uint8_t desc[128];
	uint16_t group_index;
	uint32_t len_attr;
	uint32_t num_of_attr;
	em_modb_attr attributes;
} em_modb_data;

typedef struct em_mode_db_t {
	em_modb_data data[EM_LEN_MAX_MODE];
} em_mode_db;

typedef struct em_token_ptr_t {
	em_header_info header;
	uint8_t *token_info;
	uint8_t *em_device_info[EM_LEN_MAX_DEVICE];
	uint8_t *issuer_info;
	uint8_t *mode_info;
	uint8_t *validity_info;
	uint8_t *mode_db;
	uint8_t *group_db;
	uint8_t *integrity_info;
} em_token_ptr;

typedef struct em_parsed_token_t {
	em_header_info header;
	em_token_info token;
	em_device_info device[EM_LEN_MAX_DEVICE]; /* Multiple */
	em_issuer_info issuer;
	em_mode_info mode; /* Multiple */
	em_validity_info validity;
	em_mode_db modedb; /* Mode DB */
	/* Group DB */
	em_integrity_info integrity;
} em_parsed_token;

typedef struct em_keeping_item_t {
	uint8_t single_id[EM_LEN_SINGLE_ID];
	uint8_t date[EM_LEN_DATE];
	uint8_t model_name[EM_LEN_MODEL_NAME];
	uint8_t nonce[EM_LEN_NONCE];
	uint8_t otp[EM_LEN_OTP];
	uint8_t iin[EM_LEN_IIN];
	uint8_t did[EM_LEN_DID];
	uint8_t imei[EM_LEN_IMEI];
	uint8_t session_iv[EM_LEN_SESSION_IV];
	uint8_t session_key[EM_LEN_SESSION_KEY];
} em_keeping_item;

#endif
