use lunar_lite::{LunarDate, LunarError, normalize_lunar_date};
use crate::core::error::ChartError;
use crate::core::placement::natal::life_body::{LunarDay, LunarMonth};
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(crate) struct ResolvedLunarDate {
lunar_year: i32,
lunar_month: LunarMonth,
lunar_day: LunarDay,
is_leap_month: bool,
month_days: u8,
}
impl ResolvedLunarDate {
pub(crate) const fn lunar_year(&self) -> i32 {
self.lunar_year
}
pub(crate) const fn lunar_month(&self) -> LunarMonth {
self.lunar_month
}
pub(crate) const fn lunar_day(&self) -> LunarDay {
self.lunar_day
}
pub(crate) const fn is_leap_month(&self) -> bool {
self.is_leap_month
}
pub(crate) const fn month_days(&self) -> u8 {
self.month_days
}
}
pub(crate) fn resolve_lunar_date(
lunar_year: i32,
lunar_month: LunarMonth,
lunar_day: LunarDay,
is_leap_month: bool,
) -> Result<ResolvedLunarDate, ChartError> {
let month = lunar_month.value();
let day = lunar_day.value();
let conversion_failed = || ChartError::CalendarConversionFailed {
year: lunar_year,
month,
day,
};
let date = normalize_lunar_date(LunarDate {
year: lunar_year,
month,
day,
is_leap_month,
})
.map_err(|err| map_lunar_normalize_error(err, lunar_year, month, day))?;
let month_days = match normalize_lunar_date(LunarDate { day: 30, ..date }) {
Ok(_) => 30,
Err(LunarError::InvalidLunarDate { .. }) => 29,
Err(err) => return Err(map_lunar_normalize_error(err, lunar_year, month, day)),
};
Ok(ResolvedLunarDate {
lunar_year: date.year,
lunar_month: LunarMonth::new(date.month).map_err(|_| conversion_failed())?,
lunar_day: LunarDay::new(date.day).map_err(|_| conversion_failed())?,
is_leap_month: date.is_leap_month,
month_days,
})
}
fn map_lunar_normalize_error(err: LunarError, year: i32, month: u8, day: u8) -> ChartError {
match err {
LunarError::InvalidLunarDate { .. } | LunarError::YearOutOfRange { .. } => {
ChartError::UnsupportedCalendarDate { year, month, day }
}
LunarError::InvalidSolarDate { .. }
| LunarError::InvalidTime { .. }
| LunarError::InvalidTimeIndex { .. }
| LunarError::SolarTermOutOfRange { .. } => {
ChartError::CalendarConversionFailed { year, month, day }
}
}
}
#[cfg(test)]
mod tests;