#include <sys/types.h>
#include <inttypes.h>

#include "nodes.h"
#include "commands.h"
#include "bitwise.h"


enum GetnodeData {
	GN_DATA_SIZE
};


/* Creates data and metadata for a getnodes packet.
 * Returns data size.
 */
ssize_t EncodeGetNodes(
		struct metadata *m, /* Out */
		uint8_t *data,      /* Out */
		size_t data_size,   /* Data buffer max size */
		const char * msg)  /* Value is not used; only IDs */
{
	m->msg_type = GETNODES_ID;
	m->data_len = GN_DATA_SIZE;

	return GN_DATA_SIZE;
}

enum AddnodeData {
	AN_TYPE_ID_L,
	AN_TYPE_ID_H,
	AN_NAME,
	AN_MIN_DATA_SIZE
};

/* Creates data and metadata for a addnode packet
 * Returns data size.
 */
ssize_t EncodeAddNode(
		struct metadata * m,        /* data_len and msg_type will be populated*/
		uint8_t * data,             /* Output buffer */
		size_t data_size,           /* Max buffer size */
		const char * msg)      /* Message to encode */
{
	m->msg_type = ADDNODE_ID;
	
	if (data_size < AN_MIN_DATA_SIZE) {
		return -1;
	}

	int16_t type;
	char name[512];

	memset(name, 0, 512);

	sscanf(msg, "addnode %" SCNd16 " %512c", &type, name);

	printf("found name '%s'\n", name);

	data[AN_TYPE_ID_L] = LSByte16(type);
	data[AN_TYPE_ID_H] = MSByte16(type);
	
	memcpy(&data[AN_NAME], name, strlen(name) + 1); // We want to include the null byte
	
	m->data_len = AN_MIN_DATA_SIZE + strlen(name);

	return m->data_len;
}

enum ResponseGetnodesData {
	RESP_GN_NUM_NODES_L,
	RESP_GN_NUM_NODES_H,
	RESP_GN_MIN_DATA_SIZE
};

static int resizeMsg(char **msg_ptr, int *curr_max, int check_val) {
	/* resize the msg if necessary */
	if (*curr_max < check_val) {
		*curr_max = *curr_max * 4;
		*msg_ptr = realloc(*msg_ptr, sizeof(**msg_ptr) * *curr_max);
		if (!msg_ptr) {
			return -1;
		}
	}
	return 0;
}

/* Decode a metadata and data to populate a.
 * Returns bytes written to msg, -1 on failure.
 */
int DecodeResponseGetNodes(
		char * msg, 				   /* Out */
		size_t max_len,				   /* msg buffer max size */
		const struct metadata *m,      /* In */
		const uint8_t * data)	      /* In */
{
	/* See if we have the min. amount */
	if (m->data_len < RESP_GN_MIN_DATA_SIZE) {
		return -1;
	}
	if (m->msg_type != RESPNODES_ID) {
		return -1;
	}

	uint16_t num_nodes = BytesTo16(data[RESP_GN_NUM_NODES_L], data[RESP_GN_NUM_NODES_H]);
	
	if (resizeMsg(&msg, (int *)&max_len, (m->data_len *2)) == -1) {
		return -1;
	}

	int16_t val;
	char name[512] = "";/* Corresponding to the maximum name len that the frontend will accept */
	size_t i;
	int msg_len = 0, msg_offset = 0, data_offset = RESP_GN_MIN_DATA_SIZE;

	sprintf(msg, "getnodes %hu %n", num_nodes, &msg_offset);
	msg_len += msg_offset;


	for(i = 0; i < num_nodes * 3; ++i) {
		if (i < num_nodes * 2) {
			val = BytesTo16(data[data_offset], data[data_offset+1]);
			data_offset += 2;
			sprintf(&msg[msg_len], "%" PRId16 " %n", val, &msg_offset);
		} else {
			strncpy(name, (char *) (data + data_offset), 512);
			data_offset += strlen(name) + 1;
			sprintf(&msg[msg_len], "'%s' %n", name, &msg_offset);
		}
		msg_len += msg_offset;


		if (resizeMsg(&msg, (int *)&max_len, msg_len + (msg_offset *2)) == -1) {
			return -1;
		}
	}
	strcat(&msg[msg_len], "\n");
	return strlen(msg);
}

enum ResponseAddnodeData {
	RESP_AN_BLOCK_ID_L,
	RESP_AN_BLOCK_ID_H,
	RESP_AN_DATA_SIZE
};

/* Decode a metadata and data to populate a controller.
 * Returns bytes written to msg, -1 on failure.
 */
int DecodeResponseAddNode(
		char * msg, 				   /* Out */
		size_t max_len,				   /* msg buffer max size */
		const struct metadata *m,      /* In */
		const uint8_t * data)         /* In */
{
	if (m->data_len < RESP_AN_DATA_SIZE) {
		return -1;
	}
	if (m->msg_type != RESPADDNODE_ID) {
		return -1;
	}
	
	return sprintf(msg, "addnode %d\n", 
		BytesTo16(data[RESP_AN_BLOCK_ID_L], data[RESP_AN_BLOCK_ID_H]));
}