#include "../src/ThreadPool/ThreadPool.h"
#include <assert.h>
#include <stdbool.h>
#include <stdlib.h>

void testLifetime(void)
{
	allocator_t allocator;
	assert(EXIT_SUCCESS == Allocator_CreateSystemAllocator(&allocator));
	ThreadPool pool;

	assert(EXIT_SUCCESS == ThreadPool_Create(&pool, 4, 0x00, &allocator));
	ThreadPool_Destroy(&pool);

	assert(allocator.reserved == 0);
	Allocator_DestroySystemAllocator(&allocator);
}

void* testJobFunction(void* argument)
{
	assert(argument == NULL);

	return NULL;
}

void* lastJobFunction(os_semaphore_t* semaphore)
{
	OSSemaphore_Release(semaphore);
	return NULL;
}

void testGeneric(size_t n_workers, size_t n_jobs, bool discard_result)
{
	allocator_t allocator;
	assert(EXIT_SUCCESS == Allocator_CreateSystemAllocator(&allocator));
	ThreadPool pool;

	assert(EXIT_SUCCESS == ThreadPool_Create(&pool, n_workers, 0x00, &allocator));

	os_semaphore_t semaphore;
	ThreadPoolJob job;
	assert(OSSemaphore_Create(&semaphore, 0) == EXIT_SUCCESS);


	for (size_t i = 0; i < n_jobs - 1; i++) {
		job.flags |= discard_result ? THREADPOOLJOB_DISCARD_RESULT : 0x00;
		job.arg    = NULL;
		job.job    = testJobFunction;
		assert(ThreadPool_QueueJob(&pool, &job, NULL) == EXIT_SUCCESS);
	}

	job.arg = &semaphore;
	job.job = (ThreadFunction) lastJobFunction;
	assert(ThreadPool_QueueJob(&pool, &job, NULL) == EXIT_SUCCESS);

	// Wait until all the jobs are done
	OSSemaphore_Wait(&semaphore);
	OSSemaphore_Destroy(&semaphore);

	ThreadPool_Destroy(&pool);

	assert(allocator.reserved == 0);
	Allocator_DestroySystemAllocator(&allocator);
}

size_t power2(size_t n)
{
	size_t t = 1;
	for (size_t i = 0; i < n; i++) {
		t *= 2;
	}

	return t;
}

int main()
{
	testGeneric(1, power2(6), false);
	/*
	for (size_t worker_count = 1; worker_count < 32; worker_count++) {
		for (size_t job_count = 0; job_count < 16; job_count++) {
			testGeneric(worker_count, power2(job_count), true);
			testGeneric(worker_count, power2(job_count), false);
		}
	}
	*/
	return 0;
}