diff --git a/apps/cassiopeia/src/data.rs b/apps/cassiopeia/src/data.rs index 7442d699be8..47bb6e35b6e 100644 --- a/apps/cassiopeia/src/data.rs +++ b/apps/cassiopeia/src/data.rs @@ -4,14 +4,15 @@ //! used to generate new files, and perform various lookups and //! analysis tasks. -use crate::format::LineCfg; -use chrono::{DateTime, Duration, Local, FixedOffset as Offset, NaiveDate}; +use crate::{ + format::{IrItem, IrType, MakeIr}, + Date, Time, +}; +use chrono::{DateTime, Duration, FixedOffset as Offset, Local, NaiveDate}; use std::collections::BTreeMap; #[derive(Debug, Default)] pub struct TimeFile { - /// Raw line buffers to echo back into the file - lines: Vec, /// A parsed header structure header: BTreeMap, /// A parsed session structure @@ -21,70 +22,158 @@ pub struct TimeFile { } impl TimeFile { - pub(crate) fn append(mut self, line: LineCfg) -> Self { - let lo = self.lines.len(); + pub(crate) fn append(&mut self, line: IrItem) { match line { - LineCfg::Header(ref header) => self.header = header.clone(), - LineCfg::Start(Some(time)) => self.sessions.push(Session::start(time, lo)), - LineCfg::Stop(Some(time)) => self.get_last_session().stop(time, lo), - LineCfg::Invoice(Some(date)) => self.invoices.push(Invoice::new(date, lo)), + IrItem { + tt: IrType::Header(ref header), + .. + } => self.header = header.clone(), + IrItem { + tt: IrType::Start(time), + lo, + } => self.sessions.push(Session::start(time.into())), + IrItem { + tt: IrType::Stop(time), + lo, + } => self.get_last_session().unwrap().stop(time.into()), + IrItem { + tt: IrType::Invoice(date), + lo, + } => self.invoices.push(Invoice::new(date.into())), _ => {} } + } - self.lines.push(line); - self + fn get_last_session(&mut self) -> Option<&mut Session> { + self.sessions.last_mut() } - fn get_last_session(&mut self) -> &mut Session { - self.sessions.last_mut().unwrap() + fn get_last_invoice(&mut self) -> Option<&mut Invoice> { + self.invoices.last_mut() } /// Start a new session (optionally 15-minute rounded) - pub fn start(&mut self, round: bool) -> Option<()> { - let now = Local::now(); - + /// + /// This function returns the new session object that will have to + /// be turned into an IR line to be written back into the file + pub(crate) fn start(&mut self, round: bool) -> Option { + // Check if the last session was closed + match self.get_last_session() { + Some(s) if !s.finished() => return None, + _ => {} + } + + // Create a new time + let now = if round { + Time::now().round() + } else { + Time::now() + }; + + Some(Session::start(now)) + } + + /// Stop the last session that was started, returning a completed + /// session + pub(crate) fn stop(&mut self, round: bool) -> Option { + match self.get_last_session() { + Some(s) if s.finished() => return None, + None => return None, + _ => {} + } + + // Create a new time + let now = if round { + Time::now().round() + } else { + Time::now() + }; + + self.get_last_session().cloned().map(|mut s| { + s.stop(now); + s + }) + } + + /// Add a new invoice block to the time file + pub(crate) fn invoice(&mut self) -> Option<()> { + let today = Date::today(); + + let last_sess = self.get_last_session().cloned(); + + match self.get_last_invoice() { + // Check if _today_ there has been already an invoice + Some(i) if i.date == today => return None, + + // Check if since the last invoice there has been at least + // _one_ terminated session. + Some(i) + if !last_sess + .map(|s| !s.stop.map(|s| s.after(&i.date)).unwrap_or(false)) + .unwrap_or(false) => + { + return None + } + + // Otherwise, we create an invoice + _ => {} + } + + self.invoices.push(Invoice::new(today)); Some(()) } } -#[derive(Debug)] +#[derive(Clone, Debug)] pub struct Session { - start: DateTime, - stop: Option>, - /// Track the lines this session took place in - lines: (usize, usize), + start: Time, + stop: Option