1use crate::error::{StatsError, StatsResult};
8use crate::error_diagnostics::{
9 generate_global_health_report, get_global_statistics, global_monitor, record_global_error,
10 ErrorMonitor, HealthReport,
11};
12use crate::error_handling_v2::{EnhancedError, ErrorBuilder, ErrorCode};
13use crate::error_standardization::{ErrorMessages, StandardizedErrorReporter};
14use scirs2_core::validation::{check_finite, check_positive};
15use std::sync::Once;
16use std::time::Instant;
17
18pub struct UnifiedErrorHandler {
20 #[allow(dead_code)]
21 monitor: &'static ErrorMonitor,
22 start_time: Instant,
23}
24
25impl UnifiedErrorHandler {
26 pub fn new() -> Self {
28 Self {
29 monitor: global_monitor(),
30 start_time: Instant::now(),
31 }
32 }
33
34 pub fn create_error(
36 &self,
37 code: ErrorCode,
38 operation: impl Into<String>,
39 message: impl Into<String>,
40 ) -> EnhancedError {
41 let operation_str = operation.into();
42
43 record_global_error(code, &operation_str);
45
46 let base_error = StatsError::computation(message);
48
49 ErrorBuilder::new(code, operation_str).build(base_error)
50 }
51
52 pub fn create_validation_error(
54 &self,
55 code: ErrorCode,
56 operation: impl Into<String>,
57 parameter_name: &str,
58 parameter_value: impl std::fmt::Display,
59 validation_message: impl Into<String>,
60 ) -> EnhancedError {
61 let operation_str = operation.into();
62
63 record_global_error(code, &operation_str);
65
66 let base_error = StatsError::invalid_argument(validation_message);
68
69 ErrorBuilder::new(code, operation_str)
70 .parameter(parameter_name, parameter_value)
71 .build(base_error)
72 }
73
74 pub fn validate_array_or_error<T>(
76 &self,
77 data: &[T],
78 name: &str,
79 operation: &str,
80 ) -> StatsResult<()>
81 where
82 T: PartialOrd + Copy,
83 {
84 if data.is_empty() {
86 let code = ErrorCode::E2004;
87 record_global_error(code, operation);
88 return Err(ErrorMessages::empty_array(name));
89 }
90 Ok(())
91 }
92
93 pub fn validate_finite_array_or_error(
95 &self,
96 data: &[f64],
97 name: &str,
98 operation: &str,
99 ) -> StatsResult<()> {
100 if data.is_empty() {
102 let code = ErrorCode::E2004;
103 record_global_error(code, operation);
104 return Err(ErrorMessages::empty_array(name));
105 }
106
107 for &value in data {
109 if check_finite(value, name).is_err() {
110 let code = if value.is_nan() {
111 ErrorCode::E3005
112 } else if value.is_infinite() {
113 ErrorCode::E3006
114 } else {
115 ErrorCode::E1001
116 };
117 record_global_error(code, operation);
118 return Err(ErrorMessages::nan_detected(operation));
119 }
120 }
121 Ok(())
122 }
123
124 pub fn validate_probability_or_error(
126 &self,
127 value: f64,
128 name: &str,
129 operation: &str,
130 ) -> StatsResult<()> {
131 if scirs2_core::validation::check_probability(value, name).is_err() {
133 let code = if value.is_nan() {
134 ErrorCode::E3005
135 } else if !(0.0..=1.0).contains(&value) {
136 ErrorCode::E1003
137 } else {
138 ErrorCode::E1001
139 };
140
141 record_global_error(code, operation);
142 return Err(ErrorMessages::invalid_probability(name, value));
143 }
144 Ok(())
145 }
146
147 pub fn validate_positive_or_error(
149 &self,
150 value: f64,
151 name: &str,
152 operation: &str,
153 ) -> StatsResult<()> {
154 if check_positive(value, name).is_err() {
156 let code = if value.is_nan() {
157 ErrorCode::E3005
158 } else if value.is_infinite() {
159 ErrorCode::E3006
160 } else if value <= 0.0 {
161 ErrorCode::E1002
162 } else {
163 ErrorCode::E1001
164 };
165
166 record_global_error(code, operation);
167 return Err(ErrorMessages::non_positive_value(name, value));
168 }
169 Ok(())
170 }
171
172 pub fn generate_comprehensive_report(
174 &self,
175 error: &StatsError,
176 context: Option<&str>,
177 ) -> String {
178 let mut report = StandardizedErrorReporter::generate_report(error, context);
179
180 let health_report = generate_global_health_report();
182 if health_report.health_score < 80 {
183 report.push_str("\n🚨 SYSTEM HEALTH ALERT:\n");
184 report.push_str(&format!(
185 "Overall health score: {}/100\n",
186 health_report.health_score
187 ));
188
189 if !health_report.critical_issues.is_empty() {
190 report.push_str("Critical issues detected:\n");
191 for issue in &health_report.critical_issues {
192 report.push_str(&format!(
193 " • {} (Severity: {})\n",
194 issue.title, issue.severity
195 ));
196 }
197 }
198 }
199
200 let stats = get_global_statistics();
202 if stats.total_errors > 10 {
203 report.push_str(&format!(
204 "\n📊 Error Statistics: {} total errors, {:.4} errors/sec\n",
205 stats.total_errors, stats.error_rate
206 ));
207 }
208
209 report
210 }
211
212 pub fn get_health_status(&self) -> HealthReport {
214 generate_global_health_report()
215 }
216
217 pub fn requires_immediate_attention(&self) -> bool {
219 let health_report = generate_global_health_report();
220 health_report.requires_immediate_action()
221 }
222
223 pub fn uptime(&self) -> std::time::Duration {
225 self.start_time.elapsed()
226 }
227
228 pub fn print_health_summary(&self) {
230 let health_report = generate_global_health_report();
231 println!("{}", health_report.to_formatted_string());
232 }
233}
234
235impl Default for UnifiedErrorHandler {
236 fn default() -> Self {
237 Self::new()
238 }
239}
240
241static GLOBAL_HANDLER: Once = Once::new();
243static mut GLOBAL_HANDLER_INSTANCE: Option<UnifiedErrorHandler> = None;
244
245#[allow(dead_code)]
247#[allow(static_mut_refs)]
248pub fn global_error_handler() -> &'static UnifiedErrorHandler {
249 unsafe {
250 GLOBAL_HANDLER.call_once(|| {
251 GLOBAL_HANDLER_INSTANCE = Some(UnifiedErrorHandler::new());
252 });
253 GLOBAL_HANDLER_INSTANCE.as_ref().unwrap()
254 }
255}
256
257#[macro_export]
259macro_rules! stats_error_unified {
260 ($code:expr, $op:expr, $msg:expr) => {
261 $crate::unified_error_handling::global_error_handler().create_error($code, $op, $msg)
262 };
263
264 ($code:expr, $op:expr, $msg:expr, $param:expr => $value:expr) => {
265 $crate::unified_error_handling::global_error_handler()
266 .create_validation_error($code, $op, $param, $value, $msg)
267 };
268}
269
270#[macro_export]
272macro_rules! validate_or_error {
273 (array: $data:expr, $name:expr, $op:expr) => {
274 $crate::unified_error_handling::global_error_handler()
275 .validate_array_or_error($data, $name, $op)?
276 };
277
278 (finite: $data:expr, $name:expr, $op:expr) => {
279 $crate::unified_error_handling::global_error_handler()
280 .validate_finite_array_or_error($data, $name, $op)?
281 };
282
283 (probability: $value:expr, $name:expr, $op:expr) => {
284 $crate::unified_error_handling::global_error_handler()
285 .validate_probability_or_error($value, $name, $op)?
286 };
287
288 (positive: $value:expr, $name:expr, $op:expr) => {
289 $crate::unified_error_handling::global_error_handler()
290 .validate_positive_or_error($value, $name, $op)?
291 };
292}
293
294#[allow(dead_code)]
296pub fn create_standardized_error(
297 error_type: &str,
298 parameter: &str,
299 value: &str,
300 operation: &str,
301) -> StatsError {
302 match error_type {
303 "dimension_mismatch" => ErrorMessages::dimension_mismatch(parameter, value),
304 "empty_array" => ErrorMessages::empty_array(parameter),
305 "non_positive" => {
306 ErrorMessages::non_positive_value(parameter, value.parse().unwrap_or(0.0))
307 }
308 "invalid_probability" => {
309 ErrorMessages::invalid_probability(parameter, value.parse().unwrap_or(-1.0))
310 }
311 "nan_detected" => ErrorMessages::nan_detected(operation),
312 "infinite_detected" => ErrorMessages::infinite_value_detected(operation),
313 "convergence_failure" => {
314 ErrorMessages::convergence_failure(operation, value.parse().unwrap_or(100))
315 }
316 _ => StatsError::invalid_argument(format!("Unknown error type: {}", error_type)),
317 }
318}
319
320#[cfg(test)]
321mod tests {
322 use super::*;
323 use crate::error_handling_v2::ErrorCode;
324
325 #[test]
326 fn test_unified_error_handler() {
327 let handler = UnifiedErrorHandler::new();
328
329 let error = handler.create_error(ErrorCode::E3005, "test_operation", "Test error message");
331
332 assert_eq!(error.code, ErrorCode::E3005);
333 assert_eq!(error.context.operation, "test_operation");
334 }
335
336 #[test]
337 fn test_validation_errors() {
338 let handler = UnifiedErrorHandler::new();
339
340 let empty_data: &[f64] = &[];
342 let result = handler.validate_array_or_error(empty_data, "test_array", "test_op");
343 assert!(result.is_err());
344
345 let nandata = &[1.0, f64::NAN, 3.0];
347 let result = handler.validate_finite_array_or_error(nandata, "test_array", "test_op");
348 assert!(result.is_err());
349
350 let result = handler.validate_probability_or_error(-0.5, "probability", "test_op");
352 assert!(result.is_err());
353
354 let result = handler.validate_positive_or_error(-1.0, "positive_param", "test_op");
356 assert!(result.is_err());
357 }
358
359 #[test]
360 fn test_global_handler() {
361 let handler1 = global_error_handler();
362 let handler2 = global_error_handler();
363
364 assert_eq!(handler1 as *const _, handler2 as *const _);
366 }
367
368 #[test]
369 fn test_macros() {
370 let _error = stats_error_unified!(ErrorCode::E1001, "test_operation", "Test message");
372
373 let validdata = &[1.0, 2.0, 3.0];
375 let result: Result<(), StatsError> = (|| {
376 validate_or_error!(finite: validdata, "testdata", "test_op");
377 Ok(())
378 })();
379 assert!(result.is_ok());
380 }
381}