use crate::code_mapper::StaticMap;
use crate::error::MecoError;
use crate::letter::rule::{LetterTranslateRuleFrom, LetterTranslateRuleTo};
use crate::tables::from_menk_letter::{
FROM_MENK_LETTER, FROM_MENK_LETTER_CHAGH, FROM_MENK_LETTER_HUNDII, FROM_MENK_LETTER_SAARMAG,
FROM_MENK_LETTER_W_WITH_EHSHIG,
};
use crate::tables::to_menk_letter::{TO_MENK_LETTER, TO_MENK_LETTER_CHAGH, TO_MENK_LETTER_HUNDII};
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 F_MAP: StaticMap = StaticMap::new(FROM_MENK_LETTER);
static F_CHAGH: StaticMap = StaticMap::new(FROM_MENK_LETTER_CHAGH);
static F_HUNDII: StaticMap = StaticMap::new(FROM_MENK_LETTER_HUNDII);
static F_SAARMAG: StaticMap = StaticMap::new(FROM_MENK_LETTER_SAARMAG);
static F_W_EHSHIG: StaticMap = StaticMap::new(FROM_MENK_LETTER_W_WITH_EHSHIG);
const DOUBLE_I_EHSHIG: [char; 4] = ['\u{1820}', '\u{1821}', '\u{1823}', '\u{1824}'];
pub(crate) struct MenkLetterFrom;
impl LetterTranslateRuleFrom for MenkLetterFrom {
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) = resolve_w(pre, key) {
return Some(r);
}
if let Some(r) = resolve_t(suf, key) {
return Some(r);
}
if let Some(r) = resolve_g(suf, key, nature) {
return Some(r);
}
if let Some(r) = F_MAP.get(key) {
return Some(r);
}
match nature {
Nature::Chagh => F_CHAGH.get(key),
Nature::Hundii => F_HUNDII.get(key),
Nature::Saarmag => F_SAARMAG.get(key),
}
}
fn contains(&self, key: &str) -> bool {
F_MAP.contains_key(key) || F_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], s: &str) -> Option<&'static str> {
if s != "\u{1836}" && s != "\u{1822}" {
return None;
}
let c = *pre.last()?;
if s == "\u{1822}" && (c == '\u{1822}' || c == '\u{1836}') && pre.len() > 2 {
let pre2 = pre[pre.len() - 2];
if DOUBLE_I_EHSHIG.contains(&pre2) {
return Some("");
}
}
if DOUBLE_I_EHSHIG.contains(&c) {
return Some("\u{e006}\u{e006}");
}
None
}
fn resolve_w(pre: &[char], s: &str) -> Option<&'static str> {
if !s.contains('\u{1838}') {
return None;
}
let c = *pre.last()?;
if mgl::is_ehshig(c) {
return F_W_EHSHIG.get(s);
}
None
}
fn resolve_t(suf: &[char], s: &str) -> Option<&'static str> {
if s == "\u{1832}" && !suf.is_empty() && mgl::is_giiguulegch(suf[0]) {
return Some("\u{e043}");
}
None
}
fn resolve_g(suf: &[char], s: &str, nature: Nature) -> Option<&'static str> {
if s == "\u{182d}" && !suf.is_empty() && mgl::is_giiguulegch(suf[0]) {
return Some(if nature == Nature::Chagh {
"\u{e005}\u{e005}"
} else {
"\u{e031}"
});
}
None
}
static T_MAP: StaticMap = StaticMap::new(TO_MENK_LETTER);
static T_HUNDII: StaticMap = StaticMap::new(TO_MENK_LETTER_HUNDII);
static T_CHAGH: StaticMap = StaticMap::new(TO_MENK_LETTER_CHAGH);
pub(crate) struct MenkLetterTo;
impl LetterTranslateRuleTo for MenkLetterTo {
fn get_mapper_code(&self, builder: &mut String, word: &ShapeWord) -> Result<(), MecoError> {
let mut s = String::new();
let mut ue031 = false;
for fragment in &word.fragments {
let key = fragment.get_key();
let mut s1: Option<String> = get_menk(&s, &key, word.nature).map(str::to_string);
if key == "\u{e031}" {
ue031 = true;
if s.ends_with("\u{180d}\u{1822}") {
let mut cs: Vec<char> = s.chars().collect();
cs.truncate(cs.len() - 2);
s = cs.into_iter().collect();
s.push('\u{1822}');
}
}
if ue031 {
if let Some(v) = &s1 {
if v.contains("\u{180d}\u{1822}") {
ue031 = false;
s1 = Some(v.replace("\u{180d}\u{1822}", "\u{1822}"));
}
}
}
let s1 = match s1 {
Some(v) => v,
None => return Err(MecoError::NotFoundInMapper(key)),
};
s = concat_and_202f(&s, &s1);
}
if s.starts_with('\u{202f}') && builder.ends_with('\u{20}') {
builder.pop();
}
builder.push_str(&s);
Ok(())
}
fn contains(&self, key: &str) -> bool {
T_CHAGH.contains_key(key) || T_MAP.contains_key(key)
}
fn is_translate_code_point(&self, c: char) -> bool {
zvvnmod::is_zvvnmod_code(c)
}
}
fn get_menk(pre: &str, s: &str, nature: Nature) -> Option<&'static str> {
if let Some(r) = resolve_ue00c_menk(pre, s, nature) {
return Some(r);
}
if let Some(r) = resolve_single_gii_and_ue011(pre, s) {
return Some(r);
}
let m = if nature == Nature::Chagh {
T_CHAGH.get(s)
} else {
T_HUNDII.get(s)
};
match m {
Some(v) if !v.is_empty() => Some(v),
_ => T_MAP.get(s),
}
}
fn resolve_ue00c_menk(pre: &str, s: &str, nature: Nature) -> Option<&'static str> {
if s != "\u{e00c}" {
return None;
}
let chagh_or_hundii = if nature == Nature::Chagh {
"\u{1820}"
} else {
"\u{1821}"
};
match pre.chars().last() {
None => Some(chagh_or_hundii),
Some(c) if mgl::is_traditional_ehshig(c) => Some("\u{1828}"),
Some(_) => Some(chagh_or_hundii),
}
}
fn resolve_single_gii_and_ue011(pre: &str, s: &str) -> Option<&'static str> {
if s != "\u{e011}" || pre.is_empty() {
return None;
}
if pre.chars().count() == 1 {
let ch = pre.chars().next().unwrap();
if mgl::is_giiguulegch(ch) {
return Some(if ('\u{1832}'..='\u{1834}').contains(&ch) {
"\u{1824}"
} else {
"\u{1824}\u{180b}"
});
}
}
None
}
fn concat_and_202f(s0: &str, s1: &str) -> String {
if s1.starts_with('\u{202f}') && s0.ends_with('\u{20}') {
let trimmed = &s0[..s0.len() - 1];
format!("{trimmed}{s1}")
} else {
format!("{s0}{s1}")
}
}