-- SPDX-FileCopyrightText: 2022 Gregor Kleen -- -- SPDX-License-Identifier: AGPL-3.0-or-later module Handler.Utils.Occurrences ( occurrencesWidget , occurrencesBounds , occurrencesAddBusinessDays ) where import Import import qualified Data.Set as Set import Utils.Holidays (isWeekend) import Utils.Occurrences import Handler.Utils.DateTime occurrencesWidget :: Occurrences -> Widget occurrencesWidget (normalizeOccurrences -> Occurrences{..}) = do let occurrencesScheduled' = flip map (Set.toList occurrencesScheduled) $ \case ScheduleWeekly{..} -> do scheduleStart' <- formatTime SelFormatTime scheduleStart scheduleEnd' <- formatTime SelFormatTime scheduleEnd $(widgetFile "widgets/occurrence/cell/weekly") occurrencesExceptions' = flip map (Set.toList occurrencesExceptions) $ \case ExceptOccur{..} -> do exceptStart' <- formatTime SelFormatDateTime (LocalTime exceptDay exceptStart) exceptEnd' <- formatTime SelFormatTime exceptEnd $(widgetFile "widgets/occurrence/cell/except-occur") ExceptNoOccur{..} -> do exceptTime' <- formatTime SelFormatDateTime exceptTime $(widgetFile "widgets/occurrence/cell/except-no-occur") $(widgetFile "widgets/occurrence/cell") -- | Get bounds for an Occurrences occurrencesBounds :: Term -> Occurrences -> (Maybe Day, Maybe Day) occurrencesBounds Term{..} Occurrences{..} = (Set.lookupMin occDays, Set.lookupMax occDays) where occDays = (scdDays <> plsDays) \\ excDays -- (excDays <> termHolidays term) -- TODO: should holidays be exluded here? Probably not, as they can be added as exceptions already scdDays = Set.foldr getOccDays mempty occurrencesScheduled (plsDays,excDays) = Set.foldr getExcDays mempty occurrencesExceptions getExcDays :: OccurrenceException -> (Set Day, Set Day) -> (Set Day, Set Day) getExcDays ExceptNoOccur{exceptTime} (occ,exc) = (occ, Set.insert (localDay exceptTime) exc) getExcDays ExceptOccur{exceptDay} (occ,exc) = (Set.insert exceptDay occ, exc) getOccDays :: OccurrenceSchedule -> Set Day -> Set Day getOccDays ScheduleWeekly{scheduleDayOfWeek=wday} = Set.union $ daysOfWeekBetween (termLectureStart,termLectureEnd) wday occurrencesAddBusinessDays :: Term -> (Day,Day) -> Occurrences -> Occurrences occurrencesAddBusinessDays Term{..} (dayOld, dayNew) Occurrences{..} = Occurrences newSchedule newExceptions where newSchedule = Set.map switchDayOfWeek occurrencesScheduled dayDiff = diffDays dayNew dayOld offDays = Set.fromList $ termHolidays <> weekends weekends = [d | d <- [(min termLectureStart termStart)..(max termEnd termLectureEnd)], isWeekend d] switchDayOfWeek :: OccurrenceSchedule -> OccurrenceSchedule switchDayOfWeek os | 0 == dayDiff `mod` 7 = os switchDayOfWeek os@ScheduleWeekly{scheduleDayOfWeek=wday} = os{scheduleDayOfWeek= toEnum (fromIntegral dayDiff + fromEnum wday)} newExceptions = snd $ Set.foldl' advanceExceptions (dayDiff,mempty) occurrencesExceptions -- we assume that instance Ord OccurrenceException is ordered chronologically advanceExceptions :: (Integer, Set OccurrenceException) -> OccurrenceException -> (Integer, Set OccurrenceException) advanceExceptions (offset, acc) ex | ed `Set.notMember` offDays -- skip term-holidays and weekends, unless the original day was a holiday or weekend , nd `Set.member` offDays = advanceExceptions (succ offset, acc) ex | otherwise = (offset, Set.insert (setDayOfOccurrenceException nd ex) acc) where ed = dayOfOccurrenceException ex nd = addDays offset ed