1use crate::colors;
2use crate::common_options::{get_optimized_reader, setup_automatic_optimization_config};
3use clap::ArgMatches;
4use lawkit_core::common::input::parse_text_input;
5use lawkit_core::common::output::OutputConfig;
6use lawkit_core::error::{BenfError, Result};
7use lawkit_core::laws::integration::IntegrationResult;
8use lawkit_core::{IntegrationData, LawkitResult};
9use std::io::Write;
10
11#[allow(dead_code)]
12pub fn print_integration_header(matches: &ArgMatches) {
13 let no_color = matches.get_flag("no-color");
14
15 if no_color {
16 println!("LAWKIT INTEGRATED ANALYSIS");
17 println!("==========================");
18 } else {
19 println!("{}", colors::bold("LAWKIT INTEGRATED ANALYSIS"));
20 println!("{}", colors::bold("=========================="));
21 }
22 println!();
23}
24
25#[allow(dead_code)]
26pub fn print_integration_summary(data: &IntegrationData, no_color: bool) {
27 println!("{}", data.analysis_summary);
29 println!();
30
31 if no_color {
33 println!("LAWS ANALYZED");
34 println!("-------------");
35 } else {
36 println!("{}", colors::bold("LAWS ANALYZED"));
37 println!("{}", colors::bold("-------------"));
38 }
39
40 for law in &data.laws_analyzed {
41 println!("✓ {law}");
42 }
43 println!();
44
45 let risk_display = if no_color {
47 format!("Overall Risk Level: {}", data.overall_risk)
48 } else {
49 match data.overall_risk.as_str() {
50 "HIGH" => format!("Overall Risk Level: {}", colors::red(&data.overall_risk)),
51 "MEDIUM" => format!("Overall Risk Level: {}", colors::yellow(&data.overall_risk)),
52 _ => format!("Overall Risk Level: {}", colors::green(&data.overall_risk)),
53 }
54 };
55 println!("{risk_display}");
56 println!();
57
58 if !data.conflicting_results.is_empty() {
60 if no_color {
61 println!("CONFLICTING RESULTS");
62 println!("-------------------");
63 } else {
64 println!("{}", colors::bold("CONFLICTING RESULTS"));
65 println!("{}", colors::bold("-------------------"));
66 }
67
68 for conflict in &data.conflicting_results {
69 let msg = format!("⚠ {conflict}");
70 println!("{}", if no_color { msg } else { colors::yellow(&msg) });
71 }
72 println!();
73 }
74
75 if !data.recommendations.is_empty() {
77 if no_color {
78 println!("RECOMMENDATIONS");
79 println!("---------------");
80 } else {
81 println!("{}", colors::bold("RECOMMENDATIONS"));
82 println!("{}", colors::bold("---------------"));
83 }
84
85 for recommendation in &data.recommendations {
86 println!("• {recommendation}");
87 }
88 println!();
89 }
90}
91
92#[allow(dead_code)]
93pub fn print_individual_results(results: &[LawkitResult], matches: &ArgMatches) {
94 let no_color = matches.get_flag("no-color");
95 let verbose = matches.get_flag("verbose");
96
97 for result in results {
98 match result {
99 LawkitResult::BenfordAnalysis(name, data) => {
100 println!();
101 if no_color {
102 println!("--- {} ---", name.to_uppercase());
103 } else {
104 println!("--- {} ---", colors::cyan(&name.to_uppercase()));
105 }
106 println!("Risk Level: {}", data.risk_level);
107 if verbose {
108 println!(
109 "Chi-square: {:.4}, P-value: {:.4}, MAD: {:.4}",
110 data.chi_square, data.p_value, data.mad
111 );
112 }
113 }
114 LawkitResult::ParetoAnalysis(name, data) => {
115 println!();
116 if no_color {
117 println!("--- {} ---", name.to_uppercase());
118 } else {
119 println!("--- {} ---", colors::cyan(&name.to_uppercase()));
120 }
121 println!("Risk Level: {}", data.risk_level);
122 if verbose {
123 println!(
124 "Top 20% contribution: {:.1}%, Pareto ratio: {:.2}",
125 data.top_20_percent_contribution, data.pareto_ratio
126 );
127 }
128 }
129 LawkitResult::ZipfAnalysis(name, data) => {
130 println!();
131 if no_color {
132 println!("--- {} ---", name.to_uppercase());
133 } else {
134 println!("--- {} ---", colors::cyan(&name.to_uppercase()));
135 }
136 println!("Risk Level: {}", data.risk_level);
137 if verbose {
138 println!(
139 "Zipf coefficient: {:.3}, Correlation: {:.3}",
140 data.zipf_coefficient, data.correlation_coefficient
141 );
142 }
143 }
144 LawkitResult::NormalAnalysis(name, data) => {
145 println!();
146 if no_color {
147 println!("--- {} ---", name.to_uppercase());
148 } else {
149 println!("--- {} ---", colors::cyan(&name.to_uppercase()));
150 }
151 println!("Risk Level: {}", data.risk_level);
152 if verbose {
153 println!(
154 "Mean: {:.3}, Std Dev: {:.3}, Skewness: {:.3}, Kurtosis: {:.3}",
155 data.mean, data.std_dev, data.skewness, data.kurtosis
156 );
157 }
158 }
159 LawkitResult::PoissonAnalysis(name, data) => {
160 println!();
161 if no_color {
162 println!("--- {} ---", name.to_uppercase());
163 } else {
164 println!("--- {} ---", colors::cyan(&name.to_uppercase()));
165 }
166 println!("Risk Level: {}", data.risk_level);
167 if verbose {
168 println!(
169 "Lambda: {:.3}, Variance ratio: {:.3}, P-value: {:.4}",
170 data.lambda, data.variance_ratio, data.poisson_test_p
171 );
172 }
173 }
174 _ => {} }
176 }
177}
178
179pub fn get_dataset_name(matches: &ArgMatches) -> String {
180 matches
181 .get_one::<String>("input")
182 .map(|s| s.to_string())
183 .unwrap_or_else(|| "stdin".to_string())
184}
185
186pub fn get_numbers_from_input(matches: &ArgMatches) -> Result<Vec<f64>> {
187 let (_parallel_config, _memory_config) = setup_automatic_optimization_config();
188
189 let buffer = if let Some(input) = matches.get_one::<String>("input") {
190 if input == "-" {
191 get_optimized_reader(None)
192 } else {
193 get_optimized_reader(Some(input))
194 }
195 } else {
196 get_optimized_reader(None)
197 };
198
199 let data = buffer.map_err(|e| BenfError::ParseError(e.to_string()))?;
200 parse_text_input(&data)
201}
202
203pub fn output_integration_result(
204 writer: &mut Box<dyn Write>,
205 result: &IntegrationResult,
206 config: &OutputConfig,
207) -> Result<()> {
208 match config.format.as_str() {
209 "text" => output_text_integration_result(writer, result, config),
210 "json" => output_json_integration_result(writer, result),
211 "csv" => output_csv_integration_result(writer, result),
212 "yaml" => output_yaml_integration_result(writer, result),
213 "toml" => output_toml_integration_result(writer, result),
214 "xml" => output_xml_integration_result(writer, result),
215 _ => output_text_integration_result(writer, result, config),
216 }
217}
218
219fn output_text_integration_result(
220 writer: &mut Box<dyn Write>,
221 result: &IntegrationResult,
222 config: &OutputConfig,
223) -> Result<()> {
224 writeln!(writer, "Integration Analysis Results")?;
225 writeln!(writer, "=============================")?;
226 writeln!(writer)?;
227
228 writeln!(writer, "Dataset: {}", result.dataset_name)?;
229 writeln!(writer, "Overall Risk Level: {:?}", result.risk_level)?;
230 writeln!(writer)?;
231
232 if !config.quiet {
233 writeln!(writer, "Laws Executed: {}", result.laws_executed.join(", "))?;
234 writeln!(
235 writer,
236 "Overall Quality Score: {:.3}",
237 result.overall_quality_score
238 )?;
239 writeln!(writer, "Consistency Score: {:.3}", result.consistency_score)?;
240 writeln!(writer, "Conflicts Detected: {}", result.conflicts_detected)?;
241 writeln!(writer)?;
242
243 if let Some(ref benford) = result.benford_result {
244 writeln!(
245 writer,
246 "- Benford Law: {} (Chi-square: {:.4})",
247 benford.risk_level, benford.chi_square
248 )?;
249 }
250 if let Some(ref pareto) = result.pareto_result {
251 writeln!(
252 writer,
253 "- Pareto Principle: {} (Top 20%: {:.1}%)",
254 pareto.risk_level, pareto.top_20_percent_share
255 )?;
256 }
257 if let Some(ref zipf) = result.zipf_result {
258 writeln!(
259 writer,
260 "- Zipf Law: {} (Exponent: {:.3})",
261 zipf.risk_level, zipf.zipf_exponent
262 )?;
263 }
264 if let Some(ref normal) = result.normal_result {
265 writeln!(
266 writer,
267 "- Normal Distribution: {} (Mean: {:.3})",
268 normal.risk_level, normal.mean
269 )?;
270 }
271 if let Some(ref poisson) = result.poisson_result {
272 writeln!(
273 writer,
274 "- Poisson Distribution: {} (Lambda: {:.3})",
275 poisson.risk_level, poisson.lambda
276 )?;
277 }
278 writeln!(writer)?;
279 }
280
281 if !result.conflicts.is_empty() {
282 writeln!(writer, "Conflicts:")?;
283 for conflict in &result.conflicts {
284 writeln!(writer, "• {}", conflict.description)?;
285 }
286 writeln!(writer)?;
287 }
288
289 Ok(())
290}
291
292fn output_json_integration_result(
293 writer: &mut Box<dyn Write>,
294 result: &IntegrationResult,
295) -> Result<()> {
296 use serde_json::json;
297
298 let output = json!({
299 "dataset_name": result.dataset_name,
300 "risk_level": format!("{:?}", result.risk_level),
301 "numbers_analyzed": result.numbers_analyzed,
302 "laws_executed": result.laws_executed,
303 "overall_quality_score": result.overall_quality_score,
304 "consistency_score": result.consistency_score,
305 "conflicts_detected": result.conflicts_detected
306 });
307
308 writeln!(writer, "{}", serde_json::to_string_pretty(&output).unwrap())?;
309 Ok(())
310}
311
312fn output_csv_integration_result(
313 writer: &mut Box<dyn Write>,
314 result: &IntegrationResult,
315) -> Result<()> {
316 writeln!(
317 writer,
318 "dataset,risk_level,quality_score,consistency_score,conflicts"
319 )?;
320 writeln!(
321 writer,
322 "{},{:?},{:.3},{:.3},{}",
323 result.dataset_name,
324 result.risk_level,
325 result.overall_quality_score,
326 result.consistency_score,
327 result.conflicts_detected
328 )?;
329 Ok(())
330}
331
332fn output_yaml_integration_result(
333 writer: &mut Box<dyn Write>,
334 result: &IntegrationResult,
335) -> Result<()> {
336 writeln!(writer, "dataset_name: \"{}\"", result.dataset_name)?;
337 writeln!(writer, "risk_level: \"{:?}\"", result.risk_level)?;
338 writeln!(
339 writer,
340 "primary_recommendation: {}",
341 result.recommendations.primary_law
342 )?;
343 writeln!(
344 writer,
345 "recommendation_confidence: {:.3}",
346 result.recommendations.confidence
347 )?;
348 Ok(())
349}
350
351fn output_toml_integration_result(
352 writer: &mut Box<dyn Write>,
353 result: &IntegrationResult,
354) -> Result<()> {
355 writeln!(writer, "dataset_name = \"{}\"", result.dataset_name)?;
356 writeln!(writer, "risk_level = \"{:?}\"", result.risk_level)?;
357 writeln!(
358 writer,
359 "primary_recommendation = \"{}\"",
360 result.recommendations.primary_law
361 )?;
362 writeln!(
363 writer,
364 "recommendation_confidence = {:.3}",
365 result.recommendations.confidence
366 )?;
367 Ok(())
368}
369
370fn output_xml_integration_result(
371 writer: &mut Box<dyn Write>,
372 result: &IntegrationResult,
373) -> Result<()> {
374 writeln!(writer, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>")?;
375 writeln!(writer, "<integration_analysis>")?;
376 writeln!(
377 writer,
378 " <dataset_name>{}</dataset_name>",
379 result.dataset_name
380 )?;
381 writeln!(writer, " <risk_level>{:?}</risk_level>", result.risk_level)?;
382 writeln!(
383 writer,
384 " <primary_recommendation>{}</primary_recommendation>",
385 result.recommendations.primary_law
386 )?;
387 writeln!(
388 writer,
389 " <recommendation_confidence>{:.3}</recommendation_confidence>",
390 result.recommendations.confidence
391 )?;
392 writeln!(writer, "</integration_analysis>")?;
393 Ok(())
394}
395
396pub fn parse_analysis_purpose(purpose: &str) -> lawkit_core::laws::integration::AnalysisPurpose {
397 use lawkit_core::laws::integration::AnalysisPurpose;
398 match purpose {
399 "quality" => AnalysisPurpose::QualityAudit,
400 "fraud" => AnalysisPurpose::FraudDetection,
401 "concentration" => AnalysisPurpose::ConcentrationAnalysis,
402 "anomaly" => AnalysisPurpose::AnomalyDetection,
403 "distribution" => AnalysisPurpose::DistributionFitting,
404 _ => AnalysisPurpose::GeneralAnalysis,
405 }
406}