use regex::Regex;
use unicode_segmentation::UnicodeSegmentation;
use unicode_width::UnicodeWidthStr;
use crate::align;
use crate::minusplus::MinusPlus;
/// Infer the edit operations responsible for the differences between a collection of old and new
/// lines. A "line" is a string. An annotated line is a Vec of (op, &str) pairs, where the &str
/// slices are slices of the line, and their concatenation equals the line. Return the input minus
/// and plus lines, in annotated form.
///
/// Also return a specification of the inferred alignment of minus and plus lines: a paired minus
/// and plus line is represented in this alignment specification as
/// (Some(minus_line_index),Some(plus_line_index)), whereas an unpaired minus line is
/// (Some(minus_line_index), None).
///
/// `noop_deletions[i]` is the appropriate deletion operation tag to be used for `minus_lines[i]`;
/// `noop_deletions` is guaranteed to be the same length as `minus_lines`. The equivalent statements
/// hold for `plus_insertions` and `plus_lines`.
#[allow(clippy::too_many_arguments)]
#[allow(clippy::type_complexity)]
pub fn infer_edits<'a, EditOperation>(
minus_lines: Vec<&'a str>,
plus_lines: Vec<&'a str>,
noop_deletions: Vec<EditOperation>,
deletion: EditOperation,
noop_insertions: Vec<EditOperation>,
insertion: EditOperation,
tokenization_regex: &Regex,
max_line_distance: f64,
max_line_distance_for_naively_paired_lines: f64,
) -> (
Vec<Vec<(EditOperation, &'a str)>>, // annotated minus lines
Vec<Vec<(EditOperation, &'a str)>>, // annotated plus lines
Vec<(Option<usize>, Option<usize>)>, // line alignment
)
where
EditOperation: Copy + PartialEq + std::fmt::Debug,
{
let mut annotated_minus_lines = Vec::<Vec<(EditOperation, &str)>>::new();
let mut annotated_plus_lines = Vec::<Vec<(EditOperation, &str)>>::new();
let mut line_alignment = Vec::<(Option<usize>, Option<usize>)>::new();
let mut plus_index = 0; // plus lines emitted so far
'minus_lines_loop: for (minus_index, minus_line) in minus_lines.iter().enumerate() {
let mut considered = 0; // plus lines considered so far as match for minus_line
for plus_line in &plus_lines[plus_index..] {
let alignment = align::Alignment::new(
tokenize(minus_line, tokenization_regex),
tokenize(plus_line, tokenization_regex),
);
let (annotated_minus_line, annotated_plus_line, distance) = annotate(
alignment,
noop_deletions[minus_index],
deletion,
noop_insertions[plus_index],
insertion,
minus_line,
plus_line,