use super::JawKind;
use crate::display::ToothDisplay;
use crate::{NotationKind, QuadrantKind, Tooth, ToothType};
use alloc::format;
use alloc::string::String;
use owo_colors::{OwoColorize, Style};
pub struct ToothCliFormatter;
impl ToothCliFormatter {
fn format_tooth(
tooth: &Tooth,
notation: &NotationKind,
selected_value: &Option<Tooth>,
) -> String {
let tooth_label = tooth.to(notation);
let mut style = Style::new();
style = match &tooth.get_type() {
ToothType::Canine => style.yellow(),
ToothType::Incisor => style.green(),
ToothType::Premolar => style.cyan(),
ToothType::Molar => style.blue(),
};
if let Some(t) = selected_value {
if t == tooth {
style = style.reversed();
}
}
format!(" {}", tooth_label.style(style))
}
fn format_quadrant(
notation: &NotationKind,
permanent: bool,
quadrant: QuadrantKind,
selected_value: &Option<Tooth>,
) -> String {
let max = Tooth::quadrant_max(permanent);
let format_tooth = |i| {
let tooth = Tooth::new(i, quadrant, permanent).unwrap();
ToothCliFormatter::format_tooth(&tooth, notation, selected_value)
};
if quadrant == QuadrantKind::TopLeft || quadrant == QuadrantKind::BottomLeft {
(1..=max).rev().map(format_tooth).collect()
} else {
(1..=max).map(format_tooth).collect()
}
}
fn format_jaw(
notation: &NotationKind,
permanent: bool,
jaw: JawKind,
selected_value: &Option<Tooth>,
) -> String {
let (quadrant_1, quadrant_2) = match jaw {
JawKind::Top => (QuadrantKind::TopLeft, QuadrantKind::TopRight),
JawKind::Bottom => (QuadrantKind::BottomLeft, QuadrantKind::BottomRight),
};
format!(
" {} |{}",
ToothCliFormatter::format_quadrant(notation, permanent, quadrant_1, selected_value),
ToothCliFormatter::format_quadrant(notation, permanent, quadrant_2, selected_value)
)
}
fn calculate_separator_len(notation: &NotationKind, permanent: bool) -> u8 {
let item_count = Tooth::quadrant_max(permanent);
let item_width = match (notation, permanent) {
(NotationKind::Iso, _) => 2,
(NotationKind::Uns, true) => 2,
(NotationKind::Uns, false) => 1,
(NotationKind::Alphanumeric, _) => 3,
};
(item_width + 1) * (item_count * 2 + 1)
}
}
impl ToothDisplay for ToothCliFormatter {
fn format(notation: &NotationKind, permanent: bool, selected_value: &Option<Tooth>) -> String {
let jaw_len = ToothCliFormatter::calculate_separator_len(notation, permanent);
let mut result = String::with_capacity((jaw_len * 4).into());
result.push_str(&ToothCliFormatter::format_jaw(
notation,
permanent,
JawKind::Top,
selected_value,
));
result.push_str("\nR ");
result.push_str(&"-".repeat(jaw_len.into()));
result.push_str(" L\n");
result.push_str(&ToothCliFormatter::format_jaw(
notation,
permanent,
JawKind::Bottom,
selected_value,
));
result
}
}