use strsim::damerau_levenshtein;
use whippyunits_core::{Dimension, SiPrefix};
pub fn find_similar_units(unknown_unit: &str, threshold: f64) -> Vec<(String, f64)> {
let mut suggestions = Vec::new();
let all_units = get_all_available_units();
for unit_name in all_units {
let similarity = calculate_similarity(unknown_unit, &unit_name);
if similarity >= threshold {
suggestions.push((unit_name, similarity));
}
}
suggestions.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap_or(std::cmp::Ordering::Equal));
suggestions.truncate(3);
suggestions
}
fn calculate_similarity(s1: &str, s2: &str) -> f64 {
let distance = damerau_levenshtein(&s1.to_lowercase(), &s2.to_lowercase());
let max_len = s1.len().max(s2.len()) as f64;
if max_len == 0.0 {
1.0
} else {
1.0 - (distance as f64 / max_len)
}
}
fn get_all_available_units() -> Vec<String> {
let mut units = Vec::new();
for dimension in Dimension::ALL {
for unit in dimension.units {
for symbol in unit.symbols {
units.push(symbol.to_string());
}
units.push(unit.name.to_string());
}
}
for prefix in SiPrefix::ALL {
for dimension in Dimension::ALL {
if let Some(base_unit) = dimension.units.first() {
if let Some(first_symbol) = base_unit.symbols.first() {
let prefixed_symbol = format!("{}{}", prefix.symbol(), first_symbol);
units.push(prefixed_symbol);
}
let prefixed_name = format!("{}{}", prefix.name(), base_unit.name);
units.push(prefixed_name);
}
}
}
units.sort();
units.dedup();
units
}