use std::ops::{Add, Sub};
use jiff::{SignedDuration, Zoned, civil::Date};
use crate::astronomical_calculator;
use crate::util::geolocation::GeoLocation;
use crate::util::math_helper::MINUTE_NANOS;
#[must_use]
pub fn alos(
date: &Date,
geo_location: &GeoLocation,
use_elevation: bool,
offset: &ZmanOffset,
) -> Option<Zoned> {
match offset {
ZmanOffset::Degrees(deg) => astronomical_calculator::sunrise_offset_by_degrees(
date,
geo_location,
astronomical_calculator::GEOMETRIC_ZENITH + deg,
),
ZmanOffset::Minutes(min) => Some(
hanetz(date, geo_location, use_elevation)?
.sub(SignedDuration::from_nanos((min * MINUTE_NANOS) as i64)),
),
ZmanOffset::MinutesZmaniyos {
minutes_zmaniyos: minz,
shaah_zmanis: shaah,
} => Some(offset_by_minutes_zmanis(
&hanetz(date, geo_location, use_elevation)?,
-minz,
*shaah,
)),
}
}
#[must_use]
pub fn hanetz(date: &Date, geo_location: &GeoLocation, use_elevation: bool) -> Option<Zoned> {
if use_elevation {
astronomical_calculator::sunrise(date, geo_location)
} else {
astronomical_calculator::sea_level_sunrise(date, geo_location)
}
}
#[must_use]
pub fn sof_zman_shema(day_start: &Zoned, day_end: &Zoned) -> Zoned {
shaos_into_day(day_start, day_end, 3.0)
}
#[must_use]
pub fn sof_zman_tefila(day_start: &Zoned, day_end: &Zoned) -> Zoned {
shaos_into_day(day_start, day_end, 4.0)
}
#[must_use]
pub fn sof_zman_biur_chametz(day_start: &Zoned, day_end: &Zoned) -> Zoned {
shaos_into_day(day_start, day_end, 5.0)
}
#[must_use]
pub fn chatzos(date: &Date, geo_location: &GeoLocation) -> Option<Zoned> {
astronomical_calculator::solar_noon(date, geo_location)
}
#[must_use]
pub fn chatzos_halayla(date: &Date, geo_location: &GeoLocation) -> Option<Zoned> {
astronomical_calculator::solar_midnight(date, geo_location)
}
#[must_use]
pub fn fixed_local_chatzos(date: &Date, geo_location: &GeoLocation) -> Option<Zoned> {
astronomical_calculator::local_mean_time(date, geo_location, 12.0)
}
#[must_use]
pub fn mincha_gedola_30_minutes(date: &Date, geo_location: &GeoLocation) -> Option<Zoned> {
Some(chatzos(date, geo_location)?.add(SignedDuration::from_mins(30)))
}
#[must_use]
pub fn mincha_gedola(day_start: &Zoned, day_end: &Zoned) -> Zoned {
shaos_into_day(day_start, day_end, 6.5)
}
#[must_use]
pub fn samuch_lemincha_ketana(day_start: &Zoned, day_end: &Zoned) -> Zoned {
shaos_into_day(day_start, day_end, 9.0)
}
#[must_use]
pub fn mincha_ketana(day_start: &Zoned, day_end: &Zoned) -> Zoned {
shaos_into_day(day_start, day_end, 9.5)
}
#[must_use]
pub fn plag_hamincha(day_start: &Zoned, day_end: &Zoned) -> Zoned {
shaos_into_day(day_start, day_end, 10.75)
}
#[must_use]
pub fn shkia(date: &Date, geo_location: &GeoLocation, use_elevation: bool) -> Option<Zoned> {
if use_elevation {
astronomical_calculator::sunset(date, geo_location)
} else {
astronomical_calculator::sea_level_sunset(date, geo_location)
}
}
#[must_use]
pub fn tzeis(
date: &Date,
geo_location: &GeoLocation,
use_elevation: bool,
offset: &ZmanOffset,
) -> Option<Zoned> {
match offset {
ZmanOffset::Degrees(deg) => astronomical_calculator::sunset_offset_by_degrees(
date,
geo_location,
astronomical_calculator::GEOMETRIC_ZENITH + deg,
),
ZmanOffset::Minutes(min) => {
let sunset = shkia(date, geo_location, use_elevation)?;
Some(sunset.add(SignedDuration::from_nanos((min * MINUTE_NANOS) as i64)))
}
ZmanOffset::MinutesZmaniyos {
minutes_zmaniyos: minz,
shaah_zmanis: shaah,
} => {
let sunset = shkia(date, geo_location, use_elevation)?;
Some(offset_by_minutes_zmanis(&sunset, *minz, *shaah))
}
}
}
#[must_use]
pub fn shaah_zmanis(day_start: &Zoned, day_end: &Zoned) -> SignedDuration {
astronomical_calculator::temporal_hour(day_start, day_end)
}
fn offset_by_minutes_zmanis(time: &Zoned, minutes: f64, shaah_zmanis: SignedDuration) -> Zoned {
time.add(SignedDuration::from_secs_f64(
(shaah_zmanis / 60).as_secs_f64() * minutes,
))
}
fn shaos_into_day(day_start: &Zoned, day_end: &Zoned, shaos: f64) -> Zoned {
let shaah_zmanis = astronomical_calculator::temporal_hour(day_start, day_end);
offset_by_minutes_zmanis(day_start, shaos * 60.0, shaah_zmanis)
}
#[derive(Debug, Clone, PartialEq)]
pub enum ZmanOffset {
Degrees(f64),
Minutes(f64),
MinutesZmaniyos {
minutes_zmaniyos: f64,
shaah_zmanis: SignedDuration,
},
}