use crate::core::error::ChartError;
use crate::core::model::calendar::{BirthTime, SolarDay, SolarMonth};
use crate::core::model::chart::{
Chart, HoroscopeChart, HoroscopeLunarDate, HoroscopeSolarDate, HoroscopeTargetContext,
TemporalLayer, build_age_period, build_daily_period, build_decadal_frame, build_hourly_period,
build_monthly_period, build_yearly_period, nominal_age_for_target_year,
select_decadal_period_by_age, target_lunar_date,
};
use crate::core::placement::overlay::age::build_age_horoscope_layer;
use crate::core::placement::overlay::daily_horoscope::build_daily_horoscope_layer;
use crate::core::placement::overlay::decadal_horoscope::build_decadal_horoscope_layer;
use crate::core::placement::overlay::hourly_horoscope::build_hourly_horoscope_layer;
use crate::core::placement::overlay::monthly_horoscope::build_monthly_horoscope_layer;
use crate::core::placement::overlay::yearly_horoscope::build_yearly_horoscope_layer;
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub struct HoroscopeStackInput {
target_solar_year: i32,
target_solar_month: SolarMonth,
target_solar_day: SolarDay,
target_time: BirthTime,
}
impl HoroscopeStackInput {
pub const fn new(
target_solar_year: i32,
target_solar_month: SolarMonth,
target_solar_day: SolarDay,
target_time: BirthTime,
) -> Self {
Self {
target_solar_year,
target_solar_month,
target_solar_day,
target_time,
}
}
pub const fn target_solar_year(&self) -> i32 {
self.target_solar_year
}
pub const fn target_solar_month(&self) -> SolarMonth {
self.target_solar_month
}
pub const fn target_solar_day(&self) -> SolarDay {
self.target_solar_day
}
pub const fn target_time(&self) -> BirthTime {
self.target_time
}
}
pub fn build_full_horoscope_chart(
natal: Chart,
input: HoroscopeStackInput,
) -> Result<HoroscopeChart, ChartError> {
let target_lunar = target_lunar_date(
input.target_solar_year,
input.target_solar_month,
input.target_solar_day,
)?;
let nominal_age = nominal_age_for_target_year(&natal, target_lunar.year)?;
let decadal_frame = build_decadal_frame(&natal)?;
let decadal_period = select_decadal_period_by_age(&decadal_frame, nominal_age)?;
let decadal_layer = build_decadal_horoscope_layer(&natal, decadal_period)?;
let age_period = build_age_period(&natal, nominal_age)?;
let age_layer = build_age_horoscope_layer(&natal, &age_period)?;
let yearly_period = build_yearly_period(target_lunar.year)?;
let yearly_layer = build_yearly_horoscope_layer(&natal, &yearly_period)?;
let monthly_period = build_monthly_period(
&natal,
input.target_solar_year,
input.target_solar_month,
input.target_solar_day,
input.target_time,
)?;
let monthly_layer = build_monthly_horoscope_layer(&natal, &monthly_period)?;
let daily_period = build_daily_period(
&natal,
input.target_solar_year,
input.target_solar_month,
input.target_solar_day,
input.target_time,
)?;
let daily_layer = build_daily_horoscope_layer(&natal, &daily_period)?;
let hourly_period = build_hourly_period(
&natal,
input.target_solar_year,
input.target_solar_month,
input.target_solar_day,
input.target_time,
)?;
let hourly_layer = build_hourly_horoscope_layer(&natal, &hourly_period)?;
let layers: Vec<TemporalLayer> = vec![
decadal_layer,
age_layer,
yearly_layer,
monthly_layer,
daily_layer,
hourly_layer,
];
let target_context = HoroscopeTargetContext::new(
HoroscopeSolarDate::new(
input.target_solar_year,
input.target_solar_month.value(),
input.target_solar_day.value(),
),
HoroscopeLunarDate::new(
target_lunar.year,
target_lunar.month,
target_lunar.day,
target_lunar.is_leap_month,
),
input.target_time.iztro_time_index(),
);
Ok(HoroscopeChart::with_layers_and_target_context(
natal,
layers,
target_context,
))
}