#include "Log.h"
#include "string.h"
#include <stdio.h>
#include <stdlib.h>

struct log_message_storage{
    struct Log_message_data message;
    struct log_message_storage * next;
} * log_message_envoi, log_message_storage_premier, *log_message_storage_courant;

uint log_error = LOG_ERROR_LOG_NOT_INIT;
enum Log_level log_level_reference;

int store_new_message(struct Log_message_data message, struct log_message_storage * stockage);
void envoi_message(struct Log_message_data message);

void Log_init(void){
    log_message_storage_premier.message.log_level = INFO;
    strcpy(log_message_storage_premier.message.message,"Debut du programme");
    log_message_storage_premier.message.timestamp = time_us_32() / 1000;
    log_message_storage_premier.next = NULL;

    log_message_storage_courant = &log_message_storage_premier;
    log_message_envoi = &log_message_storage_premier;

    log_level_reference = TELEPLOT;
    log_error = LOG_ERROR_OK;
}


/// @brief Add one log message to local cache. Should be quick
/// @param message : string, without '\n' at the end.
/// @param log_level : can be in TELEPLOT, TRACE, DEBUG, INFO, WARN, ERROR, FATAL
void Log_message(char * message, enum Log_level log_level){
    printf("ERROR:%s\n",message);
    if(log_error != LOG_ERROR_OK){
        return;
    }
    // On vérifie que le message a une urgence suffisante pour être enregistrée
    if(log_level >= log_level_reference){
        /// Création de la structure de données
        struct Log_message_data message_container;
        if(strlen(message) > LOG_MAX_MESSAGE_SIZE){
            strcpy(message_container.message, "MSG TOO LONG");
        }else{
            strcpy(message_container.message, message);
        }
        message_container.log_level = log_level;
        message_container.timestamp = time_us_32() / 1000;

        /// Insertion de la structure dans la liste chaînée
        struct log_message_storage* tmp_message_storage;
        tmp_message_storage = (struct log_message_storage*) malloc(sizeof(struct log_message_storage));
        if(tmp_message_storage != NULL){
            tmp_message_storage->message = message_container;
            tmp_message_storage->next = NULL;
            log_message_storage_courant->next = tmp_message_storage;
            log_message_storage_courant = log_message_storage_courant->next;
        }else{
            log_error |= LOG_ERROR_MEMORY_FULL;
        }
    }
}

/// @brief Read messages in cache, store them and send them through the serial connection
void Log_gestion(){
    if(log_error == LOG_ERROR_LOG_NOT_INIT){
        return;
    }
    // Envoi 1 message par la liaison série
    if(log_message_envoi->next != NULL){
        log_message_envoi = log_message_envoi->next;
        envoi_message(log_message_envoi->message);
        // Si on est à la fin des messages, en envoie le statut de la fonction Log
        if(log_message_envoi->next == NULL){
            if(log_error & LOG_ERROR_MEMORY_FULL){
                printf("LOG ERROR : Memoire pleine !\n");
            }
        }
    }
}

/// @brief Renvoie l'intégralité du journal de log. La fonction Log_gestion() doit être appelée continuellement pour que cette fonction fonctionne.
void Log_get_full_log(){
    log_message_envoi = &log_message_storage_premier;
}

void envoi_message(struct Log_message_data message_data){
    if(message_data.log_level == TELEPLOT){
        printf("%s\n", message_data.message);
    }else{
        printf("%u ms:%s\n", message_data.timestamp, message_data.message);
    }
}

/// @brief Renvoi le status du log
/// @return LOG_ERROR_OK ou LOG_ERROR_MEMORY_FULL ou LOG_ERROR_LOG_NOT_INIT
int Log_get_statut(){
    return log_error;
}