// SPDX-License-Identifier: LGPL-3.0-or-later
// Copyright © 2020-2021 Florian Schmaus
#include <cstdlib>	// for exit, EXIT_FAILURE, EXIT_SUC...

#include "BinaryPrivateSemaphore.hpp"		 // for BPS
#include "CountingPrivateSemaphore.hpp"	 // for CPS
#include "Fiber.hpp"										 // for Fiber
#include "PrivateSemaphore.hpp"					 // for PS
#include "Runtime.hpp"									 // for Runtime

using fibParams = struct {
	int n;
	int* result;
	PS* sem;
};

static void fib(void* voidParams) {
	auto* params = static_cast<fibParams*>(voidParams);
	int n = params->n;
	int* result = params->result;
	PS* sem = params->sem;

	if (n < 2) {
		*result = n;
	} else {
		CPS newSem(2);

		int a, b;

		fibParams newParams1;
		newParams1.n = n - 1;
		newParams1.result = &a;
		newParams1.sem = &newSem;
		fibParams newParams2;
		newParams2.n = n - 2;
		newParams2.result = &b;
		newParams2.sem = &newSem;

		Fiber* f1 = Fiber::from(&fib, &newParams1);
		Fiber* f2 = Fiber::from(&fib, &newParams2);

		Runtime* runtime = Runtime::getRuntime();
		runtime->schedule(*f1);
		runtime->schedule(*f2);

		newSem.wait();

		*result = a + b;
	}

	sem->signalAndExit();
}

void emperTest() {
	const int fibNum = 13;
	int result;
	BPS sem;
	fibParams params = {fibNum, &result, &sem};

	fib(&params);

	sem.wait();

	if (result != 233) {
		exit(EXIT_FAILURE);
	}
}