#include "logger.h"
#include "../platform.h"
#include <assert.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>

struct Logger global_logger;

void Logger_Init(struct Logger *logger)
{
	assert(logger != NULL);

	u32 initial_capacity = 512;

	logger->message_queue = Queue_Alloc(p_alloc, struct LogEntry, initial_capacity);
}

void Logger_Deinit(struct Logger *logger)
{
	assert(logger != NULL);

	Logger_Clear(logger);
	Queue_Free(p_free, logger->message_queue);
}

void Logger_Clear(struct Logger *logger)
{
	assert(logger != NULL);

	while(Queue_Size(logger->message_queue) > 0)
	{
		Logger_RemoveOldestMessage(logger);
	}
}

void Logger_AddMessage(struct Logger *logger, LogSourceInfo source_info, LogLevel level, const char *format_message, ...)
{
	assert(logger != NULL);

	// Build formatted message
	char *message;
	va_list var_args;
	va_start(var_args, format_message);
	int bytes_size = vsnprintf(NULL, 0, format_message, var_args) + 1;
	va_end(var_args);
	message = (char *) p_alloc(bytes_size * sizeof(char));
	va_start(var_args, format_message);
	int written = vsnprintf(message, bytes_size, format_message, var_args) + 1;
	va_end(var_args);

	// Add log entry to queue, checking if we have enough space
	struct LogEntry entry = {
		.level = level,
		.message = message,
		.id = logger->last_id++,
		.source = source_info
	};

	// fprintf(stderr, message);
	// fprintf(stderr, "\n");

	if(Queue_Size(logger->message_queue) >= QUEUE_HEADER_PTR(logger->message_queue)->capacity)
	{
		logger->overflow_count++;
		Logger_RemoveOldestMessage(logger);
	}
	Queue_Push(logger->message_queue, entry);
}

void Logger_RemoveOldestMessage(struct Logger *logger)
{
	assert(logger != NULL);
	assert(Queue_Size(logger->message_queue) > 0);

	struct LogEntry entry = Queue_Pop(logger->message_queue);
	p_free(entry.message);
}


u64 Logger_MessageCount(struct Logger *logger)
{
	assert(logger != NULL);

	return Queue_Size(logger->message_queue);
}

struct LogEntry *Logger_MessageAt(struct Logger *logger, u64 index)
{
	assert(logger != NULL);
	assert(Queue_Size(logger->message_queue) > index);

	return &Queue_At(logger->message_queue, index);
}
