/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */
/* Copyright (c) 2024 Brett Sheffield <bacs@librecast.net> */

#include "test.h"
#include <librecast_pvt.h>
#include <librecast/router.h>

#define ROUTERS 7

void dump_router_links(lc_router_t *r[], int routers)
{
	for (int i = 0; i < routers; i++) {
		fprintf(stderr, "r[%i] %p\n", i, (void *)r[i]);
		for (int p = 0; p < (int)r[i]->ports; p++) {
			if (r[i]->port[p]) {
				lc_router_t *peer = r[i]->port[p]->pair->router;
				fprintf(stderr, "r[%i]p[%i] %p\n", i, p, (void *)peer);
			}
		}
	}
}

int main(void)
{
	lc_ctx_t *lctx;
	lc_router_t *r[ROUTERS];
	const int m = ROUTERS - 1;
	int rc;

	test_name("lc_router_net() - LC_TOPO_CHAIN");

	lctx = lc_ctx_new();
	if (!test_assert(lctx != NULL, "lc_ctx_new()")) return test_status;

	/* create some daisy-chained routers */
	rc = lc_router_net(lctx, r, ROUTERS, LC_TOPO_CHAIN, 0, LC_ROUTER_FLAG_FIXED);
	if (!test_assert(rc == 0, "lc_router_net()")) goto err_ctx_free;
	for (int i = 0; i < ROUTERS; i++) {
		test_log("====== ROUTER %i\n", i);

		/* check router parameters */
		if (!test_assert(r[i] != NULL, "r[%i] allocated", i))
			goto err_ctx_free;
		if (!test_assert(r[i]->ctx == lctx, "context set"))
			goto err_ctx_free;
		if (!test_assert(r[i]->flags == LC_ROUTER_FLAG_FIXED, "flags set"))
			goto err_ctx_free;
		if (!test_assert(r[i]->ports == 2, "ports == 2"))
			goto err_ctx_free;
	}
	dump_router_links(r, ROUTERS);
	/* now check ports are connected correctly */
	test_assert(r[0]->port[0] == NULL, "r[0]p[0] disconnected");
	for (int i = 1; i < m; i++) {
		int prev = (i == 0) ? m : i - 1;
		test_log("R%i (prev R%i)\n", i, prev);
		/* port 0 is connected to previous router */
		if (!test_assert(r[i]->port[0] != NULL, "r[%i]p[0] connected", i))
			goto err_ctx_free;
		test_assert(r[i]->port[0]->pair == r[prev]->port[1],
				"r[%i]p[1] <--> r[%i]p[0]", prev, i);
		if (!test_assert(r[i]->port[1] != NULL, "r[%i]p[1] connected", i))
			goto err_ctx_free;
	}
	test_assert(r[m]->port[0]->pair == r[m-1]->port[1], "r[%i]p[1] <--> r[%i]p[0]", m - 1, m);
	if (!test_assert(r[m]->port[1] == NULL, "r[%i]p[1] disconnected", m))
		goto err_ctx_free;

	/* bring up all ports on all routers */
	for (int i = 0; i < ROUTERS; i++) lc_router_port_up(r[i], -1);
	test_assert(!lc_router_net_hasloop(r, ROUTERS), "routing loop not expected");

err_ctx_free:
	lc_ctx_free(lctx);
	return test_status;
}
