packages feed

conditional-restriction-parser-0.1.0.4: src/ConditionalRestriction/Internal/Parse/OpeningHoursParser.hs

-- | Parser for opening hours (incomplete).
module ConditionalRestriction.Internal.Parse.OpeningHoursParser where

import ConditionalRestriction.Internal.Parse.ParserLib
  ( Parser,
    bint,
    noneOf,
    str,
    word,
    ws,
  )
import ConditionalRestriction.Parse.AST
  ( OHState,
    OpeningHours (..),
    RuleSequence (..),
    RuleType (..),
    SelectorSequence (..),
    TimeSelector,
    TimeSpan (..),
    WeekdayRange (..),
    WeekdaySelector,
  )
import Control.Applicative (Alternative (many, (<|>)), optional)
import Data.Hourglass (TimeOfDay (TimeOfDay), WeekDay (..))

-- | Parse opening hours, e.g. @"Di-Fr 08:00-20:00"@.
pOpeningHours :: Parser String OpeningHours
pOpeningHours = OpeningHours <$> ((:) <$> pRuleSequence Normal <*> many next_rule_sequence)
  where
    next_rule_sequence =
      word ";" *> pRuleSequence Normal
        <|> word "," *> pRuleSequence Additional

pRuleSequence :: RuleType -> Parser String RuleSequence
pRuleSequence t = RuleSequence t <$> pSelectorSequence <*> pRuleModifier

pRuleModifier :: Parser String OHState
pRuleModifier =
  ( Just False <$ (word "closed" <|> word "off")
      <|> Nothing <$ word "unknown"
      <|> Just True <$ (word "open" <|> ws)
  )
    <* optional pComment

pSelectorSequence :: Parser String SelectorSequence
pSelectorSequence =
  TwentyFourSeven <$ word "24/7"
    <|> (WeekdayTime <$> pWeekdaySelector <*> pTimeSelector)
    <|> (WeekdaySel <$> pWeekdaySelector)
    <|> (TimeSel <$> pTimeSelector)

pWeekdaySelector :: Parser String WeekdaySelector
pWeekdaySelector = (:) <$> pWeekdayRange <*> many (word "," *> pWeekdayRange)

pTimeSelector :: Parser String TimeSelector
pTimeSelector = (:) <$> pTimeSpan <*> many (word "," *> pTimeSpan)

pWeekdayRange :: Parser String WeekdayRange
pWeekdayRange =
  WdayRange <$> pWday <*> (word "-" *> pWday)
    <|> SingleDay <$> pWday

pWday :: Parser String WeekDay
pWday =
  Sunday <$ word "Su"
    <|> Monday <$ word "Mo"
    <|> Tuesday <$ word "Tu"
    <|> Wednesday <$ word "We"
    <|> Thursday <$ word "Th"
    <|> Friday <$ word "Fr"
    <|> Saturday <$ word "Sa"

pTimeSpan :: Parser String TimeSpan
pTimeSpan =
  (Span <$> pTime False <*> (word "-" *> pTime True))
    <|> Moment <$> pTime False

pTime :: Bool -> Parser String TimeOfDay
pTime extended = (\h m -> TimeOfDay (fromIntegral h) (fromIntegral m) 0 0) <$> p_hour <*> (str ":" *> bint 59)
  where
    p_hour = if extended then bint 48 else bint 24

pComment :: Parser String String
pComment = str "\"" *> many (noneOf "\"") <* word "\""