use crate::{
message::Message,
CharacterSet,
MorseCodeSet,
MorseCodeArray,
MorseSignal::{Long as L, Short as S},
DEFAULT_MORSE_CODE_SET,
DEFAULT_CHARACTER_SET,
MORSE_ARRAY_LENGTH,
MORSE_DEFAULT_CHAR,
LONG_SIGNAL_MULTIPLIER,
WORD_SPACE_MULTIPLIER,
Character,
};
const DIT: Character = '.' as Character;
const DAH: Character = '-' as Character;
const WORD_DELIMITER: Character = '/' as Character;
const SDM_LENGTH: usize = 12;
#[derive(PartialEq, Copy, Clone, Debug)]
pub enum SDM {
Empty,
High(u8),
Low(u8),
}
use SDM::{Empty as SDMEmpty, High as SDMHigh, Low as SDMLow};
pub type MorseCharray = [Option<Character>; MORSE_ARRAY_LENGTH];
pub type SDMArray = [SDM; SDM_LENGTH];
pub struct Encoder<const MSG_MAX: usize> {
message: Message<MSG_MAX>,
character_set: CharacterSet,
morse_code_set: MorseCodeSet,
encoded_message: [MorseCodeArray; MSG_MAX],
}
impl<const MSG_MAX: usize> Default for Encoder<MSG_MAX> {
fn default() -> Self {
Self::new()
}
}
impl<const MSG_MAX: usize> Encoder<MSG_MAX> {
pub fn new() -> Self {
Self {
message: Message::default(),
character_set: DEFAULT_CHARACTER_SET,
morse_code_set: DEFAULT_MORSE_CODE_SET,
encoded_message: [MORSE_DEFAULT_CHAR; MSG_MAX],
}
}
pub fn with_message(mut self, message_str: &str, edit_pos_end: bool) -> Self {
self.message = Message::new(message_str, edit_pos_end, self.message.is_edit_clamped());
self
}
pub fn with_edit_position(mut self, pos: usize) -> Self {
self.message.set_edit_pos(pos);
self
}
pub fn with_character_set(mut self, character_set: CharacterSet) -> Self {
self.character_set = character_set;
self
}
pub fn with_morse_code_set(mut self, morse_code_set: MorseCodeSet) -> Self {
self.morse_code_set = morse_code_set;
self
}
pub fn with_message_pos_clamping(mut self) -> Self {
self.message.set_edit_position_clamp(true);
self
}
pub fn build(self) -> MorseEncoder<MSG_MAX> {
let Encoder {
message,
character_set,
morse_code_set,
encoded_message,
} = self;
MorseEncoder::<MSG_MAX> {
message,
character_set,
morse_code_set,
encoded_message,
}
}
}
pub struct MorseEncoder<const MSG_MAX: usize> {
pub message: Message<MSG_MAX>,
character_set: CharacterSet,
morse_code_set: MorseCodeSet,
encoded_message: [MorseCodeArray; MSG_MAX],
}
impl<const MSG_MAX: usize> MorseEncoder<MSG_MAX> {
fn get_morse_char_from_char(&self, ch: &Character) -> Option<MorseCodeArray> {
let index = self.character_set
.iter()
.position(|setchar| setchar == ch);
if let Some(i) = index {
Some(self.morse_code_set[i].clone())
} else {
None
}
}
fn get_encoded_char_as_morse_charray(&self, index: usize) -> Option<MorseCharray> {
if index < self.message.len() {
let encoded_char = self.encoded_message[index].clone();
if encoded_char == MORSE_DEFAULT_CHAR {
Some([Some(WORD_DELIMITER), None, None, None, None, None])
} else {
Some(encoded_char.map(|mchar| {
match mchar {
Some(S) => Some(DIT),
Some(L) => Some(DAH),
_ => None,
}
}))
}
} else {
None
}
}
fn get_encoded_char_as_sdm(&self, index: usize) -> Option<SDMArray> {
if index < self.message.len() {
let mut sdm_array = [SDMEmpty; SDM_LENGTH];
let encoded_char = self.encoded_message[index].clone();
if encoded_char == MORSE_DEFAULT_CHAR {
sdm_array[0] = SDMLow(WORD_SPACE_MULTIPLIER as u8);
} else {
let mut sdm_iter = sdm_array.iter_mut();
let mut encoded_iter = encoded_char.iter().filter(|mchar| mchar.is_some()).peekable();
while let Some(mchar) = encoded_iter.next() {
*sdm_iter.next().unwrap() = match mchar {
Some(S) => SDMHigh(1),
Some(L) => SDMHigh(LONG_SIGNAL_MULTIPLIER as u8),
_ => SDMEmpty,
};
if encoded_iter.peek().is_some() {
*sdm_iter.next().unwrap() = SDMLow(1);
}
}
*sdm_iter.next().unwrap() = SDMLow(LONG_SIGNAL_MULTIPLIER as u8);
}
Some(sdm_array)
} else {
None
}
}
#[cfg(not(feature = "utf8"))]
fn encode(&mut self, ch: &Character, index: usize) -> Result<Character, &'static str> {
if ch.is_ascii() {
let ch_upper = ch.to_ascii_uppercase();
match self.get_morse_char_from_char(&ch_upper) {
Some(mchar) => {
self.encoded_message[index] = mchar;
Ok(ch_upper)
},
None => Err("Encoding error: Could not find character in character set.")
}
} else {
Err("Encoding error: Character is not ASCII")
}
}
#[cfg(feature = "utf8")]
fn encode(&mut self, ch: &Character, index: usize) -> Result<Character, &'static str> {
let mut ch_upper = ch.to_uppercase();
if let Some(ch) = ch_upper.next() {
match self.get_morse_char_from_char(&ch) {
Some(mchar) => {
self.encoded_message[index] = mchar;
Ok(ch)
},
None => Err("Encoding error: Could not find character in character set.")
}
} else {
Err("Encoding error: Could not convert character to uppercase.")
}
}
}
impl<const MSG_MAX: usize> MorseEncoder<MSG_MAX> {
pub fn encode_character(&mut self, ch: &Character) -> Result<(), &str> {
let pos = self.message.get_edit_pos();
if pos < MSG_MAX {
let ch_uppercase = self.encode(ch, pos);
match ch_uppercase {
Ok(ch) => {
self.message.add_char(ch);
self.message.shift_edit_right();
Ok(())
},
Err(err) => Err(err)
}
} else {
Ok(())
}
}
#[cfg(not(feature = "utf8"))]
pub fn encode_slice(&mut self, str_slice: &str) -> Result<(), &str> {
let ascii_count = str_slice.chars().filter(|ch| ch.is_ascii()).count();
if self.message.len() + ascii_count < MSG_MAX {
str_slice.chars()
.filter(|ch| ch.is_ascii())
.for_each(|ch| {
let byte = ch as u8;
self.encode_character(&byte).unwrap();
});
Ok(())
} else {
Err("String slice length exceeds maximum message length.")
}
}
#[cfg(feature = "utf8")]
pub fn encode_slice(&mut self, str_slice: &str) -> Result<(), &str> {
if self.message.len() + str_slice.len() < MSG_MAX {
str_slice.chars()
.for_each(|ch| {
self.encode_character(&ch).unwrap();
});
Ok(())
} else {
Err("String slice length exceeds maximum message length.")
}
}
pub fn encode_message_all(&mut self) {
for index in 0..self.message.len() {
let ch = &self.message.char_at(index).clone();
self.encode(ch, index).unwrap();
}
}
pub fn get_last_char_as_morse_charray(&self) -> Option<MorseCharray> {
let pos = self.message.get_last_changed_index();
if pos > 0 {
self.get_encoded_char_as_morse_charray(pos)
} else {
None
}
}
pub fn get_last_char_as_sdm(&self) -> Option<SDMArray> {
let pos = self.message.get_last_changed_index();
if pos > 0 {
self.get_encoded_char_as_sdm(pos)
} else {
None
}
}
pub fn get_encoded_message_as_morse_charrays(&self) -> impl Iterator<Item = Option<MorseCharray>> + '_ {
(0..self.message.len()).map(|index| {
self.get_encoded_char_as_morse_charray(index)
})
}
pub fn get_encoded_message_as_sdm_arrays(&self) -> impl Iterator<Item = Option<SDMArray>> + '_ {
(0..self.message.len()).map(|index| {
self.get_encoded_char_as_sdm(index)
})
}
}