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()
            })
    }
}