/*
 * Copyright (c) 2016 Intel Corporation
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <errno.h>
#include <misc/printk.h>

#include <zephyr.h>

#include <misc/byteorder.h>
#include <net/buf.h>
#include <net/net_pkt.h>
#include <net/net_mgmt.h>
#include <net/net_ip.h>
#include <net/udp.h>
#include <net/coap.h>

#define MY_COAP_PORT 5683

#define NUM_PENDINGS 3
#define NUM_REPLIES 3

#define ALL_NODES_LOCAL_COAP_MCAST \
	{ { { 0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xfd } } }

static const struct sockaddr_in6 mcast_addr = {
	.sin6_addr = ALL_NODES_LOCAL_COAP_MCAST,
	.sin6_family = AF_INET6,
	.sin6_port = htons(MY_COAP_PORT)};

static struct net_context *context;

struct coap_pending pendings[NUM_PENDINGS];
struct coap_reply replies[NUM_REPLIES];
struct k_delayed_work retransmit_work;

#if defined(CONFIG_NET_MGMT_EVENT)
static struct net_mgmt_event_callback cb;
#endif

static const char * const test_path[] = { "test", NULL };

static void msg_dump(const char *s, u8_t *data, unsigned len)
{
	unsigned i;

	printk("%s: ", s);
	for (i = 0; i < len; i++)
		printk("%02x ", data[i]);
	printk("(%u bytes)\n", len);
}

static int resource_reply_cb(const struct coap_packet *response,
			     struct coap_reply *reply,
			     const struct sockaddr *from)
{
	struct net_pkt *pkt = response->pkt;

	msg_dump("reply", pkt->frags->data, pkt->frags->len);

	return 0;
}

static void get_from_ip_addr(struct coap_packet *cpkt,
			     struct sockaddr_in6 *from)
{
	struct net_udp_hdr hdr, *udp_hdr;

	udp_hdr = net_udp_get_hdr(cpkt->pkt, &hdr);
	if (!udp_hdr) {
		return;
	}

	net_ipaddr_copy(&from->sin6_addr, &NET_IPV6_HDR(cpkt->pkt)->src);
	from->sin6_port = udp_hdr->src_port;
	from->sin6_family = AF_INET6;
}

static void udp_receive(struct net_context *context,
			struct net_pkt *pkt,
			int status,
			void *user_data)
{
	struct coap_pending *pending;
	struct coap_reply *reply;
	struct coap_packet response;
	struct sockaddr_in6 from;
	int r;

	r = coap_packet_parse(&response, pkt, NULL, 0);
	if (r < 0) {
		printk("Invalid data received (%d)\n", r);
		return;
	}

	pending = coap_pending_received(&response, pendings,
					NUM_PENDINGS);
	if (pending) {
		/* If necessary cancel retransmissions */
	}

	get_from_ip_addr(&response, &from);
	reply = coap_response_received(&response,
				       (const struct sockaddr *) &from,
				       replies, NUM_REPLIES);
	if (!reply) {
		printk("No handler for response (%d)\n", r);
		return;
	}
}

static void retransmit_request(struct k_work *work)
{
	struct coap_pending *pending;
	int r;
	bool last_retransmit;

	pending = coap_pending_next_to_expire(pendings, NUM_PENDINGS);
	if (!pending) {
		return;
	}

	last_retransmit = !coap_pending_cycle(pending);

	r = net_context_sendto(pending->pkt, (struct sockaddr *) &mcast_addr,
			       sizeof(mcast_addr), NULL, 0, NULL, NULL);
	if (r < 0) {
		coap_pending_clear(pending);
		return;
	}

	if (last_retransmit) {
		/* packet buffer will be freed when packet is sent */
		pending->timeout = 0;
		pending->pkt = NULL;
		return;
	}

	k_delayed_work_submit(&retransmit_work, pending->timeout);
}

static void event_iface_up(struct net_mgmt_event_callback *cb,
			   u32_t mgmt_event, struct net_if *iface)
{
	static struct sockaddr_in6 any_addr = { .sin6_addr = IN6ADDR_ANY_INIT,
						.sin6_family = AF_INET6 };
	struct coap_packet request;
	struct coap_pending *pending;
	struct coap_reply *reply;
	const char * const *p;
	struct net_pkt *pkt;
	struct net_buf *frag;
	int r;
	u8_t observe = 0;

	r = net_context_get(PF_INET6, SOCK_DGRAM, IPPROTO_UDP, &context);
	if (r) {
		printk("Could not get an UDP context\n");
		return;
	}

	r = net_context_bind(context, (struct sockaddr *) &any_addr,
			     sizeof(any_addr));
	if (r) {
		printk("Could not bind the context\n");
		return;
	}

	r = net_context_recv(context, udp_receive, 0, NULL);
	if (r) {
		printk("Could not receive in the context\n");
		return;
	}

	k_delayed_work_init(&retransmit_work, retransmit_request);

	pkt = net_pkt_get_tx(context, K_FOREVER);
	if (!pkt) {
		printk("Unable to get TX packet, not enough memory.\n");
		return;
	}

	frag = net_pkt_get_data(context, K_FOREVER);
	if (!frag) {
		printk("Unable to get DATA buffer, not enough memory.\n");
		return;
	}

	net_pkt_frag_add(pkt, frag);

	r = coap_packet_init(&request, pkt, 1, COAP_TYPE_CON,
			     8, coap_next_token(),
			     COAP_METHOD_GET, coap_next_id());
	if (r < 0) {
		return;
	}

	/* Enable observing the resource. */
	r = coap_packet_append_option(&request, COAP_OPTION_OBSERVE,
				      &observe, sizeof(observe));
	if (r < 0) {
		printk("Unable add option to request.\n");
		return;
	}

	for (p = test_path; p && *p; p++) {
		r = coap_packet_append_option(&request, COAP_OPTION_URI_PATH,
					      *p, strlen(*p));
		if (r < 0) {
			printk("Unable add option to request.\n");
			return;
		}
	}

	pending = coap_pending_next_unused(pendings, NUM_PENDINGS);
	if (!pending) {
		printk("Unable to find a free pending to track "
		       "retransmissions.\n");
		return;
	}

	r = coap_pending_init(pending, &request,
			      (struct sockaddr *) &mcast_addr);
	if (r < 0) {
		printk("Unable to initialize a pending retransmission.\n");
		return;
	}

	reply = coap_reply_next_unused(replies, NUM_REPLIES);
	if (!reply) {
		printk("No resources for waiting for replies.\n");
		return;
	}

	coap_reply_init(reply, &request);
	reply->reply = resource_reply_cb;

	/* Increase packet ref count to avoid being unref after sendto() */
	coap_pending_cycle(pending);

	r = net_context_sendto(pkt, (struct sockaddr *) &mcast_addr,
			       sizeof(mcast_addr),
			       NULL, 0, NULL, NULL);
	if (r < 0) {
		printk("Error sending the packet (%d).\n", r);
		coap_pending_clear(pending);
		return;
	}

	k_delayed_work_submit(&retransmit_work, pending->timeout);

}

void main(void)
{
	struct net_if *iface = net_if_get_default();

#if defined(CONFIG_NET_MGMT_EVENT)
	/* Subscribe to NET_IF_UP if interface is not ready */
	if (!atomic_test_bit(iface->flags, NET_IF_UP)) {
		net_mgmt_init_event_callback(&cb, event_iface_up,
					     NET_EVENT_IF_UP);
		net_mgmt_add_event_callback(&cb);
		return;
	}
#endif

	event_iface_up(NULL, NET_EVENT_IF_UP, iface);
}
