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}