use icu_calendar::{Date, cal::Hebrew};
use crate::{
calendar::HebrewHolidayCalendar,
limudim::{
Limud,
interval::Interval,
limud::{CycleFinder, InternalLimud},
},
};
const DEFAULT_UNITS: [u8; 30] = [
9, 17, 22, 28, 34, 38, 43, 48, 54, 59, 65, 68, 71, 76, 78, 82, 87, 89, 96, 103, 105, 107, 112, 118, 119, 119, 134,
139, 144, 150,
];
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[allow(missing_docs)]
pub enum TehillimUnit {
Psalms { start: u8, end: u8 },
PsalmVerses {
psalm: u8,
start_verse: u16,
end_verse: u16,
},
}
#[derive(Default)]
pub struct TehillimMonthly;
fn find_monthly_cycle(date: Date<Hebrew>) -> Option<(Date<Hebrew>, Date<Hebrew>)> {
let year = date.year().extended_year();
let month = date.input_month();
let start = Date::try_new_hebrew_v2(year, month, 1).ok()?;
let days_in_month = date.days_in_month();
let end = Date::try_new_hebrew_v2(year, month, days_in_month).ok()?;
Some((start, end))
}
impl InternalLimud<TehillimUnit> for TehillimMonthly {
fn cycle_finder(&self) -> CycleFinder {
CycleFinder::Perpetual(find_monthly_cycle)
}
fn unit_for_interval(&self, interval: &Interval, _limud_date: &Date<Hebrew>) -> Option<TehillimUnit> {
let iteration = interval.iteration;
if iteration == 25 {
return Some(TehillimUnit::PsalmVerses {
psalm: 119,
start_verse: 1,
end_verse: 96,
});
}
if iteration == 26 {
return Some(TehillimUnit::PsalmVerses {
psalm: 119,
start_verse: 97,
end_verse: 176,
});
}
let (start, mut stop) = if iteration == 1 {
(1, DEFAULT_UNITS[0])
} else {
let prev_end = DEFAULT_UNITS[(iteration - 2) as usize];
let curr_end = DEFAULT_UNITS[(iteration - 1) as usize];
(prev_end + 1, curr_end)
};
let day = interval.end_date.day_of_month().0;
let days_in_month = interval.end_date.days_in_month();
if day == 29 && days_in_month == 29 && iteration < 30 {
stop = DEFAULT_UNITS[iteration as usize];
}
Some(TehillimUnit::Psalms { start, end: stop })
}
}
impl Limud<TehillimUnit> for TehillimMonthly {}
#[cfg(test)]
#[allow(clippy::expect_used, clippy::unwrap_used)]
mod tests {
use crate::calendar::month::{SHEVAT, TEVET};
use super::*;
#[test]
fn tehillim_monthly_simple_date() {
let test_date = Date::try_new_hebrew_v2(5778, TEVET, 8).unwrap();
let limud = TehillimMonthly.limud(test_date).expect("limud exists");
assert_eq!(limud, TehillimUnit::Psalms { start: 44, end: 48 });
}
#[test]
fn tehillim_monthly_beginning_of_month() {
let test_date = Date::try_new_hebrew_v2(5778, TEVET, 1).unwrap();
let limud = TehillimMonthly.limud(test_date).expect("limud exists");
assert_eq!(limud, TehillimUnit::Psalms { start: 1, end: 9 });
}
#[test]
fn tehillim_monthly_end_of_short_month() {
let test_date = Date::try_new_hebrew_v2(5778, TEVET, 29).unwrap();
let limud = TehillimMonthly.limud(test_date).expect("limud exists");
assert_eq!(limud, TehillimUnit::Psalms { start: 140, end: 150 });
}
#[test]
fn tehillim_monthly_end_of_long_month() {
let test_date = Date::try_new_hebrew_v2(5778, SHEVAT, 30).unwrap();
let limud = TehillimMonthly.limud(test_date).expect("limud exists");
assert_eq!(limud, TehillimUnit::Psalms { start: 145, end: 150 });
}
#[test]
fn tehillim_monthly_29th_day_of_long_month() {
let test_date = Date::try_new_hebrew_v2(5778, SHEVAT, 29).unwrap();
let limud = TehillimMonthly.limud(test_date).expect("limud exists");
assert_eq!(limud, TehillimUnit::Psalms { start: 140, end: 144 });
}
#[test]
fn tehillim_monthly_day_25_special_case() {
let test_date = Date::try_new_hebrew_v2(5778, SHEVAT, 25).unwrap();
let limud = TehillimMonthly.limud(test_date).expect("limud exists");
assert_eq!(
limud,
TehillimUnit::PsalmVerses {
psalm: 119,
start_verse: 1,
end_verse: 96
}
);
}
#[test]
fn tehillim_monthly_day_26_special_case() {
let test_date = Date::try_new_hebrew_v2(5778, SHEVAT, 26).unwrap();
let limud = TehillimMonthly.limud(test_date).expect("limud exists");
assert_eq!(
limud,
TehillimUnit::PsalmVerses {
psalm: 119,
start_verse: 97,
end_verse: 176
}
);
}
}