//! Typed time file for cassiopeia //! //! This data gets generated by the `format` module, and can later be //! 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 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 sessions: Vec, /// A parsed invoice list invoices: Vec, } impl TimeFile { pub(crate) fn append(mut self, line: LineCfg) -> Self { let lo = self.lines.len(); 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)), _ => {} } self.lines.push(line); self } fn get_last_session(&mut self) -> &mut Session { self.sessions.last_mut().unwrap() } /// Start a new session (optionally 15-minute rounded) pub fn start(&mut self, round: bool) -> Option<()> { let now = Local::now(); Some(()) } } #[derive(Debug)] pub struct Session { start: DateTime, stop: Option>, /// Track the lines this session took place in lines: (usize, usize), } impl Session { /// Create a new session with a start time fn start(start: DateTime, line: usize) -> Self { Self { start, stop: None, lines: (line, 0), } } /// Finalise a session with a stop time fn stop(&mut self, stop: DateTime, line: usize) { self.stop = Some(stop); self.lines.1 = line; } /// Get the length of the session, if it was already finished pub fn length(&self) -> Option { self.stop.map(|stop| stop - self.start) } } #[derive(Debug)] pub struct Invoice { date: NaiveDate, line: usize, } impl Invoice { fn new(date: NaiveDate, line: usize) -> Self { Self { date, line } } }