use mig_assembly::assembler::{Assembler, AssemblerConfig};
use mig_assembly::StructureDiagnosticKind;
use mig_types::schema::mig::MigSchema;
use mig_types::segment::OwnedSegment;
use crate::eval::{ConditionEvaluator, ExternalConditionProvider};
use crate::{
build_validated_tree, validate_unt_segment_count, AhbWorkflow, EdifactValidator, IssueKind,
Severity, ValidationIssue, ValidationLevel, ValidationReport,
};
pub fn validate_edifact_message<E: ConditionEvaluator>(
all_segments: &[OwnedSegment],
filtered_mig: &MigSchema,
workflow: &AhbWorkflow,
evaluator: E,
external: &dyn ExternalConditionProvider,
level: ValidationLevel,
) -> ValidationReport {
validate_edifact_message_with_structure(
all_segments,
filtered_mig,
None,
workflow,
evaluator,
external,
level,
)
}
pub fn validate_edifact_message_with_structure<E: ConditionEvaluator>(
all_segments: &[OwnedSegment],
filtered_mig: &MigSchema,
pid_mig: Option<&MigSchema>,
workflow: &AhbWorkflow,
evaluator: E,
external: &dyn ExternalConditionProvider,
level: ValidationLevel,
) -> ValidationReport {
validate_message(
all_segments,
filtered_mig,
pid_mig,
workflow,
EdifactValidator::new(evaluator),
external,
level,
)
}
pub fn validate_edifact_message_reporting_segments<E: ConditionEvaluator>(
all_segments: &[OwnedSegment],
filtered_mig: &MigSchema,
workflow: &AhbWorkflow,
evaluator: E,
external: &dyn ExternalConditionProvider,
level: ValidationLevel,
) -> ValidationReport {
validate_message(
all_segments,
filtered_mig,
None,
workflow,
EdifactValidator::new(evaluator).reporting_segments(),
external,
level,
)
}
fn validate_message<E: ConditionEvaluator>(
all_segments: &[OwnedSegment],
filtered_mig: &MigSchema,
pid_mig: Option<&MigSchema>,
workflow: &AhbWorkflow,
validator: EdifactValidator<E>,
external: &dyn ExternalConditionProvider,
level: ValidationLevel,
) -> ValidationReport {
let assembler = Assembler::with_config(
filtered_mig,
AssemblerConfig {
strict_code_matching: true,
skip_unknown_segments: true,
..Default::default()
},
);
let (tree, mut structure_diagnostics) = assembler.assemble_with_diagnostics(all_segments);
if let Some(pid_mig) = pid_mig {
structure_diagnostics.extend(mig_assembly::structure_check::check_structure(
&tree, pid_mig,
));
}
let validated_tree = build_validated_tree(workflow, &tree);
let mut report =
validator.validate_assembled_tree(&validated_tree, all_segments, external, level, &tree);
if level == ValidationLevel::Full {
let message_type = report.message_type.clone();
report.add_issues(crate::consistency::check_consistency(
all_segments,
&message_type,
));
}
if let Some(issue) = validate_unt_segment_count(all_segments) {
report.add_issue(issue);
}
for diag in structure_diagnostics {
let severity = match diag.kind {
StructureDiagnosticKind::MissingRequiredSegment
| StructureDiagnosticKind::MissingRequiredGroup
| StructureDiagnosticKind::MaxRepetitionsExceeded
| StructureDiagnosticKind::GroupMaxRepetitionsExceeded => Severity::Error,
_ => Severity::Warning,
};
let at = u32::try_from(diag.position).unwrap_or(0);
let kind = IssueKind::StructureDiagnostic {
kind: diag.kind,
segment_id: diag.segment_id.clone(),
position: diag.position,
detail: diag.message,
};
let mut issue = ValidationIssue::new(severity, kind);
if at > 0 {
issue = issue.with_position(crate::SegmentPosition::at(at));
}
report.add_issue(issue);
}
number_from_unh(&mut report, all_segments);
report
}
fn number_from_unh(report: &mut ValidationReport, all_segments: &[OwnedSegment]) {
let Some(unh) = all_segments
.iter()
.find(|s| s.id == "UNH")
.map(|s| s.segment_number)
.filter(|&n| n > 0)
else {
return;
};
let unt = all_segments
.iter()
.rev()
.find(|s| s.id == "UNT")
.map(|s| s.segment_number)
.unwrap_or(u32::MAX);
for issue in &mut report.issues {
if let Some(pos) = issue.segment_position.as_mut() {
if (unh..=unt).contains(&pos.segment_number) {
pos.message_segment_number = Some(pos.segment_number - unh + 1);
}
}
}
}