use indicatrix::{geometry::meet_solver::SolvedTier, optics::materials::GemMaterial};
use indicatrix_cut_core::Design;
use indicatrix_editor::raw_text::{DiffKind, TextDiff, diff_lines, generate_text};
const CONTEXT_LINES: usize = 3;
const SCOPE_NOTE: &str = "The text holds the cutting instructions only. A different rough, girdle size or material shows in the pictures, not here.";
#[derive(Debug, Clone, PartialEq, Eq)]
pub(super) struct DiffLine {
pub(super) kind: i32,
pub(super) old_line: String,
pub(super) new_line: String,
pub(super) text: String,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub(super) struct DiffView {
pub(super) title: String,
pub(super) summary: String,
pub(super) rows: Vec<DiffLine>,
}
const fn kind_code(kind: DiffKind) -> i32 {
match kind {
DiffKind::Same => 0,
DiffKind::Added => 1,
DiffKind::Removed => 2,
DiffKind::Skipped => 3,
}
}
fn number(line: Option<usize>) -> String {
line.map_or_else(String::new, |line| line.to_string())
}
pub(super) fn title(first: &str, second: &str) -> String {
format!("Cutting instructions: \"{first}\" and \"{second}\"")
}
pub(super) fn diff_view(first: &str, second: &str, diff: &TextDiff) -> DiffView {
let rows = if diff.is_identical() {
diff.rows.clone()
} else {
diff.collapsed(CONTEXT_LINES)
};
let summary = if diff.is_identical() {
format!("The cutting instructions are the same. {SCOPE_NOTE}")
} else {
format!(
"{} Added lines are only in \"{second}\", removed lines only in \"{first}\". {SCOPE_NOTE}",
diff.summary()
)
};
DiffView {
title: title(first, second),
summary,
rows: rows
.into_iter()
.map(|row| DiffLine {
kind: kind_code(row.kind),
old_line: number(row.old_line),
new_line: number(row.new_line),
text: row.text,
})
.collect(),
}
}
pub(super) fn failure_view(first: &str, second: &str, reason: &str) -> DiffView {
DiffView {
title: title(first, second),
summary: reason.to_owned(),
rows: Vec::new(),
}
}
pub(super) fn text_of(
design: &Design,
label: &str,
custom: &[GemMaterial],
) -> Result<String, String> {
let solved: Vec<SolvedTier> = design.solve().map_err(|error| {
format!("\"{label}\" does not solve, so its text cannot be written. {error}")
})?;
generate_text(design, &solved, custom)
.map_err(|error| format!("The text of \"{label}\" cannot be written. {error}"))
}
pub(super) fn compare_designs(
first: (&Design, &str),
second: (&Design, &str),
custom: &[GemMaterial],
) -> DiffView {
let texts = text_of(first.0, first.1, custom)
.and_then(|old| text_of(second.0, second.1, custom).map(|new| (old, new)));
match texts {
Ok((old, new)) => diff_view(first.1, second.1, &diff_lines(&old, &new)),
Err(reason) => failure_view(first.1, second.1, &reason),
}
}