use crate::error::{Error, Result};
use crate::formula::{inputs, round_to, Formula, FormulaResult};
use crate::language::Language;
use crate::text::TextStatistics;
pub struct WienerSachtextformel;
impl WienerSachtextformel {
fn long_word_pct(stats: &TextStatistics) -> f64 {
if stats.word_count > 0 {
(stats.long_word_count as f64 / stats.word_count as f64) * 100.0
} else {
0.0
}
}
fn one_syllable_pct(stats: &TextStatistics) -> f64 {
let one = stats.syllable_histogram.get(&1).copied().unwrap_or(0);
if stats.word_count > 0 {
(one as f64 / stats.word_count as f64) * 100.0
} else {
0.0
}
}
pub fn calculate_variant(
&self,
stats: &TextStatistics,
language: &Language,
variant: i32,
) -> Result<FormulaResult> {
let w = stats.word_count.max(1) as f64;
let ms = (stats.polysyllable_count as f64 / w) * 100.0;
let sl = stats.average_words_per_sentence;
let iw = Self::long_word_pct(stats);
let mut es = 0.0;
let score = match variant {
1 => {
es = Self::one_syllable_pct(stats);
0.1935 * ms + 0.1672 * sl + 0.1297 * iw - 0.0327 * es - 0.875
}
2 => 0.2007 * ms + 0.1682 * sl + 0.1373 * iw - 2.779,
3 => 0.2963 * ms + 0.1905 * sl - 1.1144,
4 => 0.2744 * ms + 0.2656 * sl - 1.693,
other => return Err(Error::InvalidVariant(other)),
};
let rounded = round_to(score, 1);
let grade_level = score.clamp(4.0, 15.0);
Ok(FormulaResult {
formula_name: format!("{}_{}", self.name(), variant),
language_code: language.code.clone(),
score: rounded,
grade_level: Some(grade_level),
interpretation: interpret_wstf(rounded).to_string(),
inputs: inputs(&[
("ms", ms),
("sl", sl),
("iw", iw),
("es", es),
("variant", variant as f64),
]),
})
}
}
impl Formula for WienerSachtextformel {
fn name(&self) -> &'static str {
"wiener_sachtextformel"
}
fn description(&self) -> &'static str {
"Wiener Sachtextformel - German readability formula with 4 variants. Returns school grade level."
}
fn supported_languages(&self) -> &'static [&'static str] {
&["de-1996", "de-1901", "de-ch-1901"]
}
fn calculate(&self, stats: &TextStatistics, language: &Language) -> FormulaResult {
self.calculate_variant(stats, language, 1)
.expect("variant 1 is always valid")
}
}
fn interpret_wstf(score: f64) -> &'static str {
if score < 5.0 {
"Very Easy"
} else if score < 7.0 {
"Easy"
} else if score < 9.0 {
"Standard"
} else if score < 11.0 {
"Fairly Hard"
} else if score < 13.0 {
"Hard"
} else {
"Very Hard"
}
}