#include <stdio.h>
#include <string.h>

#include "vk_table.h"
#include "vk_error.h"
#include "vk_log.h"
#include "vk_utils.h"
#include "vk_packet_maker.h"
#include "vk_data_struct.h"
#include "vk_interface.h"
#include "vk_constants.h"
#include "vk_vault_manager.h"
#include "vk_interface.h"

int parse_clientreq_create_cmdreq(target_t* target, req_to_ta_t* req_to_ta, cmd_req_t* req)
{
	int ret = VK_ERR_GENERAL;
	item_meta_t item = {0,};
	uint8_t* msg = NULL;
	int offset = 0;
	uint32_t num_items = 0;
	uint32_t i;
	uint32_t max_sheltered_size = 0;

	if (target == NULL) {
		LOGE("%s: target is null\n", __func__);
		return VK_ERR_INVALID_ARGUMENT;
	}

	if (req_to_ta == NULL) {
		LOGE("%s: req_to_ta is null\n", __func__);
		return VK_ERR_INVALID_ARGUMENT;
	}

	if (req == NULL) {
		LOGE("%s: req is null\n", __func__);
		return VK_ERR_INVALID_ARGUMENT;
	}

	// cmd_id
	req->cmd_id = req_to_ta->cmd_id;
	req->vtab_index = target->vault.vtab_index;
	req->entire_vault_size = VTAB[req->vtab_index].num_blocks * VAULT_SINGLE_BLOCK_LEN;
	req->vault_level = VTAB[req->vtab_index].vault_level;

	msg = req_to_ta->msg;
	// If exist payload TLV item
	memcpy(&num_items, msg, sizeof(int));
	if (num_items > VK_PAYLOAD_TYPE_MAX) {
		LOGI("%s: payload item num is invalid (%d)\n", __func__, num_items);
		return VK_ERR_INVALID_ARGUMENT;
	}

	offset = sizeof(int);
	for (i = 0; i < num_items; i++) {
		if (offset + sizeof(item_meta_t) >= MAX_CLIENT_MSG_LEN) {
			LOGE("%s: Invalid request packet (%d)\n", __func__, offset);
			return VK_ERR_PARSING;
		}
		memcpy(&item, msg + offset, sizeof(item_meta_t));
		offset += (int)sizeof(item_meta_t);

		if (item.type == VK_PAYLOAD_TYPE_KEY) {
			if (item.len != VAULT_KEY_LEN || offset + item.len > MAX_CLIENT_MSG_LEN) {
				LOGE("%s: wrong size for primary key(%d)\n", __func__, item.len);
				return VK_ERR_PARSING;
			} else {
				memcpy(req->key, msg + offset, item.len);
				offset += item.len;
			}
			continue;
		}

		if (item.type == VK_PAYLOAD_TYPE_PRIVATED) {
			if (item.len != VAULT_KEY_LEN || offset + item.len > MAX_CLIENT_MSG_LEN) {
				LOGE("%s: wrong size for privated(%d)\n", __func__, item.len);
				return VK_ERR_PARSING;
			} else {
				memcpy(req->privated, msg + offset, item.len);
				offset += item.len;
			}
			continue;
		}

		if (item.type == VK_PAYLOAD_TYPE_HMAC) {
			if (item.len != HMAC_SHA256_LEN || offset + item.len > MAX_CLIENT_MSG_LEN) {
				LOGE("%s: wrong size for hmac(%d)\n", __func__, item.len);
				return VK_ERR_PARSING;
			} else {
				memcpy(req->hmac, msg + offset, item.len);
				offset += item.len;
			}
			continue;
		}

		if (item.type == VK_PAYLOAD_TYPE_SHELTERED) {
			max_sheltered_size = VTAB[req->vtab_index].num_blocks * VAULT_SINGLE_BLOCK_LEN - VAULT_LEN_EXPECT_SHELTERED_DATA;
			if (item.len > max_sheltered_size) {
				LOGE("%s: wrong size for sheltered(%d/%d)\n", __func__, item.len, max_sheltered_size);
				return VK_ERR_PARSING;
			} else {
				req->sheltered = msg + offset;
				req->sheltered_len = item.len;
				offset += item.len;
			}
			continue;
		}

		if (item.type == VK_PAYLOAD_TYPE_UNSHELTERED) {
			if (item.len > MAX_UNSHELTERED_DATA_LEN || offset + item.len > MAX_CLIENT_MSG_LEN) {
				LOGE("%s: wrong size for unsheltered(%d/%d)\n", __func__, item.len, MAX_UNSHELTERED_DATA_LEN);
				return VK_ERR_PARSING;
			} else {
				memcpy(req->unsheltered, msg + offset, item.len);
				req->unsheltered_len = item.len;
				offset += item.len;
			}
			continue;
		}

		if (item.type == VK_PAYLOAD_TYPE_SERVER_CERT) {
			if (item.len > MAX_SERVER_CERT_LEN) {
				LOGE("%s: wrong size for server cert(%d/%d)\n", __func__, item.len, MAX_SERVER_CERT_LEN);
				return VK_ERR_PARSING;
			} else {
				req->server_cert = msg + offset;
				req->server_cert_len = item.len;
				offset += item.len;
			}
			continue;
		}

		if (item.type == VK_PAYLOAD_TYPE_RSA_SIGNATURE) {
			if (item.len > RSA2048_SIGNATURE_LEN) {
				LOGE("%s: wrong size for rsa signature(%d)\n", __func__, item.len);
				return VK_ERR_PARSING;
			} else {
				memcpy(req->rsa_signature, msg + offset, item.len);
				req->rsa_signature_len = item.len;
				offset += item.len;
			}
			continue;
		}

		if (item.type == VK_PAYLOAD_TYPE_AUTH_MSG) {
			if (offset + item.len > MAX_CLIENT_MSG_LEN) {
				LOGE("%s: wrong size for msg(%d)\n", __func__, item.len);
				return VK_ERR_PARSING;
			} else {
				req->auth_msg = msg + offset;
				req->auth_msg_len = item.len;
				offset += item.len;
			}
			continue;
		}
	}

	// read preload
	req->preload = req_to_ta->preload_steady.preload_data;
	req->preload_size = req_to_ta->preload_steady.preload_size;

	// read device property
	memcpy(req->device_property, req_to_ta->device_property, sizeof(req_to_ta->device_property));

	// read client code
	req->client_code = VTAB[req->vtab_index].client_code;

	// get random iv
	ret = target->platform.get_secure_item(VK_SECURE_ITEM_IV, req->random_iv, AES_IV_LEN);
	if (ret != VK_SUCCESS || isAllZero(req->random_iv, AES_IV_LEN)) {
		LOGE("%s: Failed to get random iv(%d)\n", __func__, ret);
		return ret;
	}

	// read EM Token
	memcpy(req->em_token, req_to_ta->em_token, MAX_EMT_LEN);

	return ret;
}

int parse_cmdrsp_create_clientrsp(target_t* target, cmd_rsp_t* rsp, rsp_from_ta_t* rsp_from_ta)
{
	if (target == NULL) {
		LOGE("%s: target is null\n", __func__);
		return VK_ERR_INVALID_ARGUMENT;
	}

	if (rsp == NULL) {
		LOGE("%s: rsp is null\n", __func__);
		return VK_ERR_INVALID_ARGUMENT;
	}

	if (rsp_from_ta == NULL) {
		LOGE("%s: rsp_from_ta is null\n", __func__);
		return VK_ERR_INVALID_ARGUMENT;;
	}

	if (target->vault.vtab_index >= NUM_OF_VAULTS) {
		LOGE("%s: Invalid table index(%d)\n", __func__, target->vault.vtab_index);
		return VK_ERR_READ_VTAB;
	}

	rsp_from_ta->ret = rsp->ret;

	if (rsp->msg_len > 0) {
		memcpy(rsp_from_ta->msg, rsp->msg, rsp->msg_len);
		rsp_from_ta->msg_size = rsp->msg_len;
	}

	if (VTAB[target->vault.vtab_index].vault_level == VAULT_LEVEL1 || VTAB[target->vault.vtab_index].update_steady == true) {
		rsp_from_ta->req_steady.need_to_update = 1;
		rsp_from_ta->req_steady.need_to_update_2nd = rsp->req_steady.need_to_update_2nd;
		rsp_from_ta->req_steady.req_data_size = rsp->req_steady.req_data_size;
		rsp_from_ta->req_steady.req_data_size_2nd = rsp->req_steady.req_data_size_2nd;
		memcpy(rsp_from_ta->req_steady.req_data, rsp->req_steady.req_data, MAX_VAULT_LEN);
		memcpy(rsp_from_ta->req_steady.req_data_2nd, rsp->req_steady.req_data_2nd, MAX_VAULT_LEN);
	}

	return VK_SUCCESS;
}
