/*
 * log.c
 *
 * Created on: 21.04.2025
 * Author: Kilian
 *
 * Implementation of the core logging system
 */

#include "log.h"
#include "stm32h7xx_hal.h"

/* Backend management */
static const log_backend_t* registered_backends[MAX_LOG_BACKENDS] = {0};
static uint8_t backend_count = 0;

/* Register a new logging backend */
bool log_register_backend(const log_backend_t* backend) {
    if (backend_count >= MAX_LOG_BACKENDS || backend == NULL) {
        return false;
    }
    
    registered_backends[backend_count++] = backend;
    return true;
}

/* Initialize all registered backends */
void log_init_all_backends(void) {
    /* Initialize all registered backends */
    for (uint8_t i = 0; i < backend_count; i++) {
        if (registered_backends[i]->init != NULL) {
            registered_backends[i]->init();
        }
    }
}

/* Check if a log level is enabled */
bool log_is_level_enabled(log_level_t level) {
    for (uint8_t i = 0; i < backend_count; i++) {
        if (registered_backends[i]->is_enabled(level)) {
            return true;
        }
    }
    return false;
}





/* Frontend implementation */

/* Main logging function */
void log_message(log_level_t level, const char *msg, ...) {
    log_message_t log_msg = {level, HAL_GetTick(), "\n", 0};
    
    /* Format the message prefix (timestamp, log level) */
    size_t prefix_len = 1;
    
    /* Add timestamp if configured */
    if (PRINT_TIMESTAMP) {
        prefix_len += snprintf(log_msg.message + prefix_len, MAX_MESSAGE_LENGTH, "[%lu] ", log_msg.timestamp);
    }
    
    /* Add log level name */
    if (level <= LOG_LEVEL_NOISY) {
        prefix_len += snprintf(log_msg.message + prefix_len, MAX_MESSAGE_LENGTH - prefix_len, 
                              "%s", log_level_names[level]);
    }
    
    /* Format the log message with variable arguments */
    va_list args;
    va_start(args, msg);
    log_msg.message_length = prefix_len + vsnprintf(log_msg.message + prefix_len, 
                                                  MAX_MESSAGE_LENGTH - prefix_len, 
                                                  msg, args);
    va_end(args);
    
    /* Send to all enabled backends */
    for (uint8_t i = 0; i < backend_count; i++) {
        if (registered_backends[i]->is_enabled(level)) {
            registered_backends[i]->write(&log_msg);
        }
    }
}

/* Continuation logging without timestamp or log level */
void log_message_cont(log_level_t level, const char *msg, ...) {
    log_message_t log_msg;
    log_msg.level = level;
    log_msg.timestamp = HAL_GetTick();
    
    /* Format the log message with variable arguments */
    va_list args;
    va_start(args, msg);
    log_msg.message_length = vsnprintf(log_msg.message, MAX_MESSAGE_LENGTH, msg, args);
    va_end(args);
    
    /* Send to all enabled backends */
    for (uint8_t i = 0; i < backend_count; i++) {
        if (registered_backends[i]->is_enabled(level)) {
            registered_backends[i]->write(&log_msg);
        }
    }
}

/* Clear the console on all backends that support it */
void log_clear_console(void) {
    for (uint8_t i = 0; i < backend_count; i++) {
        if (registered_backends[i]->clear != NULL) {
            registered_backends[i]->clear();
        }
    }
}