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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
use std::cmp::{min, max};

/// Time type that we use, currently corresponds to seconds, or unix time.
pub type TimeUnit = u64;

/// An event.
///
/// Ex:
/// - A club meeting is an event.
/// - A class in a course is an event.
/// - A swimming meet is an event.
/// - Fencing practice is an event.
#[derive(Eq, Serialize, Deserialize, Clone, Debug, Hash)]
pub struct Event {
    pub uuid: String,
    /// Offset from the start of the owning scheduleable.
    pub offset: TimeUnit,
    pub duration: TimeUnit,
    /// Time from start -> start of next event
    pub repeat: TimeUnit,
}

/// An option for a scheduleable.
///
/// Ex. A course is a scheduleable. A section of that course is one of its
/// scheduleable options.
#[derive(Clone, Eq, Serialize, Deserialize, Debug, Hash)]
pub struct ScheduleableOption {
    pub uuid: String,
    pub events: Vec<Event>,
}

/// Something which can be scheduled.
///
/// Ex:
/// - A course is a scheduleable.
/// - A a club is a scheduleable.
/// - A sport is a scheduleable.
#[derive(Clone, Eq, Serialize, Deserialize, Debug, Hash)]
pub struct Scheduleable {
    pub uuid: String,
    pub start: TimeUnit,
    /// Duration of this scheduleable.
    /// This should be at least the difference between the start of this
    /// scheduleable and the end of the last event or event repeat.
    pub duration: TimeUnit,
    pub options: Vec<ScheduleableOption>,
}


/// Labeled ScheduleabelOption, used in solver.
#[derive(Clone, Eq, PartialEq, Debug, Hash)]
pub struct InfoScheduleableOption<'option_lifetime> {
    pub inner: &'option_lifetime ScheduleableOption,
    start: TimeUnit,
    end: TimeUnit,
}

impl ::std::cmp::PartialEq for Scheduleable {
    fn eq(&self, other: &Self) -> bool {other.uuid == self.uuid}
}

impl ::std::cmp::PartialEq for ScheduleableOption {
    fn eq(&self, other: &Self) -> bool {other.uuid == self.uuid}
}

impl ::std::cmp::PartialEq for Event {
    fn eq(&self, other: &Self) -> bool {other.uuid == self.uuid}
}

impl Scheduleable {
    /// This scheduleables start + duration.
    pub fn get_end(&self) -> TimeUnit {self.start + self.duration}

    /// Labels all of the ScheduleableOptions in self.options
    pub fn label_options(&self) -> Vec<InfoScheduleableOption> {
        self.options
            .iter()
            .map(|scheduleable_option| {InfoScheduleableOption{
                inner: scheduleable_option,
                start: self.start,
                end: self.get_end(),
            }})
            .collect()
    }

    /// Returns true if none of the ScheduleableOptions conflict with themselves.
    pub fn is_valid(&self) -> bool { self.label_options().iter().all(|iso| iso.is_valid()) }

}

impl<'a> InfoScheduleableOption<'a> {

    /// Check if two InfoSceduleableOptions conflict.
    pub fn conflict(&self, other: &Self) -> bool {
        let start = max(self.start, other.start);
        let end = min(self.end, other.end);
        if end < start {false}
        else {
            let duration = end - start;
            !self.inner.events.iter()
                .any(|event| {
                    other.inner.events.iter()
                        .any(|event2| {
                            event.contains_between(0, event2.offset, duration) ||
                            event.contains_between(0, event2.get_end(), duration)
                        })
                })
        }
    }

    /// A ScheduleableOption is valid if none of its events conflict with each other.
    /// This is unfortunately an O(n^2) operation.
    fn is_valid(&self) -> bool {
        self.inner.events.iter()
            .map(|event| (event, &self.inner.events))
            .all(|(event, ref vec)| {
                !vec.iter()
                    .any(|event2| {
                        event.contains_between(0, event2.offset, self.end-self.start) ||
                        event.contains_between(0, event2.get_end(), self.end-self.start)
                    })
            })
    }
}


impl Event {
    /// Check if this event or any of its repetitions within `during`
    /// contain `time`.
    pub fn contains(&self, time: TimeUnit, during: &Scheduleable) -> bool {
        self.contains_between(during.start, time, during.get_end())
    }

    /// This event's offset + duration.
    pub fn get_end(&self) -> TimeUnit {self.offset + self.duration}


    fn contains_between(&self, start: TimeUnit, time: TimeUnit, end: TimeUnit) -> bool {
        let mut mut_start = self.offset + start;
        while mut_start < end {
            if mut_start <= time && mut_start + self.duration > time { return true }
                else if self.repeat != 0 { mut_start += self.repeat; }
                    else { return false }
        }
        false
    }

}