

#include <bluetooth/mesh.h>
#include "Keepalive.h"
#include "mesh/net.h"
#include "mesh/transport.h"
#include <string.h>

#include <logging/log.h>
LOG_MODULE_DECLARE(keepalive_model);

BUILD_ASSERT(BT_MESH_MODEL_BUF_LEN(BT_MESH_KEEPALIVE_OP_MESSAGE,
				   BT_MESH_KEEPALIVE_MSG_MAXLEN_MESSAGE) <=
		    BT_MESH_RX_SDU_MAX,
	     "The message must fit inside an application SDU.");
BUILD_ASSERT(BT_MESH_MODEL_BUF_LEN(BT_MESH_KEEPALIVE_OP_MESSAGE,
				   BT_MESH_KEEPALIVE_MSG_MAXLEN_MESSAGE) <=
		    BT_MESH_TX_SDU_MAX,
	     "The message must fit inside an application SDU.");

static void encode_presence(struct net_buf_simple *buf, enum bt_mesh_keepalive_presence presence)
{
	bt_mesh_model_msg_init(buf, BT_MESH_KEEPALIVE_OP_PRESENCE);
	net_buf_simple_add_u8(buf, presence);
}

static const uint8_t *extract_msg(struct net_buf_simple *buf)
{
	buf->data[buf->len - 1] = '\0';
	return net_buf_simple_pull_mem(buf, buf->len);
}

static void handle_message_PERIODIC_KEEPALIVE (struct bt_mesh_model *model,
			   struct bt_mesh_msg_ctx *ctx,
			   struct net_buf_simple *buf)
{
	struct bt_mesh_keepalive *keepalive_model = model->user_data;
	const uint8_t *msg;

	msg = extract_msg(buf);

	if (keepalive_model->handlers->message) {
		keepalive_model->handlers->message(keepalive_model, ctx, msg);
	}
}


/* .. include_startingpoint_keepalive_rst_2 */
const struct bt_mesh_model_op _bt_mesh_keepalive_op[] = {
	{
		BT_MESH_KEEPALIVE_OP_MESSAGE,
		BT_MESH_KEEPALIVE_MSG_MINLEN_MESSAGE,
		handle_message_PERIODIC_KEEPALIVE
	},
	BT_MESH_MODEL_OP_END,
};
/* .. include_endpoint_keepalive_rst_2 */

static int bt_mesh_keepalive_update_handler(struct bt_mesh_model *model)
{
	struct bt_mesh_keepalive *keepalive_model = model->user_data;

	/* Continue publishing current presence. */
	encode_presence(model->pub->msg, keepalive_model->presence);

	return 0;
}


/* .. include_endpoint_keepalive_rst_3 */

/* .. include_startingpoint_keepalive_rst_4 */
static int bt_mesh_keepalive_init(struct bt_mesh_model *model)
{
	struct bt_mesh_keepalive *keepalive_model = model->user_data;

	keepalive_model->model = model;

	net_buf_simple_init_with_data(&keepalive_model->pub_msg, keepalive_model->buf,
				      sizeof(keepalive_model->buf));
	keepalive_model->pub.msg = &keepalive_model->pub_msg;
	keepalive_model->pub.update = bt_mesh_keepalive_update_handler;

	return 0;
}
/* .. include_endpoint_keepalive_rst_4 */

/* .. include_startingpoint_keepalive_rst_5 */
static int bt_mesh_keepalive_start(struct bt_mesh_model *model)
{
	struct bt_mesh_keepalive *keepalive_model = model->user_data;

	if (keepalive_model->handlers->start) {
		keepalive_model->handlers->start(keepalive_model);
	}

	return 0;
}

/* .. include_endpoint_keepalive_rst_6 */

/* .. include_startingpoint_keepalive_rst_7 */
const struct bt_mesh_model_cb _bt_mesh_keepalive_cb = {
	.init = bt_mesh_keepalive_init,
	.start = bt_mesh_keepalive_start,

	//.reset = bt_mesh_keepalive_reset,
};
/* .. include_endpoint_keepalive_rst_7 */

/* .. include_startingpoint_keepalive_rst_8 */
int bt_mesh_keepalive_presence_set(struct bt_mesh_keepalive *keepalive_model,
			 enum bt_mesh_keepalive_presence presence)
{
	if (presence != keepalive_model->presence) {
		keepalive_model->presence = presence;

		if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
			(void) bt_mesh_model_data_store(keepalive_model->model, true,
						NULL, &presence,
						sizeof(keepalive_model->presence));
		}
	}

	encode_presence(keepalive_model->model->pub->msg, keepalive_model->presence);

	return bt_mesh_model_publish(keepalive_model->model);
}
/* .. include_endpoint_keepalive_rst_8 */

int bt_mesh_keepalive_presence_get(struct bt_mesh_keepalive *keepalive_model,
				  uint16_t addr)
{
	struct bt_mesh_msg_ctx ctx = {
		.addr = addr,
		.app_idx = keepalive_model->model->keys[0],
		.send_ttl = BT_MESH_TTL_DEFAULT,
		.send_rel = true,
	};

	BT_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_KEEPALIVE_OP_PRESENCE_GET,
				 BT_MESH_KEEPALIVE_MSG_LEN_PRESENCE_GET);
	bt_mesh_model_msg_init(&buf, BT_MESH_KEEPALIVE_OP_PRESENCE_GET);

	return bt_mesh_model_send(keepalive_model->model, &ctx, &buf, NULL, NULL);
}

int bt_mesh_keepalive_message_send(struct bt_mesh_keepalive *keepalive_model,
				  const uint8_t *msg)
{
	struct net_buf_simple *buf = keepalive_model->model->pub->msg;

	bt_mesh_model_msg_init(buf, BT_MESH_KEEPALIVE_OP_MESSAGE);

	net_buf_simple_add_mem(buf, msg,
			       strnlen(msg,
				       CONFIG_BT_MESH_KEEPALIVE_MESSAGE_LENGTH));
	net_buf_simple_add_u8(buf, '\0');

	return bt_mesh_model_publish(keepalive_model->model);
}

/* .. include_startingpoint_keepalive_rst_9 */
int bt_mesh_keepalive_private_message_send(struct bt_mesh_keepalive *keepalive_model,
					  uint16_t addr,
					  const uint8_t *msg)
{
	struct bt_mesh_msg_ctx ctx = {
		.addr = addr,
		.app_idx = keepalive_model->model->keys[0],
		.send_ttl = BT_MESH_TTL_DEFAULT,
		.send_rel = true,
	};

	BT_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_KEEPALIVE_OP_PRIVATE_MESSAGE,
				 BT_MESH_KEEPALIVE_MSG_MAXLEN_MESSAGE);
	bt_mesh_model_msg_init(&buf, BT_MESH_KEEPALIVE_OP_PRIVATE_MESSAGE);

	net_buf_simple_add_mem(&buf, msg,
			       strnlen(msg,
				       CONFIG_BT_MESH_KEEPALIVE_MESSAGE_LENGTH));
	net_buf_simple_add_u8(&buf, '\0');

	return bt_mesh_model_send(keepalive_model->model, &ctx, &buf, NULL, NULL);
}
/* .. include_endpoint_keepalive_rst_9 */
a