use crate::error::{StatsError, StatsResult};
use crate::error_diagnostics::{
generate_global_health_report, get_global_statistics, global_monitor, record_global_error,
ErrorMonitor, HealthReport,
};
use crate::error_handling_v2::{EnhancedError, ErrorBuilder, ErrorCode};
use crate::error_standardization::{ErrorMessages, StandardizedErrorReporter};
use scirs2_core::validation::{check_finite, check_positive};
use std::sync::Once;
use std::time::Instant;
pub struct UnifiedErrorHandler {
#[allow(dead_code)]
monitor: &'static ErrorMonitor,
start_time: Instant,
}
impl UnifiedErrorHandler {
pub fn new() -> Self {
Self {
monitor: global_monitor(),
start_time: Instant::now(),
}
}
pub fn create_error(
&self,
code: ErrorCode,
operation: impl Into<String>,
message: impl Into<String>,
) -> EnhancedError {
let operation_str = operation.into();
record_global_error(code, &operation_str);
let base_error = StatsError::computation(message);
ErrorBuilder::new(code, operation_str).build(base_error)
}
pub fn create_validation_error(
&self,
code: ErrorCode,
operation: impl Into<String>,
parameter_name: &str,
parameter_value: impl std::fmt::Display,
validation_message: impl Into<String>,
) -> EnhancedError {
let operation_str = operation.into();
record_global_error(code, &operation_str);
let base_error = StatsError::invalid_argument(validation_message);
ErrorBuilder::new(code, operation_str)
.parameter(parameter_name, parameter_value)
.build(base_error)
}
pub fn validate_array_or_error<T>(
&self,
data: &[T],
name: &str,
operation: &str,
) -> StatsResult<()>
where
T: PartialOrd + Copy,
{
if data.is_empty() {
let code = ErrorCode::E2004;
record_global_error(code, operation);
return Err(ErrorMessages::empty_array(name));
}
Ok(())
}
pub fn validate_finite_array_or_error(
&self,
data: &[f64],
name: &str,
operation: &str,
) -> StatsResult<()> {
if data.is_empty() {
let code = ErrorCode::E2004;
record_global_error(code, operation);
return Err(ErrorMessages::empty_array(name));
}
for &value in data {
if check_finite(value, name).is_err() {
let code = if value.is_nan() {
ErrorCode::E3005
} else if value.is_infinite() {
ErrorCode::E3006
} else {
ErrorCode::E1001
};
record_global_error(code, operation);
return Err(ErrorMessages::nan_detected(operation));
}
}
Ok(())
}
pub fn validate_probability_or_error(
&self,
value: f64,
name: &str,
operation: &str,
) -> StatsResult<()> {
if scirs2_core::validation::check_probability(value, name).is_err() {
let code = if value.is_nan() {
ErrorCode::E3005
} else if !(0.0..=1.0).contains(&value) {
ErrorCode::E1003
} else {
ErrorCode::E1001
};
record_global_error(code, operation);
return Err(ErrorMessages::invalid_probability(name, value));
}
Ok(())
}
pub fn validate_positive_or_error(
&self,
value: f64,
name: &str,
operation: &str,
) -> StatsResult<()> {
if check_positive(value, name).is_err() {
let code = if value.is_nan() {
ErrorCode::E3005
} else if value.is_infinite() {
ErrorCode::E3006
} else if value <= 0.0 {
ErrorCode::E1002
} else {
ErrorCode::E1001
};
record_global_error(code, operation);
return Err(ErrorMessages::non_positive_value(name, value));
}
Ok(())
}
pub fn generate_comprehensive_report(
&self,
error: &StatsError,
context: Option<&str>,
) -> String {
let mut report = StandardizedErrorReporter::generate_report(error, context);
let health_report = generate_global_health_report();
if health_report.health_score < 80 {
report.push_str("\n🚨 SYSTEM HEALTH ALERT:\n");
report.push_str(&format!(
"Overall health score: {}/100\n",
health_report.health_score
));
if !health_report.critical_issues.is_empty() {
report.push_str("Critical issues detected:\n");
for issue in &health_report.critical_issues {
report.push_str(&format!(
" • {} (Severity: {})\n",
issue.title, issue.severity
));
}
}
}
let stats = get_global_statistics();
if stats.total_errors > 10 {
report.push_str(&format!(
"\n📊 Error Statistics: {} total errors, {:.4} errors/sec\n",
stats.total_errors, stats.error_rate
));
}
report
}
pub fn get_health_status(&self) -> HealthReport {
generate_global_health_report()
}
pub fn requires_immediate_attention(&self) -> bool {
let health_report = generate_global_health_report();
health_report.requires_immediate_action()
}
pub fn uptime(&self) -> std::time::Duration {
self.start_time.elapsed()
}
pub fn print_health_summary(&self) {
let health_report = generate_global_health_report();
println!("{}", health_report.to_formatted_string());
}
}
impl Default for UnifiedErrorHandler {
fn default() -> Self {
Self::new()
}
}
static GLOBAL_HANDLER: Once = Once::new();
static mut GLOBAL_HANDLER_INSTANCE: Option<UnifiedErrorHandler> = None;
#[allow(dead_code)]
#[allow(static_mut_refs)]
pub fn global_error_handler() -> &'static UnifiedErrorHandler {
unsafe {
GLOBAL_HANDLER.call_once(|| {
GLOBAL_HANDLER_INSTANCE = Some(UnifiedErrorHandler::new());
});
GLOBAL_HANDLER_INSTANCE.as_ref().expect("Operation failed")
}
}
#[macro_export]
macro_rules! stats_error_unified {
($code:expr, $op:expr, $msg:expr) => {
$crate::unified_error_handling::global_error_handler().create_error($code, $op, $msg)
};
($code:expr, $op:expr, $msg:expr, $param:expr => $value:expr) => {
$crate::unified_error_handling::global_error_handler()
.create_validation_error($code, $op, $param, $value, $msg)
};
}
#[macro_export]
macro_rules! validate_or_error {
(array: $data:expr, $name:expr, $op:expr) => {
$crate::unified_error_handling::global_error_handler()
.validate_array_or_error($data, $name, $op)?
};
(finite: $data:expr, $name:expr, $op:expr) => {
$crate::unified_error_handling::global_error_handler()
.validate_finite_array_or_error($data, $name, $op)?
};
(probability: $value:expr, $name:expr, $op:expr) => {
$crate::unified_error_handling::global_error_handler()
.validate_probability_or_error($value, $name, $op)?
};
(positive: $value:expr, $name:expr, $op:expr) => {
$crate::unified_error_handling::global_error_handler()
.validate_positive_or_error($value, $name, $op)?
};
}
#[allow(dead_code)]
pub fn create_standardized_error(
error_type: &str,
parameter: &str,
value: &str,
operation: &str,
) -> StatsError {
match error_type {
"dimension_mismatch" => ErrorMessages::dimension_mismatch(parameter, value),
"empty_array" => ErrorMessages::empty_array(parameter),
"non_positive" => {
ErrorMessages::non_positive_value(parameter, value.parse().unwrap_or(0.0))
}
"invalid_probability" => {
ErrorMessages::invalid_probability(parameter, value.parse().unwrap_or(-1.0))
}
"nan_detected" => ErrorMessages::nan_detected(operation),
"infinite_detected" => ErrorMessages::infinite_value_detected(operation),
"convergence_failure" => {
ErrorMessages::convergence_failure(operation, value.parse().unwrap_or(100))
}
_ => StatsError::invalid_argument(format!("Unknown error type: {}", error_type)),
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::error_handling_v2::ErrorCode;
#[test]
fn test_unified_error_handler() {
let handler = UnifiedErrorHandler::new();
let error = handler.create_error(ErrorCode::E3005, "test_operation", "Test error message");
assert_eq!(error.code, ErrorCode::E3005);
assert_eq!(error.context.operation, "test_operation");
}
#[test]
fn test_validation_errors() {
let handler = UnifiedErrorHandler::new();
let empty_data: &[f64] = &[];
let result = handler.validate_array_or_error(empty_data, "test_array", "test_op");
assert!(result.is_err());
let nandata = &[1.0, f64::NAN, 3.0];
let result = handler.validate_finite_array_or_error(nandata, "test_array", "test_op");
assert!(result.is_err());
let result = handler.validate_probability_or_error(-0.5, "probability", "test_op");
assert!(result.is_err());
let result = handler.validate_positive_or_error(-1.0, "positive_param", "test_op");
assert!(result.is_err());
}
#[test]
fn test_global_handler() {
let handler1 = global_error_handler();
let handler2 = global_error_handler();
assert_eq!(handler1 as *const _, handler2 as *const _);
}
#[test]
fn test_macros() {
let _error = stats_error_unified!(ErrorCode::E1001, "test_operation", "Test message");
let validdata = &[1.0, 2.0, 3.0];
let result: Result<(), StatsError> = (|| {
validate_or_error!(finite: validdata, "testdata", "test_op");
Ok(())
})();
assert!(result.is_ok());
}
}