#include <stdint.h>
#include <stddef.h>
#include <stdlib.h>

#include "VaultKeeperAPI.h"
#include "IVaultKeeper.h"
#include "object.h"

#include "qsee_env.h"
#include "qsee_log.h"
#include "qsee_time.h"

#include "vk_constants.h"

#define CMD_PROTOCOL CMD_PROTOCOL_TA

#define VK_SUCCESS           0
#define VK_ERR_OPEN_FAIL    -1

extern char TZ_APP_NAME[];

static Object obj = { NULL, NULL };
static int32_t err;

static int generate_cmd_no()
{
	// To observe between TAs, Generate command number. (Range:1~9999);
	// coverd milliseconds
	srand(time_getmsec());

	return rand() % 9999 + 1;
}

static int open_vk_obj()
{
	err = qsee_open(VK_UID, &obj);
	if (!Object_isOK(err) || Object_isNull(obj)) {
		obj = Object_NULL;
		return err;
	}
	return VK_SUCCESS;
}

static void release_vk_obj()
{
	if (!Object_isNull(obj)) {
		IVaultKeeper_release(obj);
	}
}

int vk_read_sbox(const uint32_t sbox_type, void* out_data, size_t out_data_len, size_t* out_data_lenout)
{
	int ret;
	int cmd_no = 0;
	const char prefix_name[] = {"TA_"};
	char ta_client_name[MAX_CLIENT_NAME_LEN + 3] = {0,};

	cmd_no = generate_cmd_no();

	qsee_log(QSEE_LOG_MSG_ERROR, "[%s:VaultKeeper] Reqeust to read sbox(%d/%d)", TZ_APP_NAME, sbox_type, cmd_no);

	if (out_data == NULL || out_data_len <= 0 || out_data_len > MAX_TA_BUFFER_LEN) {
		qsee_log(QSEE_LOG_MSG_ERROR, "[%s:VaultKeeper] Invalid parameter\n", TZ_APP_NAME);
		ret = VK_ERR_OPEN_FAIL;
		goto out;
	}

	memcpy(ta_client_name, prefix_name, 3);
	memcpy(ta_client_name + 3, TZ_APP_NAME, strlen(TZ_APP_NAME));

	if ((ret = open_vk_obj()) != VK_SUCCESS) {
		qsee_log(QSEE_LOG_MSG_ERROR, "[%s:VaultKeeper] Failed to connect VK service(%d/%d)", TZ_APP_NAME, cmd_no, ret);
		ret = VK_ERR_OPEN_FAIL;
		goto out;
	}

	ret = IVaultKeeper_readSbox(obj, CMD_PROTOCOL, cmd_no, ta_client_name, strlen(ta_client_name),
                                 sbox_type, out_data, out_data_len, out_data_lenout);

	// Object error
	if (ret > 0 || ret <= -90) {
		qsee_log(QSEE_LOG_MSG_ERROR, "[%s:VaultKeeper] Occure qsee object errors(%d/%d)", TZ_APP_NAME, cmd_no, ret);
		ret = VK_ERR_OPEN_FAIL;
		goto out;
	}

	if (ret < 0) ret -= 1;

out:
	release_vk_obj();
	return ret;
}

int vk_read_vault(const uint32_t vault_type, void* out_data, size_t out_data_len, size_t* out_data_lenout)
{
	int ret;
	int cmd_no = 0;
	const char prefix_name[] = {"TA_"};
	char ta_client_name[MAX_CLIENT_NAME_LEN + 3] = {0,};

	cmd_no = generate_cmd_no();

	qsee_log(QSEE_LOG_MSG_ERROR, "[%s:VaultKeeper] Reqeust to read vault(%d/%d)", TZ_APP_NAME, vault_type, cmd_no);

	if (out_data == NULL || out_data_len <= 0 || out_data_len > MAX_TA_BUFFER_LEN) {
		qsee_log(QSEE_LOG_MSG_ERROR, "[%s:VaultKeeper] Invalid parameter\n");
		ret = VK_ERR_OPEN_FAIL;
		goto out;
	}

	memcpy(ta_client_name, prefix_name, 3);
	memcpy(ta_client_name + 3, TZ_APP_NAME, strlen(TZ_APP_NAME));

	if ((ret = open_vk_obj()) != VK_SUCCESS) {
		qsee_log(QSEE_LOG_MSG_ERROR, "[%s:VaultKeeper] Failed to connect VK service(%d/%d)", TZ_APP_NAME, cmd_no, ret);
		ret = VK_ERR_OPEN_FAIL;
		goto out;
	}

	ret = IVaultKeeper_readVault(obj, CMD_PROTOCOL, cmd_no, ta_client_name, strlen(ta_client_name),
                                 vault_type, out_data, out_data_len, out_data_lenout);

	// Object error
	if (ret > 0 || ret <= -90) {
		qsee_log(QSEE_LOG_MSG_ERROR, "[%s:VaultKeeper] Occure qsee object errors(%d/%d)", TZ_APP_NAME, cmd_no, ret);
		ret = VK_ERR_OPEN_FAIL;
		goto out;
	}

	if (ret < 0) ret -= 1;

out:
	release_vk_obj();
	return ret;
}

int vk_write_vault(const uint32_t vault_type, const void* in_data, size_t in_data_len)
{
	int ret;
	int cmd_no = 0;
	const char prefix_name[] = {"TA_"};
	char ta_client_name[MAX_CLIENT_NAME_LEN + 3] = {0,};

	cmd_no = generate_cmd_no();

	qsee_log(QSEE_LOG_MSG_ERROR, "[%s:VaultKeeper] Reqeust to write vault(%d/%d)", TZ_APP_NAME, vault_type, cmd_no);

	if (in_data == NULL || in_data_len <= 0 || in_data_len > MAX_TA_BUFFER_LEN) {
		qsee_log(QSEE_LOG_MSG_ERROR, "[%s:VaultKeeper] Invalid parameter\n", TZ_APP_NAME);
		ret = VK_ERR_OPEN_FAIL;
		goto out;
	}

	memcpy(ta_client_name, prefix_name, 3);
	memcpy(ta_client_name + 3, TZ_APP_NAME, strlen(TZ_APP_NAME));

	if ((ret = open_vk_obj()) != VK_SUCCESS) {
		qsee_log(QSEE_LOG_MSG_ERROR, "[%s:VaultKeeper] Failed to connect VK service(%d/%d)", TZ_APP_NAME, cmd_no, ret);
		ret = VK_ERR_OPEN_FAIL;
		goto out;
	}

	ret = IVaultKeeper_writeVault(obj, CMD_PROTOCOL, cmd_no, ta_client_name, strlen(ta_client_name),
                                 vault_type, in_data, in_data_len);

	// Object error
	if (ret > 0 || ret <= -90) {
		qsee_log(QSEE_LOG_MSG_ERROR, "[%s:VaultKeeper] Occure qsee object errors(%d/%d)", TZ_APP_NAME, cmd_no, ret);
		ret = VK_ERR_OPEN_FAIL;
		goto out;
	}

	if (ret < 0) ret -= 1;

out:
	release_vk_obj();
	return ret;
}

