use crate::Compiler::AST::{ConfigSection, Position};
use crate::Compiler::Core::Tokenizer::{Token, TokenType};
use crate::Compiler::VersionControl::VersionManager;
use crate::ErrorManager::{ErrorManager, DebugConfig};
use crate::Utilities::MID_Logger;
use super::{ConfigSchema, OperationalSettings};
use std::collections::HashMap;
pub struct ConfigSectionHandler {
logger: Option<std::sync::Arc<std::sync::Mutex<MID_Logger>>>,
error_manager: ErrorManager,
debug_config: DebugConfig,
}
impl ConfigSectionHandler {
pub fn new_with_error_manager(
logger: Option<std::sync::Arc<std::sync::Mutex<MID_Logger>>>,
error_manager: ErrorManager,
) -> Self {
let logger = logger.or_else(|| {
if MID_Logger::HasSharedInstance() {
Some(MID_Logger::GetSharedInstance(None, None))
} else {
None
}
});
ConfigSectionHandler {
logger,
error_manager,
debug_config: DebugConfig::silent(),
}
}
pub fn new(logger: Option<std::sync::Arc<std::sync::Mutex<MID_Logger>>>) -> Self {
Self::new_with_error_manager(logger, ErrorManager::get_shared_instance())
}
pub fn error_manager(&self) -> ErrorManager {
self.error_manager.clone()
}
pub fn process_config_tokens(
&mut self,
config_tokens: &[Token],
) -> ProcessConfigResult {
self.log_info("Starting CONFIG token-based extraction");
let mut result = ProcessConfigResult::default();
if config_tokens.is_empty() {
self.log_info("No CONFIG tokens — using cached minimal config");
result.config_section = ConfigSchema::create_minimal_config();
result.warnings.push(
"No CONFIG tokens provided — using cached defaults".to_string(),
);
self.initialize_singletons(&mut result);
return result;
}
let section_position = config_tokens
.iter()
.find(|t| matches!(t.token_type, TokenType::SectionConfig))
.map(|t| Position::new(t.line, t.column))
.unwrap_or(Position::UNKNOWN);
let entries_result = self.parse_config_entries_from_tokens(config_tokens);
result.warnings.extend(entries_result.warnings.clone());
match ConfigSchema::validate_and_enhance_config(entries_result.entries) {
Ok(validated) => {
let mut config_section = ConfigSchema::create_config_section(validated);
self.apply_positions_to_config_section(
&mut config_section,
&entries_result.positions,
section_position,
);
result.config_section = config_section;
}
Err(e) => {
self.log_warning(&format!(
"Config token validation failed: {} — using defaults", e
));
result.config_section = ConfigSchema::create_minimal_config();
result.warnings.push(format!("Config validation error: {}", e));
}
}
self.initialize_singletons(&mut result);
result
}
fn initialize_singletons(&mut self, result: &mut ProcessConfigResult) {
let settings = ConfigSchema::extract_operational_settings(&result.config_section);
self.debug_config = DebugConfig::from_debug_mode(settings.debug_mode);
if self.debug_config.is_enabled {
self.log_info(&format!(
"Settings: {:?}, {:?}, Version: {}",
settings.error_handling_strategy, settings.debug_mode, settings.version
));
}
VersionManager::initialize(&settings.version);
if self.debug_config.is_enabled {
self.log_info(&format!(
"VersionManager initialized with version {}",
settings.version
));
}
if let Ok(vm) = VersionManager::instance().read() {
if vm.current_version() != settings.version {
self.log_warning(&format!(
"Version mismatch: Config requests {}, but VersionManager is {}",
settings.version,
vm.current_version()
));
}
}
self.error_manager.update_settings(settings.clone());
result.operational_settings = settings;
self.log_info("ErrorManager configured with operational settings");
}
fn parse_config_entries_from_tokens(
&self,
tokens: &[Token],
) -> TokenConfigEntriesResult {
let mut entries: HashMap<String, String> = HashMap::new();
let mut positions: HashMap<String, Position> = HashMap::new();
let mut warnings: Vec<String> = Vec::new();
let mut i = 0usize;
while i < tokens.len() {
match &tokens[i].token_type {
TokenType::SectionConfig
| TokenType::Symbol('(')
| TokenType::Comment(_) => { i += 1; }
_ => break,
}
}
while i < tokens.len() {
match &tokens[i].token_type {
TokenType::Symbol(',')
| TokenType::Symbol(')')
| TokenType::Comment(_) => { i += 1; continue; }
TokenType::EndOfFile => break,
_ => {}
}
let (key, key_pos) = match &tokens[i].token_type {
TokenType::Identifier(k) => {
(k.clone(), Position::new(tokens[i].line, tokens[i].column))
}
other => {
warnings.push(format!(
"Unexpected token in @CONFIG at {}:{} — {:?}",
tokens[i].line, tokens[i].column, other
));
i += 1;
continue;
}
};
i += 1;
if i >= tokens.len() { break; }
match &tokens[i].token_type {
TokenType::SwitchCase => { i += 1; }
_ => {
warnings.push(format!(
"Expected '->' after config key '{}' at {}:{}",
key, tokens[i].line, tokens[i].column
));
while i < tokens.len() {
match &tokens[i].token_type {
TokenType::Identifier(_) | TokenType::EndOfFile => break,
_ => { i += 1; }
}
}
continue;
}
}
while i < tokens.len()
&& matches!(tokens[i].token_type, TokenType::Comment(_))
{
i += 1;
}
if i >= tokens.len() { break; }
let value_str = match &tokens[i].token_type {
TokenType::String(s) | TokenType::StringSingle(s) => s.clone(),
TokenType::Integer(n) => n.to_string(),
TokenType::Long(l) => l.to_string(),
TokenType::Float(f) => f.to_string(),
TokenType::Double(d) => d.to_string(),
TokenType::ScientificNotation(d) => d.to_string(),
TokenType::Bool(b) => b.to_string(),
TokenType::Date(d) => d.clone(),
TokenType::Timestamp(t) => t.clone(),
TokenType::Identifier(s) => s.clone(),
TokenType::Keyword(k) => k.to_string(),
other => {
warnings.push(format!(
"Unexpected value token for config key '{}' at {}:{} — {:?}",
key, tokens[i].line, tokens[i].column, other
));
i += 1;
continue;
}
};
i += 1;
entries.insert(key.clone(), value_str);
positions.insert(key, key_pos);
}
TokenConfigEntriesResult { entries, positions, warnings }
}
fn apply_positions_to_config_section(
&self,
section: &mut ConfigSection,
positions: &HashMap<String, Position>,
section_position: Position,
) {
section.position = section_position;
for entry in &mut section.entries {
if let Some(&pos) = positions.get(&entry.key) {
entry.position = pos;
}
}
}
fn log_info(&self, message: &str) {
if let Some(ref logger) = self.logger {
if let Ok(mut log) = logger.lock() { log.Info(message); }
}
}
fn log_warning(&self, message: &str) {
if let Some(ref logger) = self.logger {
if let Ok(mut log) = logger.lock() { log.Warning(message); }
}
}
}
#[derive(Debug, Clone)]
pub struct ProcessConfigResult {
pub config_section: ConfigSection,
pub operational_settings: OperationalSettings,
pub warnings: Vec<String>,
}
impl Default for ProcessConfigResult {
fn default() -> Self {
ProcessConfigResult {
config_section: ConfigSchema::create_minimal_config(),
operational_settings: OperationalSettings::default(),
warnings: Vec::new(),
}
}
}
struct TokenConfigEntriesResult {
entries: HashMap<String, String>,
positions: HashMap<String, Position>,
warnings: Vec<String>,
}