/* Copyright 2020 The Fuchsia Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include "common.h"

#include <factory_boot_kvs.h>
#include <cbor/cbor.h>
#include <cn-cbor/cn-cbor.h>

static cn_cbor* s_cbor_head = NULL;
static uint8_t s_buf[FACTORY_BOOT_KVS_SIZE] __attribute__ ((aligned(16))) = {0};

FbKvsResult FbKvsInit(FbKvsOps* op)
{
	cn_cbor_errback err;
	if ((op == NULL) || (op->read == NULL)) {
		FB_KVS_ERROR("INVALID args.\n");
		return kFbKvsResultInvalidArg;
	}

	if (s_cbor_head != NULL) {
		FB_KVS_ERROR("factory boot is already initialized\n");
		return kFbKvsResultOk;
	}

	FbKvsResult ret = op->read(s_buf, FACTORY_BOOT_KVS_SIZE);
	if (ret != kFbKvsResultOk) {
		FB_KVS_ERROR("failed to read data: %d\n", ret);
		return kFbKvsResultInvalid;
	}

	s_cbor_head = cn_cbor_decode(s_buf, FACTORY_BOOT_KVS_SIZE, &err);
	if (s_cbor_head == NULL) {
		/* check if the call failed because there is a padding at the end of data.
		 * Re-run decoding in this case
		 */
		if ((err.err == CN_CBOR_ERR_NOT_ALL_DATA_CONSUMED) && (err.pos != 0)) {
			s_cbor_head = cn_cbor_decode(s_buf, err.pos, &err);
		}

		if (s_cbor_head == NULL) {
			FB_KVS_ERROR("failed to parse data: position %zu, error %d\n", err.pos, err.err);
			return kFbKvsResultInvalidData;
		}
	}

	return kFbKvsResultOk;
}

void FbKvsDeinit(void)
{
	if (s_cbor_head == NULL) {
		cn_cbor_free(s_cbor_head);
		s_cbor_head = NULL;
	}
}

FbKvsResult FbKvsGetNumberOfPairs(size_t* size)
{
	cn_cbor* cp = NULL;
	size_t num = 0;

	if (s_cbor_head == NULL) {
		return kFbKvsResultErrorNotInitialized;
	}

	if (size == NULL) {
		return kFbKvsResultInvalidArg;
	}

	*size = 0;

	/* counts keys and values together. should be even number */
	for (cp = s_cbor_head->first_child; cp; cp = cp->next) {
		num++;
	}

	/* fail if there are odd number of items */
	if (num & 1) {
		return kFbKvsResultInvalid;
	}

	*size = num/2;

	return kFbKvsResultOk;
}

FbKvsResult FbKvsGetKeyByIndex(uint32_t index, char* key, size_t size)
{
	if (s_cbor_head == NULL) {
		return kFbKvsResultErrorNotInitialized;
	}

	if ((key == NULL) || (size == 0)) {
		return kFbKvsResultInvalidArg;
	}

	/* get a key info */
	cn_cbor* k = cn_cbor_index(s_cbor_head, index*2);
	if (k == NULL) {
		return kFbKvsResultNotFound;
	}

	if (k->type != CN_CBOR_TEXT) {
		return kFbKvsResultInvalidData;
	}

	if ((size_t)(k->length + 1) > size) {
		return kFbKvsResultBufTooSmall;
	}

	memcpy(key, k->v.str, k->length);
	key[k->length] = '\0';

	return kFbKvsResultOk;
}

FbKvsResult FbKvsGetValueSize(const char* key, size_t* size)
{
	if (s_cbor_head == NULL) {
		return kFbKvsResultErrorNotInitialized;
	}

	if ((key == NULL) || (size == NULL)) {
		return kFbKvsResultInvalidArg;
	}

	cn_cbor* cb = cn_cbor_mapget_string(s_cbor_head, key);
	if (cb == NULL) {
		return kFbKvsResultNotFound;
	}

	switch (cb->type) {
		case CN_CBOR_UINT:
			*size = sizeof(uint64_t);
			break;
		case CN_CBOR_INT:
			*size = sizeof(int64_t);
			break;
		case CN_CBOR_BYTES:
			*size = cb->length;
			break;
		case CN_CBOR_TEXT:
			*size = cb->length + 1;
			break;
		default:
			return kFbKvsResultInvalidData;
	}

	return kFbKvsResultOk;
}

FbKvsResult FbKvsGetValueType(const char* key, FbKvsValueType* type)
{
	if (s_cbor_head == NULL) {
		return kFbKvsResultErrorNotInitialized;
	}

	if ((key == NULL) || (type == NULL)) {
		return kFbKvsResultInvalidArg;
	}

	cn_cbor* cb = cn_cbor_mapget_string(s_cbor_head, key);
	if (cb == NULL) {
		return kFbKvsResultNotFound;
	}

	switch (cb->type) {
		case CN_CBOR_UINT:
			*type = kFbKvsTypeULong;
			break;
		case CN_CBOR_INT:
			*type = kFbKvsTypeLong;
			break;
		case CN_CBOR_BYTES:
			*type = kFbKvsTypeData;
			break;
		case CN_CBOR_TEXT:
			*type = kFbKvsTypeString;
			break;
		default:
			return kFbKvsResultInvalid;
	}

	return kFbKvsResultOk;
}

FbKvsResult FbKvsGetString(const char* key, char* value, size_t* size)
{
	if (s_cbor_head == NULL) {
		return kFbKvsResultErrorNotInitialized;
	}

	if ((key == NULL) || (value == NULL) || (size == NULL) || (*size == 0)) {
		return kFbKvsResultInvalidArg;
	}

	cn_cbor* cb = cn_cbor_mapget_string(s_cbor_head, key);
	if (cb == NULL) {
		return kFbKvsResultNotFound;
	}

	if (cb->type != CN_CBOR_TEXT) {
		return kFbKvsResultTypeMismatch;
	}

	if ((size_t)(cb->length + 1) > *size) {
		return kFbKvsResultBufTooSmall;
	}

	memcpy(value, cb->v.str, cb->length);
	value[cb->length] = '\0';
	*size = cb->length + 1;

	return kFbKvsResultOk;
}

FbKvsResult FbKvsGetLong(const char* key, int64_t* value)
{
	if (s_cbor_head == NULL) {
		return kFbKvsResultErrorNotInitialized;
	}

	if ((key == NULL) || (value == NULL)) {
		return kFbKvsResultInvalidArg;
	}

	cn_cbor* cb = cn_cbor_mapget_string(s_cbor_head, key);
	if (cb == NULL) {
		return kFbKvsResultNotFound;
	}

	switch (cb->type) {
		case CN_CBOR_INT:
			*value = cb->v.sint;
			break;
		default:
			return kFbKvsResultTypeMismatch;
	}

	return kFbKvsResultOk;
}

FbKvsResult FbKvsGetULong(const char* key, uint64_t* value)
{
	if (s_cbor_head == NULL) {
		return kFbKvsResultErrorNotInitialized;
	}

	if ((key == NULL) || (value == NULL)) {
		return kFbKvsResultInvalidArg;
	}

	cn_cbor* cb = cn_cbor_mapget_string(s_cbor_head, key);
	if (cb == NULL) {
		return kFbKvsResultNotFound;
	}

	switch (cb->type) {
		case CN_CBOR_UINT:
			*value = cb->v.uint;
			break;
		default:
			return kFbKvsResultTypeMismatch;
	}

	return kFbKvsResultOk;
}

FbKvsResult FbKvsGetData(const char* key, uint8_t* value, size_t* size)
{
	if (s_cbor_head == NULL) {
		return kFbKvsResultErrorNotInitialized;
	}

	if ((key == NULL) || (value == NULL) || (size == NULL) || (*size == 0)) {
		return kFbKvsResultInvalidArg;
	}

	cn_cbor* cb = cn_cbor_mapget_string(s_cbor_head, key);
	if (cb == NULL) {
		return kFbKvsResultNotFound;
	}

	if (cb->type != CN_CBOR_BYTES) {
		return kFbKvsResultTypeMismatch;
	}

	if ((size_t)cb->length > *size) {
		return kFbKvsResultBufTooSmall;
	}

	memcpy(value, cb->v.bytes, cb->length);
	*size = cb->length;

	return kFbKvsResultOk;
}
