use crate::error::MecoError;
use crate::shape::rule::ShapeTranslateRule;
use crate::strings;
use crate::word::char_type::CharType;
use crate::word::shape_word::{ShapeWord, ShapeWordFragment};
pub(crate) struct ShapeTranslator {
rule: &'static dyn ShapeTranslateRule,
}
impl ShapeTranslator {
pub fn new(rule: &'static dyn ShapeTranslateRule) -> Self {
Self { rule }
}
pub fn translate(&self, s: &str) -> Result<String, MecoError> {
if strings::is_blank(s) {
return Ok(String::new());
}
let mut chars: Vec<char> = s.chars().collect();
chars.push('\u{e666}');
let mut word = ShapeWord::new();
let mut fragment = ShapeWordFragment::new();
let mut builder = String::new();
fragment.set_head(Some(CharType::Other));
let mut i = 0usize;
while i < chars.len() {
let c = chars[i];
if self.rule.is_translate_code_point(c) {
fragment.push(c);
fragment.set_tail(self.rule.get_char_type(chars[i + 1]));
if self.rule.contains(&fragment) {
i += 1;
continue; }
fragment.pop()?;
fragment.set_tail(self.rule.get_char_type(c));
if fragment.is_blank() {
if word.is_not_blank() {
self.translate_word(&mut builder, &word)?;
word = ShapeWord::new();
}
builder.push(c);
fragment = ShapeWordFragment::new();
fragment.set_head(Some(CharType::Other));
i += 1;
continue;
}
word.add(fragment);
fragment = ShapeWordFragment::new();
fragment.set_head(self.rule.get_char_type(chars[i - 1]));
continue; } else {
if fragment.is_not_blank() {
fragment.set_tail(Some(CharType::Other));
word.add(fragment);
fragment = ShapeWordFragment::new();
fragment.set_head(Some(CharType::Other));
}
if word.is_not_blank() {
self.translate_word(&mut builder, &word)?;
word = ShapeWord::new();
}
builder.push(c);
}
i += 1;
}
builder.pop(); Ok(builder)
}
fn translate_word(&self, builder: &mut String, word: &ShapeWord) -> Result<(), MecoError> {
let mut pre: Vec<char> = Vec::new();
for fragment in &word.fragments {
match self.rule.get_mapper_code(&pre, fragment) {
Some(s) => builder.push_str(s),
None => return Err(MecoError::NotFoundInMapper(fragment.get_key())),
}
pre.extend(fragment.content());
}
Ok(())
}
}