/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : bsp_config.c
  * @brief          : Board support package configuration file source
  ******************************************************************************
  */
/* USER CODE END Header */

#include "bsp_config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

/**
 * @brief Configuration storage entry
 */
typedef struct bsp_config_storage_entry {
    char section[BSP_CONFIG_MAX_SECTION_NAME_LENGTH];
    char key[BSP_CONFIG_MAX_KEY_NAME_LENGTH];
    char value[BSP_CONFIG_MAX_VALUE_LENGTH];
    struct bsp_config_storage_entry* next;
} bsp_config_storage_entry_t;

/**
 * @brief Configuration storage
 */
typedef struct {
    bsp_config_storage_entry_t* entries;
    uint32_t entry_count;
    uint8_t initialized;
} bsp_config_storage_t;

/**
 * @brief Configuration storage instance
 */
static bsp_config_storage_t bsp_config_storage = {
    .entries = NULL,
    .entry_count = 0,
    .initialized = 0
};

/**
 * @brief Trim whitespace from a string
 * @param str: String to trim
 * @return Trimmed string
 */
static char* bsp_config_trim(char* str) {
    char* end;
    
    // Trim leading whitespace
    while (isspace((unsigned char)*str)) {
        str++;
    }
    
    if (*str == 0) {
        return str;
    }
    
    // Trim trailing whitespace
    end = str + strlen(str) - 1;
    while (end > str && isspace((unsigned char)*end)) {
        end--;
    }
    
    // Null terminate
    *(end + 1) = 0;
    
    return str;
}

/**
 * @brief Open configuration file
 * @param filename: Configuration file name
 * @param parser: Parser context
 * @retval HAL status code
 */
static hal_ret_t bsp_config_file_open(const char* filename, bsp_config_parser_t* parser) {
    if (filename == NULL || parser == NULL) {
        return HAL_INVALID_PARAM;
    }
    
    parser->file = fopen(filename, "r");
    if (parser->file == NULL) {
        return HAL_ERROR;
    }
    
    memset(parser->current_section, 0, sizeof(parser->current_section));
    memset(parser->buffer, 0, sizeof(parser->buffer));
    parser->line_number = 0;
    parser->initialized = 1;
    
    return HAL_OK;
}

/**
 * @brief Close configuration file
 * @param parser: Parser context
 * @retval HAL status code
 */
static hal_ret_t bsp_config_file_close(bsp_config_parser_t* parser) {
    if (parser == NULL || !parser->initialized) {
        return HAL_INVALID_PARAM;
    }
    
    if (parser->file != NULL) {
        fclose(parser->file);
        parser->file = NULL;
    }
    
    parser->initialized = 0;
    
    return HAL_OK;
}

/**
 * @brief Read a configuration entry from file
 * @param parser: Parser context
 * @param entry: Configuration entry
 * @retval HAL status code
 */
static hal_ret_t bsp_config_file_read_entry(bsp_config_parser_t* parser, bsp_config_entry_t* entry) {
    if (parser == NULL || entry == NULL || !parser->initialized) {
        return HAL_INVALID_PARAM;
    }
    
    if (parser->file == NULL) {
        return HAL_ERROR;
    }
    
    while (fgets(parser->buffer, sizeof(parser->buffer), parser->file) != NULL) {
        parser->line_number++;
        
        char* line = bsp_config_trim(parser->buffer);
        size_t len = strlen(line);
        
        // Skip empty lines and comments
        if (len == 0 || line[0] == '#') {
            continue;
        }
        
        // Check for section header
        if (line[0] == '[' && line[len - 1] == ']') {
            // Extract section name
            memset(parser->current_section, 0, sizeof(parser->current_section));
            strncpy(parser->current_section, line + 1, len - 2);
            parser->current_section[len - 2] = '\0';
            continue;
        }
        
        // Check for key-value pair
        char* equals = strchr(line, '=');
        if (equals != NULL) {
            // Extract key and value
            *equals = '\0';
            char* key = bsp_config_trim(line);
            char* value = bsp_config_trim(equals + 1);
            
            entry->section = parser->current_section;
            entry->key = key;
            entry->value = value;
            
            return HAL_OK;
        }
    }
    
    return HAL_TIMEOUT;
}

/**
 * @brief Parse integer value
 * @param value: String value to parse
 * @param result: Pointer to store result
 * @retval HAL status code
 */
static hal_ret_t bsp_config_parse_int(const char* value, int* result) {
    if (value == NULL || result == NULL) {
        return HAL_INVALID_PARAM;
    }
    
    char* endptr;
    long val = strtol(value, &endptr, 0);
    
    if (*endptr != '\0') {
        return HAL_ERROR;
    }
    
    *result = (int)val;
    
    return HAL_OK;
}

/**
 * @brief Parse unsigned integer value
 * @param value: String value to parse
 * @param result: Pointer to store result
 * @retval HAL status code
 */
static hal_ret_t bsp_config_parse_uint(const char* value, uint32_t* result) {
    if (value == NULL || result == NULL) {
        return HAL_INVALID_PARAM;
    }
    
    char* endptr;
    unsigned long val = strtoul(value, &endptr, 0);
    
    if (*endptr != '\0') {
        return HAL_ERROR;
    }
    
    *result = (uint32_t)val;
    
    return HAL_OK;
}

/**
 * @brief Parse boolean value
 * @param value: String value to parse
 * @param result: Pointer to store result
 * @retval HAL status code
 */
static hal_ret_t bsp_config_parse_bool(const char* value, uint8_t* result) {
    if (value == NULL || result == NULL) {
        return HAL_INVALID_PARAM;
    }
    
    if (strcmp(value, "true") == 0 || strcmp(value, "TRUE") == 0 || 
        strcmp(value, "1") == 0 || strcmp(value, "yes") == 0 || 
        strcmp(value, "YES") == 0) {
        *result = 1;
        return HAL_OK;
    } else if (strcmp(value, "false") == 0 || strcmp(value, "FALSE") == 0 || 
               strcmp(value, "0") == 0 || strcmp(value, "no") == 0 || 
               strcmp(value, "NO") == 0) {
        *result = 0;
        return HAL_OK;
    }
    
    return HAL_ERROR;
}

/**
 * @brief Parse string value
 * @param value: String value to parse
 * @param result: Pointer to store result
 * @param max_length: Maximum length of result buffer
 * @retval HAL status code
 */
static hal_ret_t bsp_config_parse_string(const char* value, char* result, size_t max_length) {
    if (value == NULL || result == NULL) {
        return HAL_INVALID_PARAM;
    }
    
    strncpy(result, value, max_length - 1);
    result[max_length - 1] = '\0';
    
    return HAL_OK;
}

/**
 * @brief Add a configuration entry to storage
 * @param section: Section name
 * @param key: Key name
 * @param value: Value
 * @retval HAL status code
 */
static hal_ret_t bsp_config_storage_add(const char* section, const char* key, const char* value) {
    // Check if entry already exists
    bsp_config_storage_entry_t* entry = bsp_config_storage.entries;
    while (entry != NULL) {
        if (strcmp(entry->section, section) == 0 && strcmp(entry->key, key) == 0) {
            // Update existing entry
            strncpy(entry->value, value, sizeof(entry->value) - 1);
            entry->value[sizeof(entry->value) - 1] = '\0';
            return HAL_OK;
        }
        entry = entry->next;
    }
    
    // Create new entry
    bsp_config_storage_entry_t* new_entry = malloc(sizeof(bsp_config_storage_entry_t));
    if (new_entry == NULL) {
        return HAL_OUT_OF_MEMORY;
    }
    
    strncpy(new_entry->section, section, sizeof(new_entry->section) - 1);
    strncpy(new_entry->key, key, sizeof(new_entry->key) - 1);
    strncpy(new_entry->value, value, sizeof(new_entry->value) - 1);
    new_entry->section[sizeof(new_entry->section) - 1] = '\0';
    new_entry->key[sizeof(new_entry->key) - 1] = '\0';
    new_entry->value[sizeof(new_entry->value) - 1] = '\0';
    new_entry->next = NULL;
    
    // Add to list
    if (bsp_config_storage.entries == NULL) {
        bsp_config_storage.entries = new_entry;
    } else {
        entry = bsp_config_storage.entries;
        while (entry->next != NULL) {
            entry = entry->next;
        }
        entry->next = new_entry;
    }
    
    bsp_config_storage.entry_count++;
    
    return HAL_OK;
}

/**
 * @brief Clear configuration storage
 */
static void bsp_config_storage_clear(void) {
    bsp_config_storage_entry_t* entry = bsp_config_storage.entries;
    while (entry != NULL) {
        bsp_config_storage_entry_t* next = entry->next;
        free(entry);
        entry = next;
    }
    
    bsp_config_storage.entries = NULL;
    bsp_config_storage.entry_count = 0;
}

/**
 * @brief Initialize BSP configuration system
 * @retval HAL status code
 */
hal_ret_t bsp_config_init(void) {
    if (bsp_config_storage.initialized) {
        return HAL_OK;
    }
    
    bsp_config_storage_clear();
    bsp_config_storage.initialized = 1;
    
    return HAL_OK;
}

/**
 * @brief Deinitialize BSP configuration system
 * @retval HAL status code
 */
hal_ret_t bsp_config_deinit(void) {
    if (!bsp_config_storage.initialized) {
        return HAL_OK;
    }
    
    bsp_config_storage_clear();
    bsp_config_storage.initialized = 0;
    
    return HAL_OK;
}

/**
 * @brief Load BSP configuration from file
 * @param filename: Configuration file name
 * @retval HAL status code
 */
hal_ret_t bsp_config_load(const char* filename) {
    if (!bsp_config_storage.initialized) {
        hal_ret_t status = bsp_config_init();
        if (status != HAL_OK) {
            return status;
        }
    }
    
    bsp_config_parser_t parser;
    hal_ret_t status = bsp_config_file_open(filename, &parser);
    if (status != HAL_OK) {
        return status;
    }
    
    bsp_config_entry_t entry;
    while ((status = bsp_config_file_read_entry(&parser, &entry)) == HAL_OK) {
        status = bsp_config_storage_add(entry.section, entry.key, entry.value);
        if (status != HAL_OK) {
            bsp_config_file_close(&parser);
            return status;
        }
    }
    
    if (status != HAL_TIMEOUT) {
        bsp_config_file_close(&parser);
        return status;
    }
    
    status = bsp_config_file_close(&parser);
    if (status != HAL_OK) {
        return status;
    }
    
    return HAL_OK;
}

/**
 * @brief Save BSP configuration to file
 * @param filename: Configuration file name
 * @retval HAL status code
 */
hal_ret_t bsp_config_save(const char* filename) {
    if (!bsp_config_storage.initialized || bsp_config_storage.entry_count == 0) {
        return HAL_OK;
    }
    
    FILE* file = fopen(filename, "w");
    if (file == NULL) {
        return HAL_ERROR;
    }
    
    fprintf(file, "# BSP Configuration File\n");
    fprintf(file, "# Version: %s\n\n", BSP_CONFIG_FILE_VERSION);
    
    char current_section[BSP_CONFIG_MAX_SECTION_NAME_LENGTH] = "";
    bsp_config_storage_entry_t* entry = bsp_config_storage.entries;
    
    while (entry != NULL) {
        if (strcmp(entry->section, current_section) != 0) {
            // New section
            strncpy(current_section, entry->section, sizeof(current_section) - 1);
            fprintf(file, "[%s]\n", current_section);
        }
        
        fprintf(file, "%s=%s\n", entry->key, entry->value);
        entry = entry->next;
    }
    
    fclose(file);
    
    return HAL_OK;
}

/**
 * @brief Get configuration value
 * @param section: Configuration section name
 * @param key: Configuration key name
 * @param value: Pointer to store value
 * @param max_length: Maximum length of value buffer
 * @retval HAL status code
 */
hal_ret_t bsp_config_get_value(const char* section, const char* key, char* value, size_t max_length) {
    if (!bsp_config_storage.initialized || section == NULL || key == NULL || value == NULL) {
        return HAL_INVALID_PARAM;
    }
    
    bsp_config_storage_entry_t* entry = bsp_config_storage.entries;
    while (entry != NULL) {
        if (strcmp(entry->section, section) == 0 && strcmp(entry->key, key) == 0) {
            strncpy(value, entry->value, max_length - 1);
            value[max_length - 1] = '\0';
            return HAL_OK;
        }
        entry = entry->next;
    }
    
    return HAL_NOT_SUPPORTED;
}

/**
 * @brief Set configuration value
 * @param section: Configuration section name
 * @param key: Configuration key name
 * @param value: Configuration value
 * @retval HAL status code
 */
hal_ret_t bsp_config_set_value(const char* section, const char* key, const char* value) {
    if (!bsp_config_storage.initialized || section == NULL || key == NULL || value == NULL) {
        return HAL_INVALID_PARAM;
    }
    
    return bsp_config_storage_add(section, key, value);
}

/**
 * @brief Get configuration value as integer
 * @param section: Configuration section name
 * @param key: Configuration key name
 * @param value: Pointer to store integer value
 * @retval HAL status code
 */
hal_ret_t bsp_config_get_int(const char* section, const char* key, int* value) {
    char str_value[BSP_CONFIG_MAX_VALUE_LENGTH];
    hal_ret_t status = bsp_config_get_value(section, key, str_value, sizeof(str_value));
    if (status != HAL_OK) {
        return status;
    }
    
    return bsp_config_parse_int(str_value, value);
}

/**
 * @brief Set configuration value as integer
 * @param section: Configuration section name
 * @param key: Configuration key name
 * @param value: Integer value
 * @retval HAL status code
 */
hal_ret_t bsp_config_set_int(const char* section, const char* key, int value) {
    char str_value[BSP_CONFIG_MAX_VALUE_LENGTH];
    snprintf(str_value, sizeof(str_value), "%d", value);
    return bsp_config_set_value(section, key, str_value);
}

/**
 * @brief Get configuration value as unsigned integer
 * @param section: Configuration section name
 * @param key: Configuration key name
 * @param value: Pointer to store unsigned integer value
 * @retval HAL status code
 */
hal_ret_t bsp_config_get_uint(const char* section, const char* key, uint32_t* value) {
    char str_value[BSP_CONFIG_MAX_VALUE_LENGTH];
    hal_status_t status = bsp_config_get_value(section, key, str_value, sizeof(str_value));
    if (status != HAL_OK) {
        return status;
    }
    
    return bsp_config_parse_uint(str_value, value);
}

/**
 * @brief Set configuration value as unsigned integer
 * @param section: Configuration section name
 * @param key: Configuration key name
 * @param value: Unsigned integer value
 * @retval HAL status code
 */
hal_ret_t bsp_config_set_uint(const char* section, const char* key, uint32_t value) {
    char str_value[BSP_CONFIG_MAX_VALUE_LENGTH];
    snprintf(str_value, sizeof(str_value), "%lu", (unsigned long)value);
    return bsp_config_set_value(section, key, str_value);
}

/**
 * @brief Get configuration value as boolean
 * @param section: Configuration section name
 * @param key: Configuration key name
 * @param value: Pointer to store boolean value
 * @retval HAL status code
 */
hal_ret_t bsp_config_get_bool(const char* section, const char* key, uint8_t* value) {
    char str_value[BSP_CONFIG_MAX_VALUE_LENGTH];
    hal_status_t status = bsp_config_get_value(section, key, str_value, sizeof(str_value));
    if (status != HAL_OK) {
        return status;
    }
    
    return bsp_config_parse_bool(str_value, value);
}

/**
 * @brief Set configuration value as boolean
 * @param section: Configuration section name
 * @param key: Configuration key name
 * @param value: Boolean value
 * @retval HAL status code
 */
hal_ret_t bsp_config_set_bool(const char* section, const char* key, uint8_t value) {
    return bsp_config_set_value(section, key, value ? "true" : "false");
}

/**
 * @brief Parse BSP modules from configuration
 * @param config: Pointer to BSP board configuration structure to fill
 * @retval HAL status code
 */
hal_ret_t bsp_config_parse_modules(bsp_board_config_t* config) {
    if (config == NULL) {
        return HAL_INVALID_PARAM;
    }
    
    // TODO: Implement module parsing logic
    // This will depend on the specific configuration file format
    // and how modules are defined in the configuration
    
    return HAL_OK;
}

/**
 * @brief Initialize BSP from configuration file
 * @param filename: Configuration file name
 * @retval HAL status code
 */
hal_ret_t bsp_init_from_config(const char* filename) {
    // Load configuration file
    hal_ret_t status = bsp_config_load(filename);
    if (status != HAL_OK) {
        return status;
    }
    
    // Initialize HAL layer
    status = hal_init();
    if (status != HAL_OK) {
        return status;
    }
    
    // Initialize BSP module manager
    status = bsp_module_manager_init();
    if (status != HAL_OK) {
        return status;
    }
    
    // Create board configuration from file
    bsp_board_config_t board_config;
    memset(&board_config, 0, sizeof(board_config));
    
    // Parse board information
    char board_name[64];
    status = bsp_config_get_value("board", "name", board_name, sizeof(board_name));
    if (status == HAL_OK) {
        board_config.name = strdup(board_name);
    } else {
        board_config.name = "Unknown";
    }
    
    uint32_t version = BSP_CONFIG_VERSION;
    status = bsp_config_get_uint("board", "version", &version);
    if (status == HAL_OK) {
        board_config.version = version;
    } else {
        board_config.version = BSP_CONFIG_VERSION;
    }
    
    // Parse modules from configuration
    status = bsp_config_parse_modules(&board_config);
    if (status != HAL_OK) {
        return status;
    }
    
    // Initialize board
    status = bsp_board_init();
    if (status != HAL_OK) {
        return status;
    }
    
    // Initialize all modules
    status = bsp_module_init_all();
    if (status != HAL_OK) {
        return status;
    }
    
    // Configure all modules
    // TODO: Implement module configuration from file
    
    // Start all modules
    status = bsp_module_start_all();
    if (status != HAL_OK) {
        return status;
    }
    
    return HAL_OK;
}
