/*
 * Copyright (c) 2022 Nordic Semiconductor ASA
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include "mesh_cfg.h"
#include "api/mesh.h"

#include "foundation.h"
#include "op_agg.h"

#define LOG_LEVEL CONFIG_BT_MESH_MODEL_LOG_LEVEL
#include "api/mesh_log.h"

#if (CONFIG_BT_MESH_OP_AGG)

#define IS_LENGTH_LONG(buf) ((buf)->data[0] & 1)
#define LENGTH_SHORT_MAX BIT_MASK(7)

int bt_mesh_op_agg_encode_msg(struct net_buf_simple *msg, struct net_buf_simple *buf)
{
	if (msg->len > LENGTH_SHORT_MAX) {
		if (net_buf_simple_tailroom(buf) < (msg->len + 2)) {
			return -ENOMEM;
		}

		net_buf_simple_add_le16(buf, (msg->len << 1) | 1);
	} else {
		if (net_buf_simple_tailroom(buf) < (msg->len + 1)) {
			return -ENOMEM;
		}

		net_buf_simple_add_u8(buf, msg->len << 1);
	}
	net_buf_simple_add_mem(buf, msg->data, msg->len);

	return 0;
}

int bt_mesh_op_agg_decode_msg(struct net_buf_simple *msg,
			      struct net_buf_simple *buf)
{
	uint16_t len;

	if (IS_LENGTH_LONG(buf)) {
		if (buf->len < 2) {
			return -EINVAL;
		}

		len = net_buf_simple_pull_le16(buf) >> 1;
	} else {
		if (buf->len < 1) {
			return -EINVAL;
		}

		len = net_buf_simple_pull_u8(buf) >> 1;
	}

	if (buf->len < len) {
		return -EINVAL;
	}

	net_buf_simple_init_with_data(msg, net_buf_simple_pull_mem(buf, len), len);

	return 0;
}

bool bt_mesh_op_agg_is_op_agg_msg(struct net_buf_simple *buf)
{
	if (buf->len >= 2 && (buf->data[0] >> 6) == 2) {
		uint16_t opcode;
		struct net_buf_simple_state state;

		net_buf_simple_save(buf, &state);
		opcode = net_buf_simple_pull_be16(buf);
		net_buf_simple_restore(buf, &state);

		if ((opcode == OP_OPCODES_AGGREGATOR_STATUS) ||
		    (opcode == OP_OPCODES_AGGREGATOR_SEQUENCE)) {
			return true;
		}
	}
	return false;
}

#endif // CONFIG_BT_MESH_OP_AGG