/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : hal.c
  * @brief          : Hardware Abstraction Layer main source file
  ******************************************************************************
  */
/* USER CODE END Header */

#include "hal.h"
#include <string.h>

/**
 * @brief HAL module registry
 */
static hal_module_config_t hal_module_registry[HAL_MODULE_MAX];
static uint32_t hal_module_count = 0;

/**
 * @brief HAL error context
 */
static hal_error_context_t hal_error_ctx = {
    .callback = NULL,
    .error_count = 0,
    .enabled = 1
};

/**
 * @brief HAL module initialization
 * @retval HAL status code
 */
hal_ret_t hal_init(void) {
    hal_ret_t status = HAL_RET_OK;
    
    /* Clear module registry */
    memset(hal_module_registry, 0, sizeof(hal_module_registry));
    hal_module_count = 0;
    
    /* Initialize error handling system */
    status = hal_error_init();
    if (status != HAL_RET_OK) {
        return status;
    }
    
    /* Call architecture specific initialization */
#if HAL_TARGET_ARCH == HAL_ARCH_STM32F1
    hal_stm32f1_init();
#elif HAL_TARGET_ARCH == HAL_ARCH_STM32F4
    hal_stm32f4_init();
#elif HAL_TARGET_ARCH == HAL_ARCH_STM32F7
    hal_stm32f7_init();
#elif HAL_TARGET_ARCH == HAL_ARCH_STM32L4
    hal_stm32l4_init();
#else
#error "Unsupported HAL architecture"
    return HAL_RET_ERROR;
#endif
    
    return HAL_RET_OK;
}

/**
 * @brief Register a HAL module
 * @param module_config: Module configuration
 * @retval HAL status code
 */
hal_ret_t hal_module_register(const hal_module_config_t* module_config) {
    if (module_config == NULL) {
        return HAL_RET_INVALID_PARAM;
    }
    
    if (module_config->type >= HAL_MODULE_MAX) {
        return HAL_RET_INVALID_PARAM;
    }
    
    /* Check if module already registered */
    if (hal_module_registry[module_config->type].ops.init != NULL) {
        return HAL_RET_RESOURCE_LOCKED;
    }
    
    /* Register the module */
    memcpy(&hal_module_registry[module_config->type], module_config, sizeof(hal_module_config_t));
    hal_module_count++;
    
    return HAL_RET_OK;
}

/**
 * @brief Initialize a specific HAL module
 * @param module_type: Module type
 * @param handle: HAL handle for the module
 * @retval HAL status code
 */
hal_ret_t hal_module_init(hal_module_type_t module_type, hal_handle_t* handle) {
    if (module_type >= HAL_MODULE_MAX || handle == NULL) {
        return HAL_RET_INVALID_PARAM;
    }
    
    if (hal_module_registry[module_type].ops.init == NULL) {
        return HAL_RET_NOT_SUPPORTED;
    }
    
    /* Initialize handle if not already initialized */
    if (handle->status == HAL_PERIPH_STATE_RESET) {
        HAL_HANDLE_INIT(handle);
        handle->status = HAL_PERIPH_STATE_READY;
    }
    
    return hal_module_registry[module_type].ops.init(handle);
}

/**
 * @brief Deinitialize a specific HAL module
 * @param module_type: Module type
 * @param handle: HAL handle for the module
 * @retval HAL status code
 */
hal_ret_t hal_module_deinit(hal_module_type_t module_type, hal_handle_t* handle) {
    if (module_type >= HAL_MODULE_MAX || handle == NULL) {
        return HAL_RET_INVALID_PARAM;
    }
    
    if (hal_module_registry[module_type].ops.deinit == NULL) {
        return HAL_RET_NOT_SUPPORTED;
    }
    
    hal_ret_t status = hal_module_registry[module_type].ops.deinit(handle);
    if (status == HAL_RET_OK) {
        handle->status = HAL_PERIPH_STATE_RESET;
    }
    
    return status;
}

/**
 * @brief Configure a specific HAL module
 * @param module_type: Module type
 * @param handle: HAL handle for the module
 * @param config: Module configuration data
 * @retval HAL status code
 */
hal_ret_t hal_module_configure(hal_module_type_t module_type, hal_handle_t* handle, void* config) {
    if (module_type >= HAL_MODULE_MAX || handle == NULL) {
        return HAL_RET_INVALID_PARAM;
    }
    
    if (hal_module_registry[module_type].ops.configure == NULL) {
        return HAL_RET_NOT_SUPPORTED;
    }
    
    return hal_module_registry[module_type].ops.configure(handle, config);
}

/**
 * @brief Control a specific HAL module
 * @param module_type: Module type
 * @param handle: HAL handle for the module
 * @param cmd: Control command
 * @param param: Control parameter
 * @retval HAL status code
 */
hal_ret_t hal_module_control(hal_module_type_t module_type, hal_handle_t* handle, uint32_t cmd, void* param) {
    if (module_type >= HAL_MODULE_MAX || handle == NULL) {
        return HAL_RET_INVALID_PARAM;
    }
    
    if (hal_module_registry[module_type].ops.control == NULL) {
        return HAL_RET_NOT_SUPPORTED;
    }
    
    return hal_module_registry[module_type].ops.control(handle, cmd, param);
}

/**
 * @brief Get status of a specific HAL module
 * @param module_type: Module type
 * @param handle: HAL handle for the module
 * @param status: Pointer to store module status
 * @retval HAL status code
 */
hal_ret_t hal_module_get_status(hal_module_type_t module_type, hal_handle_t* handle, uint32_t* status) {
    if (module_type >= HAL_MODULE_MAX || handle == NULL || status == NULL) {
        return HAL_RET_INVALID_PARAM;
    }
    
    if (hal_module_registry[module_type].ops.get_status == NULL) {
        return HAL_RET_NOT_SUPPORTED;
    }
    
    return hal_module_registry[module_type].ops.get_status(handle, status);
}

/**
 * @brief Get default configuration for a module
 * @param module_type: Module type
 * @return Pointer to default configuration, or NULL if not available
 */
void* hal_module_get_default_config(hal_module_type_t module_type) {
    if (module_type >= HAL_MODULE_MAX) {
        return NULL;
    }
    
    return hal_module_registry[module_type].default_config;
}

/**
 * @brief Get HAL version information
 * @param major: Pointer to store major version
 * @param minor: Pointer to store minor version
 * @param patch: Pointer to store patch version
 * @retval HAL status code
 */
hal_ret_t hal_get_version(uint8_t* major, uint8_t* minor, uint8_t* patch) {
    if (major == NULL || minor == NULL || patch == NULL) {
        return HAL_RET_INVALID_PARAM;
    }
    
    *major = HAL_VERSION_MAJOR;
    *minor = HAL_VERSION_MINOR;
    *patch = HAL_VERSION_PATCH;
    
    return HAL_RET_OK;
}

/**
 * @brief Get HAL version string
 * @retval Version string
 */
const char* hal_get_version_string(void) {
    return HAL_VERSION_STRING;
}

/**
 * @brief Get HAL module count
 * @retval Number of registered HAL modules
 */
uint32_t hal_get_module_count(void) {
    return hal_module_count;
}

/**
 * @brief Get HAL module configuration
 * @param module_type: Module type
 * @retval Pointer to module configuration, or NULL if not found
 */
const hal_module_config_t* hal_get_module_config(hal_module_type_t module_type) {
    if (module_type >= HAL_MODULE_MAX) {
        return NULL;
    }
    
    if (hal_module_registry[module_type].ops.init == NULL) {
        return NULL;
    }
    
    return &hal_module_registry[module_type];
}

/**
 * @brief Initialize HAL error handling system
 * @retval HAL status code
 */
hal_ret_t hal_error_init(void) {
    memset(&hal_error_ctx.last_error, 0, sizeof(hal_error_t));
    hal_error_ctx.error_count = 0;
    hal_error_ctx.enabled = 1;
    hal_error_ctx.callback = NULL;
    return HAL_RET_OK;
}

/**
 * @brief Deinitialize HAL error handling system
 * @retval HAL status code
 */
hal_ret_t hal_error_deinit(void) {
    hal_error_ctx.enabled = 0;
    hal_error_ctx.callback = NULL;
    return HAL_RET_OK;
}

/**
 * @brief Register an error callback function
 * @param callback: Error callback function
 * @retval HAL status code
 */
hal_ret_t hal_error_register_callback(hal_error_callback_t callback) {
    hal_error_ctx.callback = callback;
    return HAL_RET_OK;
}

/**
 * @brief Record an error
 * @param error: Pointer to error information
 * @retval HAL status code
 */
hal_ret_t hal_error_record(const hal_error_t* error) {
    if (error == NULL) {
        return HAL_RET_INVALID_PARAM;
    }
    
    if (!hal_error_ctx.enabled) {
        return HAL_RET_OK;
    }
    
    /* Copy error information */
    memcpy(&hal_error_ctx.last_error, error, sizeof(hal_error_t));
    hal_error_ctx.error_count++;
    
    /* Call error callback if registered */
    if (hal_error_ctx.callback != NULL) {
        hal_error_ctx.callback(error);
    }
    
    return HAL_RET_OK;
}

/**
 * @brief Get last error information
 * @retval Pointer to last error information
 */
const hal_error_t* hal_error_get_last(void) {
    return &hal_error_ctx.last_error;
}

/**
 * @brief Get total error count
 * @retval Total error count
 */
uint32_t hal_error_get_count(void) {
    return hal_error_ctx.error_count;
}

/**
 * @brief Clear error information
 * @retval HAL status code
 */
hal_ret_t hal_error_clear(void) {
    memset(&hal_error_ctx.last_error, 0, sizeof(hal_error_t));
    hal_error_ctx.error_count = 0;
    return HAL_RET_OK;
}

/**
 * @brief Enable/disable error logging
 * @param enable: Enable flag (1 to enable, 0 to disable)
 * @retval HAL status code
 */
hal_ret_t hal_error_enable(uint8_t enable) {
    hal_error_ctx.enabled = enable;
    return HAL_RET_OK;
}
