use std::{collections::HashSet, hash::Hash};
use serde::{Deserialize, Serialize};
use crate::{diff::TreeDiff, uslm::AmendingAction};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LegalDiff {
pub tree_diff: TreeDiff,
pub annotations: Vec<ChangeAnnotation>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ChangeAnnotation {
pub operation: AmendingAction,
pub source_bill: BillReference,
pub paths: Vec<String>,
pub metadata: AnnotationMetadata,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BillReference {
pub bill_id: String,
pub amendment_id: String,
pub causative_text: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AnnotationMetadata {
pub status: AnnotationStatus,
pub confidence: Option<f32>,
pub annotator: String,
pub timestamp: time::OffsetDateTime,
pub notes: Option<String>,
pub reasoning: Option<String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum AnnotationStatus {
Pending,
Verified,
Disputed,
Rejected,
}
impl LegalDiff {
pub fn new(tree_diff: &TreeDiff) -> Self {
LegalDiff {
tree_diff: tree_diff.clone(),
annotations: Vec::new(),
}
}
pub fn add_annotation(&mut self, annotation: ChangeAnnotation) {
self.annotations.push(annotation);
}
pub fn get_annotations(&self, path: &str) -> Vec<&ChangeAnnotation> {
let path_string = String::from(path);
let matches: Vec<&ChangeAnnotation> = self
.annotations
.iter()
.filter(|annotation| annotation.paths.contains(&path_string))
.collect();
matches
}
pub fn get_diff_node(&self, path: &str) -> Option<&TreeDiff> {
self.tree_diff.find(path)
}
pub fn annotated_paths(&self) -> HashSet<String> {
self.annotations
.iter()
.flat_map(|annotation| annotation.paths.clone())
.collect()
}
pub fn unannotated_paths(&self) -> Vec<String> {
let a_paths = self.annotated_paths();
let mut paths_with_changes = Vec::new();
Self::collect_paths_with_changes(&self.tree_diff, &mut paths_with_changes);
paths_with_changes
.into_iter()
.filter(|p| !a_paths.contains(p))
.collect()
}
fn collect_paths_with_changes(diff: &TreeDiff, paths: &mut Vec<String>) {
if !diff.changes.is_empty() || !diff.added.is_empty() || !diff.removed.is_empty() {
paths.push(diff.root_path.clone());
}
for child in &diff.child_diffs {
Self::collect_paths_with_changes(child, paths);
}
}
}