augr_core/
timesheet.rs

1use crate::{repository::timesheet::PatchedTimesheet, EventRef, Tag};
2use chrono::{DateTime, Duration, Utc};
3use std::collections::{BTreeMap, BTreeSet};
4
5#[derive(Debug, Clone)]
6pub struct Event {
7    start: DateTime<Utc>,
8    tags: BTreeSet<Tag>,
9}
10
11#[derive(Clone, Debug)]
12pub struct Timesheet<'cl> {
13    patched_timesheet: &'cl PatchedTimesheet,
14    event_starts: BTreeMap<DateTime<Utc>, EventRef>,
15}
16
17#[derive(Clone, Debug)]
18pub struct Segment {
19    pub event_ref: EventRef,
20    pub start_time: DateTime<Utc>,
21    pub tags: BTreeSet<Tag>,
22    pub duration: Duration,
23    pub end_time: DateTime<Utc>,
24}
25
26impl Event {
27    pub fn new(start: DateTime<Utc>, tags: BTreeSet<Tag>) -> Self {
28        Self { start, tags }
29    }
30
31    pub fn start(&self) -> &DateTime<Utc> {
32        &self.start
33    }
34
35    pub fn tags(&self) -> &BTreeSet<Tag> {
36        &self.tags
37    }
38}
39
40impl<'a, 'b> PartialEq<Timesheet<'b>> for Timesheet<'a> {
41    fn eq(&self, other: &Timesheet) -> bool {
42        self.events().eq(&other.events())
43    }
44}
45
46impl Eq for Timesheet<'_> {}
47
48impl PartialEq<BTreeMap<DateTime<Utc>, BTreeSet<Tag>>> for Timesheet<'_> {
49    fn eq(&self, other: &BTreeMap<DateTime<Utc>, BTreeSet<Tag>>) -> bool {
50        self.events().eq(other)
51    }
52}
53
54impl<'cl> Timesheet<'cl> {
55    pub fn new(patched_timesheet: &'cl PatchedTimesheet) -> Self {
56        Self {
57            patched_timesheet,
58            event_starts: BTreeMap::new(),
59        }
60    }
61
62    pub fn get_patched_timesheet(&'cl self) -> &'cl PatchedTimesheet {
63        &self.patched_timesheet
64    }
65
66    pub fn event_at_time(&mut self, start: DateTime<Utc>, event_ref: EventRef) -> Option<EventRef> {
67        match self.event_starts.insert(start, event_ref) {
68            None => None,
69            Some(previous_event_ref) => Some(previous_event_ref),
70        }
71    }
72
73    pub fn events(&self) -> BTreeMap<DateTime<Utc>, BTreeSet<Tag>> {
74        self.event_starts
75            .iter()
76            .map(|(start, event_ref)| {
77                let tags = self.patched_timesheet.events[event_ref]
78                    .tags()
79                    .into_iter()
80                    .map(|(_patch_ref, tag)| tag)
81                    .collect();
82                (*start, tags)
83            })
84            .collect()
85    }
86
87    pub fn segments(&self) -> Vec<Segment> {
88        let now = Utc::now();
89        let end_cap_arr = [now];
90        self.event_starts
91            .iter()
92            .zip(self.event_starts.keys().skip(1).chain(end_cap_arr.iter()))
93            .map(|((start_time, event_ref), end_time)| {
94                let event = &self.patched_timesheet.events[event_ref];
95                let duration = end_time.signed_duration_since(*start_time);
96                Segment {
97                    event_ref: event_ref.clone(),
98                    start_time: *start_time,
99                    tags: event.tags().into_iter().map(|(_ref, tag)| tag).collect(),
100                    duration,
101                    end_time: *end_time,
102                }
103            })
104            .collect()
105    }
106
107    pub fn tags_at_time<'ts>(&'ts self, datetime: &DateTime<Utc>) -> Option<BTreeSet<Tag>> {
108        self.event_starts
109            .range::<DateTime<_>, _>(..datetime)
110            .last()
111            .map(|(_time, event_ref)| {
112                self.patched_timesheet.events[event_ref]
113                    .tags()
114                    .into_iter()
115                    .map(|(_patch_ref, tag)| tag)
116                    .collect()
117            })
118    }
119}