use crate::core::calendar::solar_to_lunar;
use crate::core::error::ChartError;
use crate::core::facade::by_lunar::{LunarChartRequest, by_lunar};
use crate::core::model::calendar::{BirthTime, Gender, SolarDay, SolarMonth};
use crate::core::model::chart::{Chart, HoroscopeLunarDate, HoroscopeSolarDate, NatalDateFacts};
use crate::core::model::profile::MethodProfile;
use lunar_lite::EarthlyBranch;
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct SolarChartRequest {
solar_year: i32,
solar_month: SolarMonth,
solar_day: SolarDay,
birth_time: BirthTime,
gender: Gender,
fix_leap: bool,
method_profile: MethodProfile,
}
impl SolarChartRequest {
pub fn builder() -> SolarChartRequestBuilder {
SolarChartRequestBuilder::default()
}
pub const fn solar_year(&self) -> i32 {
self.solar_year
}
pub const fn solar_month(&self) -> SolarMonth {
self.solar_month
}
pub const fn solar_day(&self) -> SolarDay {
self.solar_day
}
pub const fn birth_time(&self) -> EarthlyBranch {
self.birth_time.branch()
}
pub const fn birth_time_variant(&self) -> BirthTime {
self.birth_time
}
pub const fn gender(&self) -> Gender {
self.gender
}
pub const fn fix_leap(&self) -> bool {
self.fix_leap
}
pub const fn method_profile(&self) -> &MethodProfile {
&self.method_profile
}
}
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct SolarChartRequestBuilder {
solar_year: Option<i32>,
solar_month: Option<SolarMonth>,
solar_day: Option<SolarDay>,
birth_time: Option<BirthTime>,
gender: Option<Gender>,
fix_leap: Option<bool>,
method_profile: Option<MethodProfile>,
}
impl SolarChartRequestBuilder {
pub fn solar_year(mut self, value: i32) -> Self {
self.solar_year = Some(value);
self
}
pub fn solar_month(mut self, value: SolarMonth) -> Self {
self.solar_month = Some(value);
self
}
pub fn solar_day(mut self, value: SolarDay) -> Self {
self.solar_day = Some(value);
self
}
pub fn birth_time(mut self, value: EarthlyBranch) -> Self {
self.birth_time = Some(BirthTime::from_branch(value));
self
}
pub fn birth_time_variant(mut self, value: BirthTime) -> Self {
self.birth_time = Some(value);
self
}
pub fn iztro_time_index(mut self, value: u8) -> Result<Self, ChartError> {
self.birth_time = Some(BirthTime::from_iztro_time_index(value)?);
Ok(self)
}
pub fn gender(mut self, value: Gender) -> Self {
self.gender = Some(value);
self
}
pub fn fix_leap(mut self, value: bool) -> Self {
self.fix_leap = Some(value);
self
}
pub fn method_profile(mut self, value: MethodProfile) -> Self {
self.method_profile = Some(value);
self
}
pub fn build(self) -> Result<SolarChartRequest, ChartError> {
Ok(SolarChartRequest {
solar_year: self.solar_year.ok_or(ChartError::MissingRequiredInput {
field: "solar_year",
})?,
solar_month: self.solar_month.ok_or(ChartError::MissingRequiredInput {
field: "solar_month",
})?,
solar_day: self
.solar_day
.ok_or(ChartError::MissingRequiredInput { field: "solar_day" })?,
birth_time: self.birth_time.ok_or(ChartError::MissingRequiredInput {
field: "birth_time",
})?,
gender: self
.gender
.ok_or(ChartError::MissingRequiredInput { field: "gender" })?,
fix_leap: self.fix_leap.unwrap_or(true),
method_profile: self
.method_profile
.ok_or(ChartError::MissingRequiredInput {
field: "method_profile",
})?,
})
}
}
pub fn by_solar(request: SolarChartRequest) -> Result<Chart, ChartError> {
let conversion = solar_to_lunar(
request.solar_year(),
request.solar_month(),
request.solar_day(),
request.birth_time_variant().iztro_time_index(),
)?;
let lunar_request = LunarChartRequest::builder()
.lunar_year(conversion.lunar_year())
.lunar_month(conversion.lunar_month())
.lunar_day(conversion.lunar_day())
.birth_time_variant(request.birth_time_variant())
.gender(request.gender())
.birth_year_stem(conversion.birth_year_stem())
.birth_year_branch(conversion.birth_year_branch())
.is_leap_month(conversion.is_leap_month())
.fix_leap(request.fix_leap())
.method_profile(request.method_profile().clone())
.build()?;
let chart = by_lunar(lunar_request)?;
let natal_dates = NatalDateFacts::new(
HoroscopeSolarDate::new(
request.solar_year(),
request.solar_month().value(),
request.solar_day().value(),
),
HoroscopeLunarDate::new(
conversion.lunar_year(),
conversion.lunar_month().value(),
conversion.lunar_day().value(),
conversion.is_leap_month(),
),
);
Ok(Chart::try_new_with_four_pillars(
chart.birth_context().clone(),
chart.birth_year(),
Some(conversion.four_pillars()),
chart.method_profile().clone(),
chart.palaces().to_vec(),
chart.body_palace_branch(),
chart.five_element_bureau(),
)?
.with_natal_date_facts(natal_dates))
}