#ifdef __linux__
#define __STDC_FORMAT_MACROS
#include <inttypes.h>
#else
typedef __int32 int32_t;
typedef unsigned __int32 uint32_t;
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
#define PRIu64       "I64u"
#define PRIx64       "I64x"
#endif

#include "CppUTest/TestHarness.h"

extern "C"
{
#include <stdio.h>
#include <string.h>
#include <stdint.h>

#include "mrp_doubles.h"
#include "mrp.h"
#include "mvrp.h"
#include "parse.h"

/* Most MVRP commands operate on the global DB */
extern struct mvrp_database *MVRP_db;

void mvrp_event_observer(int event, struct mvrp_attribute *attr);
char *mvrp_attrib_type_string(int t);
char *mrp_event_string(int e);
}

/* This include file contains all the byte buffers implementing
 * packets for the tests */
#include "sample_mvrp_packets.h"

/* Needed for mvrp_recv_cmd() */
static struct sockaddr_in client;

/*
 * The test_state keeps track of counts of all events that are
 * triggered during a test, and these functions show how to read
 * them.
 */

static void mvrp_dump_events() {
	int i, evtid, evtcount;
	evtcount = (sizeof test_state.mvrp_event_counts /
		    sizeof *test_state.mvrp_event_counts);
	printf("\nMVRP Event Counts:\n");
	for (i = 0; i < evtcount; i++) {
		if (test_state.mvrp_event_counts[i] > 0) {
			printf("%s: %d\n", mrp_event_string(MSRP_EVENT_ID(i)),
			       test_state.mvrp_event_counts[i]);
		}
	}
}

static int mvrp_count_events() {
	int i, total, evtcount;
	evtcount = (sizeof test_state.mvrp_event_counts /
		    sizeof *test_state.mvrp_event_counts);
	total = 0;
	for (i = 0; i < evtcount; i++) {
		total += test_state.mvrp_event_counts[i];
	}
	return total;
}

int mvrp_tests_cmd_ok(const char *zstr)
{
	int status;

	status = (zstr[0] != 'E') && (zstr[1] != 'R');

	return status;
}

/* A sample event observer; this is called on every event generated by
 * the mvrp_recv_msg function, so each attribute parsed will be passed
 * to it in turn and can be analyzed. The following line inserted into
 * a test will enable it:
 *
 * test_state.mvrp_observe = mvrp_event_observer;
 */
void mvrp_event_observer(int event, struct mvrp_attribute *attr)
{
	printf("Event: %s vlan: %02d",
	       mrp_event_string(event),
	       attr->attribute);
}

/* Test doubles for the mrpd functionality enable feeding PDU buffers
 * into the msrp code as if they were received from the network and
 * observing the resulting MSRP events.
 *
 * test_state.rx_PDU - a buffer to hold packet data for simulated Rx
 *
 * test_state.rx_PDU_len - store the length of stored PDU data here
 *
 * test_state.forward_msrp_events - when set to 0, only the test
 *    double code for observing events will run. When set to 1, the
 *    observation code will run and then the events will pass to the
 *    normal processing.
 *
 * test_state.msrp_observe - a function pointer that, if not NULL,
 *    will be called on every event that occurs during a test.
 */

/******* Start of test cases *******/

TEST_GROUP(MvrpPDUTests)
{
	void setup() {
		mrpd_reset();
		mvrp_init(1);
		test_state.forward_mvrp_events = 0;
	}
	void teardown() {
		mvrp_reset();
		mrpd_reset();
	}
};

/*
 * This is a sample packet captured via wireshark. In this case the
 * packet contains a single rJoinMT! and more than 4000 rMT!. This
 * test verfies that the rMT! events are ignored.
 */
TEST(MvrpPDUTests, ParsePkt1)
{
	static struct sockaddr_in client1;
	int rv;

	memset(&client1, 0, sizeof(client1));

	/* no error returned for first client */
	mvrp_recv_cmd("V??", strlen("V??") + 1, &client1);
	CHECK(mvrp_tests_cmd_ok(test_state.ctl_msg_data));
	/* one client notification sent in response to V?? */
	LONGS_EQUAL(1, test_state.sent_ctl_msg_count);

	memcpy(test_state.rx_PDU, mvrp_pdu_pkt1, sizeof mvrp_pdu_pkt1);
	test_state.rx_PDU_len = sizeof mvrp_pdu_pkt1;
	rv = mvrp_recv_msg();
	LONGS_EQUAL(0, rv);
	/* no errors send to client */
	CHECK(mvrp_tests_cmd_ok(test_state.ctl_msg_data));
	/*
	 * second client notification sent in response to PDU decode.
	 * Notifcations that could potentially be generated from each
	 * rMT! event in the packet are ignored.
	 */
	LONGS_EQUAL(2, test_state.sent_ctl_msg_count);

}
