use chrono::{NaiveTime, TimeDelta};
use std::fmt::{Display, Formatter};
use std::time::Duration;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct NeralieTime {
pub beats: i64,
pub pulses: i64,
}
impl From<Duration> for NeralieTime {
fn from(value: Duration) -> Self {
let total_beats = value.as_secs_f64() / 86.4;
let total_pulses = value.as_secs_f64() / (86.4 / 1000.0);
let beats = total_beats.floor() as i64;
let pulses = (total_pulses - total_beats.floor() * 1000.0).ceil() as i64;
Self { beats, pulses }
}
}
impl From<NeralieTime> for Duration {
fn from(val: NeralieTime) -> Self {
Duration::from_secs_f64(
((val.beats as f64 + (val.pulses as f64 / 1000.0)) * 86.4).round_ties_even(),
)
}
}
impl From<TimeDelta> for NeralieTime {
fn from(value: TimeDelta) -> Self {
let total_beats = value.as_seconds_f64() / 86.4;
let total_pulses = value.as_seconds_f64() / (86.4 / 1000.0);
let beats = total_beats.floor() as i64;
let pulses = (total_pulses - total_beats.floor() * 1000.0).ceil() as i64;
Self { beats, pulses }
}
}
impl From<NeralieTime> for TimeDelta {
fn from(value: NeralieTime) -> Self {
TimeDelta::from_std(Duration::from(value)).unwrap()
}
}
impl From<NaiveTime> for NeralieTime {
fn from(value: chrono::NaiveTime) -> Self {
value.signed_duration_since(NaiveTime::MIN).into()
}
}
impl From<NeralieTime> for NaiveTime {
fn from(value: NeralieTime) -> Self {
let duration = Duration::from(value);
let total_milli = duration.as_millis();
let total_sec = duration.as_secs();
let total_min = total_sec / 60;
let total_hour = total_min / 60;
let hour = total_hour as u32;
let min = (total_min - total_hour * 60) as u32;
let sec = (total_sec - total_min * 60) as u32;
let milli = (total_milli - (total_sec as u128 * 1000)) as u32;
NaiveTime::from_hms_milli_opt(hour, min, sec, milli).unwrap()
}
}
impl Display for NeralieTime {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{:0>3}:{:0>3}", self.beats, self.pulses)
}
}