/*
 * Copyright (C) 2019 SAMSUNG S.LSI
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifdef ESE_U_BOOT_BUILD
#include <linux/string.h>
#include <malloc.h>
#else
#include <stdlib.h>
#include <string.h>
#endif

#include <ese_log.h>
#include <ese_util.h>
#include "ese_data.h"

#define LOG_TAG "ESE_DATA"
#define RELEASE_BUILD

#ifdef RELEASE_BUILD
#define API
#else
#define API __attribute__((visibility("default")))
#endif

static int32_t _eseData_getDataFromList(p_recv_buff_list_t head, uint8_t *buff, uint32_t *data_len)
{
	recv_buff_list_t *cur_node;
	uint32_t offset = 0;

	if (head == NULL || buff == NULL) {
		return -1;
	}

	cur_node = head->next;
	while (cur_node != NULL) {
		if (offset + cur_node->data.len > head->data.len)
			break;
		memcpy((buff + offset), cur_node->data.buffer, cur_node->data.len);
		offset += cur_node->data.len;
		cur_node = cur_node->next;
	}
	*data_len = offset;
	return 0;
}

static int32_t _eseData_deletList(p_recv_buff_list_t head)
{
	recv_buff_list_t *current, *next;

	if (head == NULL) {
		return -1;
	}

	current = head->next;
	while (current != NULL) {
		next = current->next;
		ESE_FREE(current->data.buffer);
		ESE_FREE(current);
		current = NULL;
		current = next;
	}

	head->next = NULL;
	head->data.buffer = NULL;
	head->data.len = 0;
	return 0;
}

API ESE_STATUS eseData_getData(p_recv_buff_list_t head, uint8_t **buffer, uint32_t *data_len)
{
	uint32_t total_data_len = 0;
	uint8_t* buff = NULL;

	if (buffer != NULL && data_len != NULL) {
		if (head->data.len == 0) {
			*buffer = NULL;
			*data_len = 0;
			return ESESTATUS_SUCCESS;
		}

		buff = ESE_MALLOC(head->data.len);
		if (buff == NULL) {
			ESELOG_E("%s Error in malloc ", __FUNCTION__);
			return ESESTATUS_INSUFFICIENT_RESOURCES;
		}

		if (_eseData_getDataFromList(head, buff, &total_data_len) != 0) {
			ESELOG_E("ese_getDataFromList is failed");
			ESE_FREE(buff);
			return ESESTATUS_INVALID_RECEIVE_LENGTH;
		}

		if (total_data_len != head->data.len) {
			ESELOG_E("%s Mismatch of len total_data_len %d g_total_len %d", __FUNCTION__,
					total_data_len, head->data.len);
			ESE_FREE(buff);
			return ESESTATUS_INVALID_RECEIVE_LENGTH;
		}
		*buffer = buff;
		*data_len = total_data_len;
	}

	if (_eseData_deletList(head) < 0) {
		return ESESTATUS_INSUFFICIENT_RESOURCES;
	}
	return ESESTATUS_SUCCESS;
}

API ESE_STATUS eseData_storeData(p_recv_buff_list_t head, uint8_t *buff, uint32_t data_len, uint8_t copy)
{
	p_recv_buff_list_t new_node = NULL;
	p_recv_buff_list_t cur_node = NULL;

	new_node = ESE_MALLOC(sizeof(recv_buff_list_t));
	if (new_node == NULL) {
		return ESESTATUS_INSUFFICIENT_RESOURCES;
	}

	new_node->next = NULL;
	new_node->data.len = data_len;
	if (copy) {
		new_node->data.buffer = ESE_MALLOC(data_len);
		if (new_node->data.buffer == NULL) {
			ESE_FREE(new_node);
			return ESESTATUS_INSUFFICIENT_RESOURCES;
		}
		memcpy(new_node->data.buffer, buff, data_len);
	} else {
		new_node->data.buffer = buff;
	}

	cur_node = head;
	while (cur_node->next != NULL) {
		cur_node = cur_node->next;
	}

	cur_node->next = new_node;
	head->data.len += data_len;
	return ESESTATUS_SUCCESS;
}
