use crate::code_mapper::StaticMap;
use crate::error::MecoError;
use crate::letter::rule::{
ends_with_boundary, LetterTranslateRuleFrom, LetterTranslateRuleTo, WORD_CONNECTOR,
};
use crate::tables::from_delehi::{
FROM_DELEHI, FROM_DELEHI_CHAGH, FROM_DELEHI_HUNDII, FROM_DELEHI_SAARMAG,
};
use crate::tables::to_delehi::TO_DELEHI;
use crate::unicode::{mgl, zvvnmod};
use crate::word::nature::Nature;
use crate::word::shape_word::ShapeWord;
fn is_word_connector(c: char) -> bool {
c == '\u{202f}'
}
static FROM_MAP: StaticMap = StaticMap::new(FROM_DELEHI);
static CHAGH: StaticMap = StaticMap::new(FROM_DELEHI_CHAGH);
static HUNDII: StaticMap = StaticMap::new(FROM_DELEHI_HUNDII);
static SAARMAG: StaticMap = StaticMap::new(FROM_DELEHI_SAARMAG);
const DOUBLE_I_EHSHIG: [char; 5] = ['\u{1820}', '\u{1821}', '\u{1822}', '\u{1823}', '\u{1824}'];
pub(crate) struct DelehiFrom;
impl LetterTranslateRuleFrom for DelehiFrom {
fn get_mapper_code(
&self,
pre: &[char],
_suf: &[char],
key: &str,
nature: Nature,
) -> Option<&'static str> {
if key.trim_matches(' ') == "\u{180a}" {
return Some("\u{180a}");
}
if let Some(r) = resolve_devsger_i(pre, key) {
return Some(r);
}
if let Some(r) = FROM_MAP.get(key) {
return Some(r);
}
match nature {
Nature::Chagh => CHAGH.get(key),
Nature::Hundii => HUNDII.get(key),
Nature::Saarmag => SAARMAG.get(key),
}
}
fn contains(&self, key: &str) -> bool {
FROM_MAP.contains_key(key) || CHAGH.contains_key(key)
}
fn get_code_nature(&self, c: char) -> Nature {
mgl::get_code_nature(c)
}
fn is_translate_code_point(&self, c: char) -> bool {
mgl::is_normal_letter(c)
|| mgl::is_free_variation_selector(c)
|| mgl::is_vowel_separator(c)
|| is_word_connector(c)
|| mgl::other_mongolian_code(c)
}
fn is_word_code_point(&self, c: char) -> bool {
mgl::is_normal_letter(c)
|| mgl::is_free_variation_selector(c)
|| mgl::is_vowel_separator(c)
|| mgl::other_mongolian_code(c)
}
}
fn resolve_devsger_i(pre: &[char], key: &str) -> Option<&'static str> {
if key != "\u{1822}" || pre.is_empty() {
return None;
}
let c = *pre.last().unwrap();
if DOUBLE_I_EHSHIG.contains(&c) {
Some("\u{e006}\u{e006}")
} else {
None
}
}
static TO_MAP: StaticMap = StaticMap::new(TO_DELEHI);
pub(crate) struct DelehiTo;
impl LetterTranslateRuleTo for DelehiTo {
fn get_mapper_code(&self, builder: &mut String, word: &ShapeWord) -> Result<(), MecoError> {
let mut s = String::new();
for fragment in &word.fragments {
match get_delehi(&s, &fragment.get_key()) {
Some(v) => s = v,
None => return Err(MecoError::NotFoundInMapper(fragment.get_key())),
}
}
if s.starts_with(WORD_CONNECTOR) && ends_with_boundary(builder) {
builder.pop();
}
builder.push_str(&s);
Ok(())
}
fn contains(&self, key: &str) -> bool {
TO_MAP.contains_key(key)
}
fn is_translate_code_point(&self, c: char) -> bool {
zvvnmod::is_zvvnmod_code(c)
}
}
fn get_delehi(pre_letter_codes: &str, key: &str) -> Option<String> {
if key == "\u{e00c}" {
let tail = match pre_letter_codes.chars().last() {
None => '\u{1820}',
Some(c) if mgl::is_traditional_ehshig(c) => '\u{1828}',
Some(_) => '\u{1820}',
};
return Some(format!("{pre_letter_codes}{tail}"));
}
let mapped = TO_MAP.get(key)?;
Some(concat_and_202f(pre_letter_codes, mapped))
}
fn concat_and_202f(s0: &str, s1: &str) -> String {
if s1.starts_with(WORD_CONNECTOR) && ends_with_boundary(s0) {
let mut trimmed = s0.to_owned();
trimmed.pop(); format!("{trimmed}{s1}")
} else {
format!("{s0}{s1}")
}
}