use crate::error::{Error, err};
use crate::series::{Series, SeriesCore};
use crate::{IntoBounds, Pattern, try_simplify_range};
use core::ops::{Bound, RangeBounds};
use jiff::{Span, civil::DateTime};
#[derive(Debug, Clone)]
pub struct SeriesWith<P> {
pattern: P,
bounds: (Bound<DateTime>, Bound<DateTime>),
fixpoint: Option<DateTime>,
event_duration: Span,
}
impl<P> SeriesWith<P>
where
P: Pattern,
{
pub(crate) fn new<B: RangeBounds<DateTime>>(range: B, pattern: P) -> SeriesWith<P> {
SeriesWith {
pattern,
bounds: range.into_bounds(),
fixpoint: None,
event_duration: Span::new(),
}
}
pub(crate) fn from_series(series: &Series<P>) -> SeriesWith<P> {
SeriesWith {
pattern: series.core.pattern.clone(),
bounds: series.range.into_bounds(),
fixpoint: series.range.fixpoint,
event_duration: series.core.event_duration,
}
}
#[must_use]
pub fn range<B: RangeBounds<DateTime>>(mut self, range: B) -> SeriesWith<P> {
self.bounds = range.into_bounds();
self
}
#[must_use]
pub fn start(mut self, start: DateTime) -> SeriesWith<P> {
self.bounds.0 = Bound::Included(start);
self
}
#[must_use]
pub fn end(mut self, end: DateTime) -> SeriesWith<P> {
self.bounds.1 = Bound::Excluded(end);
self
}
#[must_use]
pub fn fixpoint(mut self, fixpoint: DateTime) -> SeriesWith<P> {
self.fixpoint = Some(fixpoint);
self
}
#[must_use]
pub fn event_duration(mut self, event_duration: Span) -> SeriesWith<P> {
self.event_duration = event_duration;
self
}
#[must_use]
pub fn pattern<Q: Pattern>(self, pattern: Q) -> SeriesWith<Q> {
SeriesWith {
pattern,
bounds: self.bounds,
fixpoint: self.fixpoint,
event_duration: self.event_duration,
}
}
pub fn build(self) -> Result<Series<P>, Error> {
let mut range = try_simplify_range(self.bounds)?;
if self.event_duration.is_negative() {
return Err(err!(
"event duration must be positive or zero but got {}",
self.event_duration
));
}
if self.event_duration.is_positive() {
range.end = range.end.checked_sub(self.event_duration)?;
}
if range.start >= range.end {
return Err(Error::datetime_range("series", range.into()));
}
if let Some(fixpoint) = self.fixpoint {
range = range.with_fixpoint(fixpoint)?;
}
Ok(Series {
core: SeriesCore::new(self.pattern, self.event_duration),
range,
})
}
}