use std::{cell::RefCell, ops::Index};
use crate::{
display_chars::DisplayChars, MorseChar, MorseResult, MorseUnit,
};
#[cfg(feature = "audio")]
use crate::sound::Sound;
#[cfg(feature = "audio")]
use std::{thread, time};
use super::TMorse;
mod iterator;
use iterator::*;
mod converters;
pub use converters::*;
#[derive(Debug, PartialEq, Clone)]
pub struct Morse {
morse_str: Vec<MorseChar>,
display_as: DisplayChars,
#[cfg(feature = "audio")]
sound: Sound,
from_char_converter: fn(char) -> MorseResult<Vec<MorseUnit>>,
into_char_converter: fn(Vec<MorseUnit>) -> MorseResult<char>,
}
impl TMorse for Morse {
fn parse_text(&mut self, text: &str) -> MorseResult<()> {
let mut morse: Vec<MorseChar> = Vec::new();
for letter in text.chars() {
morse.push(MorseChar::from_char(letter, self.from_char_converter)?);
}
Ok(())
}
fn parse_bin(&mut self, bin: &str) -> MorseResult<()> {
let words: Vec<&str> = bin.split("0000000").collect();
for word in words {
let letters: Vec<&str> = word.split("000").collect();
for letter in letters {
self.morse_str
.push(MorseChar::from_bin(letter, self.into_char_converter)?);
}
}
Ok(())
}
fn len(&self) -> usize {
self.morse_str.len()
}
fn remove(&mut self, idx: usize) -> MorseChar {
self.morse_str.remove(idx)
}
}
impl Index<usize> for Morse {
type Output = MorseChar;
fn index(&self, idx: usize) -> &Self::Output {
&self.morse_str[idx]
}
}
impl Morse {
pub fn from_text(text: &str) -> MorseResult<Morse> {
let mut morse_str: Vec<MorseChar> = Vec::new();
for letter in text.chars() {
morse_str.push(MorseChar::from_char(letter, from_int_char)?);
}
Ok(Morse {
morse_str,
..Morse::default()
})
}
pub fn from_bin(bin: &str) -> MorseResult<Morse> {
let words: Vec<&str> = bin.split("0000000").collect();
let mut morse_str: Vec<MorseChar> = Vec::new();
for word in words {
let letters: Vec<&str> = word.split("000").collect();
for letter in letters {
morse_str.push(MorseChar::from_bin(letter, into_int_char)?);
}
}
Ok(Morse {
morse_str,
..Morse::default()
})
}
pub fn dot_as(&mut self, alias: &str) {
self.display_as.dot = alias.to_string();
}
pub fn line_as(&mut self, alias: &str) {
self.display_as.line = alias.to_string();
}
pub fn whitespace_as(&mut self, alias: &str) {
self.display_as.whitespace = alias.to_string();
}
#[cfg(feature = "audio")]
pub fn to_beep(&self) {
let morse_str = RefCell::new(self.morse_str.clone());
for (idx, m_char) in morse_str.borrow_mut().iter_mut().enumerate() {
m_char.frequency(self.sound.frequency);
m_char.play_speed(self.sound.speed);
m_char.to_beep();
if idx < self.morse_str.len() - 1 {
thread::sleep(time::Duration::from_secs(3));
}
}
}
#[cfg(feature = "audio")]
pub fn frequency(&mut self, frequency: f32) {
self.sound.frequency = frequency;
}
#[cfg(feature = "audio")]
pub fn play_speed(&mut self, speed: f32) {
self.sound.speed = speed;
}
pub fn to_bin_str(&self) -> String {
let mut string = String::new();
for (idx, m_char) in self.morse_str.iter().enumerate() {
string.push_str(&m_char.to_bin_str());
if idx < self.morse_str.len() - 1 {
string.push_str("000");
}
}
string
}
pub fn to_text(&self) -> String {
let mut text = String::new();
for m_char in &self.morse_str {
text.push(m_char.get_letter());
}
text
}
pub fn iter(&self) -> MorseIterator {
MorseIterator::init(self)
}
}
impl IntoIterator for Morse {
type Item = MorseChar;
type IntoIter = MorseIntoIterator;
fn into_iter(self) -> MorseIntoIterator {
MorseIntoIterator { morse: self }
}
}
impl Default for Morse {
fn default() -> Self {
Self {
morse_str: Vec::new(),
display_as: DisplayChars::default(),
#[cfg(feature = "audio")]
sound: Sound::default(),
from_char_converter: from_int_char,
into_char_converter: into_int_char,
}
}
}
impl ToString for Morse {
fn to_string(&self) -> String {
let mut string = String::new();
let morse = RefCell::new(self.morse_str.clone());
for (idx, m_char) in morse.borrow_mut().iter_mut().enumerate() {
m_char.dot_as(&self.display_as.dot);
m_char.line_as(&self.display_as.line);
m_char.whitespace_as(&self.display_as.whitespace);
string.push_str(&m_char.to_string());
if idx < self.morse_str.len() - 1 {
string.push_str(" ");
}
}
string
}
}
#[cfg(test)]
mod morse_tests {
use super::*;
#[test]
fn create_from_text_str() {
assert_eq!(
Morse::from_text("Hello").unwrap().to_bin_str(),
"1010101000100010111010100010111010100011101110111"
);
}
#[test]
fn create_from_binary_str() {
const HELLO_BIN: &str = "1010101000100010111010100010111010100011101110111";
assert_eq!(Morse::from_bin(HELLO_BIN).unwrap().to_bin_str(), HELLO_BIN);
}
#[test]
fn to_string() {
assert_eq!(
Morse::from_text("hi u").unwrap().to_string(),
". . . . . . . . ⚊"
);
}
#[test]
fn to_bin_str() {
assert_eq!(
Morse::from_text("hi u").unwrap().to_bin_str(),
"101010100010100000001010111"
);
}
#[test]
fn set_aliases_for_whitespace_lines_and_dots() {
let mut morse = Morse::from_text("hi u").unwrap();
morse.dot_as("🔥");
morse.line_as("➖");
morse.whitespace_as("🚧");
assert_eq!(morse.to_string(), "🔥 🔥 🔥 🔥 🔥 🔥 🚧 🔥 🔥 ➖");
}
}