use crate::common::math::TermNum;
use crate::day_count::Fixed;
use num_traits::AsPrimitive;
use num_traits::FromPrimitive;
use num_traits::ToPrimitive;
use std::cmp::PartialEq;
use std::fmt::Debug;
pub trait BoundedCycle<const N: u8, const M: u8>:
FromPrimitive + ToPrimitive + PartialEq + Debug
{
fn cycle_length() -> u8 {
N
}
fn min() -> u8 {
M
}
fn max() -> u8 {
match M {
0 => N - 1,
1 => N,
_ => panic!("M must be 0 or 1 for BoundedCycle"),
}
}
fn from_unbounded(x: i64) -> Self {
let m = match M {
0 => x.modulus(N.as_()),
1 => x.adjusted_remainder(N.as_()),
_ => panic!("M must be 0 or 1 for BoundedCycle"),
};
Self::from_i64(m).expect("Modulus guaranteed within range.")
}
fn to_unbounded(&self) -> i64 {
self.to_i64().expect("Guaranteed result")
}
}
pub trait OnOrBefore<const N: u8, const M: u8>: BoundedCycle<N, M> {
fn raw_on_or_before(self, date: i64) -> Fixed;
fn on_or_before(self, date: Fixed) -> Fixed {
self.raw_on_or_before(date.get_day_i())
}
fn on_or_after(self, date: Fixed) -> Fixed {
self.raw_on_or_before(date.get_day_i() + ((Self::cycle_length() as i64) - 1))
}
fn nearest(self, date: Fixed) -> Fixed {
self.raw_on_or_before(date.get_day_i() + ((Self::cycle_length() as i64) / 2))
}
fn before(self, date: Fixed) -> Fixed {
self.raw_on_or_before(date.get_day_i() - 1)
}
fn after(self, date: Fixed) -> Fixed {
self.raw_on_or_before(date.get_day_i() + (Self::cycle_length() as i64))
}
}