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