{-# LANGUAGE DeriveAnyClass #-}

-- This module pins down the details of week days in the API. It's boilerplate-y
-- but that makes it robust.

-- | A day of week type. Integer representations are not used in the API, but
-- are provided for convenience and will not change.
module Hercules.API.DayOfWeek
  ( DayOfWeek (..),

    -- * Conversions for @time@ package
    toTime,
    fromTime,

    -- * Optional, stable, opinionated integer conversions
    toNum,
    fromNumMaybe,
    fromNum,
  )
where

import Control.DeepSeq (NFData)
import Data.Aeson (FromJSON, ToJSON)
import Data.Maybe (fromJust)
import Data.Swagger (ToSchema)
import qualified Data.Time
import GHC.Generics (Generic)
import Prelude (Eq, Integral, Maybe (..), Num (..), Show, mod)

-- | Day of week representation used in the API.
data DayOfWeek = Mon | Tue | Wed | Thu | Fri | Sat | Sun
  deriving ((forall x. DayOfWeek -> Rep DayOfWeek x)
-> (forall x. Rep DayOfWeek x -> DayOfWeek) -> Generic DayOfWeek
forall x. Rep DayOfWeek x -> DayOfWeek
forall x. DayOfWeek -> Rep DayOfWeek x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep DayOfWeek x -> DayOfWeek
$cfrom :: forall x. DayOfWeek -> Rep DayOfWeek x
Generic, Int -> DayOfWeek -> ShowS
[DayOfWeek] -> ShowS
DayOfWeek -> String
(Int -> DayOfWeek -> ShowS)
-> (DayOfWeek -> String)
-> ([DayOfWeek] -> ShowS)
-> Show DayOfWeek
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [DayOfWeek] -> ShowS
$cshowList :: [DayOfWeek] -> ShowS
show :: DayOfWeek -> String
$cshow :: DayOfWeek -> String
showsPrec :: Int -> DayOfWeek -> ShowS
$cshowsPrec :: Int -> DayOfWeek -> ShowS
Show, DayOfWeek -> DayOfWeek -> Bool
(DayOfWeek -> DayOfWeek -> Bool)
-> (DayOfWeek -> DayOfWeek -> Bool) -> Eq DayOfWeek
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: DayOfWeek -> DayOfWeek -> Bool
$c/= :: DayOfWeek -> DayOfWeek -> Bool
== :: DayOfWeek -> DayOfWeek -> Bool
$c== :: DayOfWeek -> DayOfWeek -> Bool
Eq, DayOfWeek -> ()
(DayOfWeek -> ()) -> NFData DayOfWeek
forall a. (a -> ()) -> NFData a
rnf :: DayOfWeek -> ()
$crnf :: DayOfWeek -> ()
NFData, [DayOfWeek] -> Encoding
[DayOfWeek] -> Value
DayOfWeek -> Encoding
DayOfWeek -> Value
(DayOfWeek -> Value)
-> (DayOfWeek -> Encoding)
-> ([DayOfWeek] -> Value)
-> ([DayOfWeek] -> Encoding)
-> ToJSON DayOfWeek
forall a.
(a -> Value)
-> (a -> Encoding)
-> ([a] -> Value)
-> ([a] -> Encoding)
-> ToJSON a
toEncodingList :: [DayOfWeek] -> Encoding
$ctoEncodingList :: [DayOfWeek] -> Encoding
toJSONList :: [DayOfWeek] -> Value
$ctoJSONList :: [DayOfWeek] -> Value
toEncoding :: DayOfWeek -> Encoding
$ctoEncoding :: DayOfWeek -> Encoding
toJSON :: DayOfWeek -> Value
$ctoJSON :: DayOfWeek -> Value
ToJSON, Value -> Parser [DayOfWeek]
Value -> Parser DayOfWeek
(Value -> Parser DayOfWeek)
-> (Value -> Parser [DayOfWeek]) -> FromJSON DayOfWeek
forall a.
(Value -> Parser a) -> (Value -> Parser [a]) -> FromJSON a
parseJSONList :: Value -> Parser [DayOfWeek]
$cparseJSONList :: Value -> Parser [DayOfWeek]
parseJSON :: Value -> Parser DayOfWeek
$cparseJSON :: Value -> Parser DayOfWeek
FromJSON, Proxy DayOfWeek -> Declare (Definitions Schema) NamedSchema
(Proxy DayOfWeek -> Declare (Definitions Schema) NamedSchema)
-> ToSchema DayOfWeek
forall a.
(Proxy a -> Declare (Definitions Schema) NamedSchema) -> ToSchema a
declareNamedSchema :: Proxy DayOfWeek -> Declare (Definitions Schema) NamedSchema
$cdeclareNamedSchema :: Proxy DayOfWeek -> Declare (Definitions Schema) NamedSchema
ToSchema)

-- | Conversion to @time@ package representation.
toTime :: DayOfWeek -> Data.Time.DayOfWeek
toTime :: DayOfWeek -> DayOfWeek
toTime DayOfWeek
Mon = DayOfWeek
Data.Time.Monday
toTime DayOfWeek
Tue = DayOfWeek
Data.Time.Tuesday
toTime DayOfWeek
Wed = DayOfWeek
Data.Time.Wednesday
toTime DayOfWeek
Thu = DayOfWeek
Data.Time.Thursday
toTime DayOfWeek
Fri = DayOfWeek
Data.Time.Friday
toTime DayOfWeek
Sat = DayOfWeek
Data.Time.Saturday
toTime DayOfWeek
Sun = DayOfWeek
Data.Time.Sunday

-- | Conversion from @time@ package representation.
fromTime :: Data.Time.DayOfWeek -> DayOfWeek
fromTime :: DayOfWeek -> DayOfWeek
fromTime DayOfWeek
Data.Time.Monday = DayOfWeek
Mon
fromTime DayOfWeek
Data.Time.Tuesday = DayOfWeek
Tue
fromTime DayOfWeek
Data.Time.Wednesday = DayOfWeek
Wed
fromTime DayOfWeek
Data.Time.Thursday = DayOfWeek
Thu
fromTime DayOfWeek
Data.Time.Friday = DayOfWeek
Fri
fromTime DayOfWeek
Data.Time.Saturday = DayOfWeek
Sat
fromTime DayOfWeek
Data.Time.Sunday = DayOfWeek
Sun

-- | Conversion to integers where 'Mon' -> 1, 'Sun' -> 7
toNum :: Num n => DayOfWeek -> n
toNum :: forall n. Num n => DayOfWeek -> n
toNum DayOfWeek
Mon = n
1
toNum DayOfWeek
Tue = n
2
toNum DayOfWeek
Wed = n
3
toNum DayOfWeek
Thu = n
4
toNum DayOfWeek
Fri = n
5
toNum DayOfWeek
Sat = n
6
toNum DayOfWeek
Sun = n
7

-- | Conversion from integers where @1 -> Just 'Mon'@, @7 -> Just 'Sun'@, @outside of 1..7 -> Nothing@
fromNumMaybe :: (Num n, Eq n) => n -> Maybe DayOfWeek
fromNumMaybe :: forall n. (Num n, Eq n) => n -> Maybe DayOfWeek
fromNumMaybe n
1 = DayOfWeek -> Maybe DayOfWeek
forall a. a -> Maybe a
Just DayOfWeek
Mon
fromNumMaybe n
2 = DayOfWeek -> Maybe DayOfWeek
forall a. a -> Maybe a
Just DayOfWeek
Tue
fromNumMaybe n
3 = DayOfWeek -> Maybe DayOfWeek
forall a. a -> Maybe a
Just DayOfWeek
Wed
fromNumMaybe n
4 = DayOfWeek -> Maybe DayOfWeek
forall a. a -> Maybe a
Just DayOfWeek
Thu
fromNumMaybe n
5 = DayOfWeek -> Maybe DayOfWeek
forall a. a -> Maybe a
Just DayOfWeek
Fri
fromNumMaybe n
6 = DayOfWeek -> Maybe DayOfWeek
forall a. a -> Maybe a
Just DayOfWeek
Sat
fromNumMaybe n
7 = DayOfWeek -> Maybe DayOfWeek
forall a. a -> Maybe a
Just DayOfWeek
Sun
fromNumMaybe n
_ = Maybe DayOfWeek
forall a. Maybe a
Nothing

-- | Conversion from integers where @{...,-7,0,7,...} -> Just 'Sun'@, @{...,-6,1,8,...} -> Just 'Mon'@, etc.
--
-- Requires a sensible implementation of the 'Integral' 'mod' method that returns non-negative numbers.
-- 'Integer', 'Int', 'Int8', etc are ok. So is the 'Word' family of types, though beware of 'minBound' overflows.
fromNum :: (Integral n, Eq n) => n -> DayOfWeek
fromNum :: forall n. (Integral n, Eq n) => n -> DayOfWeek
fromNum n
n = Maybe DayOfWeek -> DayOfWeek
forall a. HasCallStack => Maybe a -> a
fromJust (n -> Maybe DayOfWeek
forall n. (Num n, Eq n) => n -> Maybe DayOfWeek
fromNumMaybe (n
1 n -> n -> n
forall a. Num a => a -> a -> a
+ (n
n n -> n -> n
forall a. Num a => a -> a -> a
- n
1) n -> n -> n
forall a. Integral a => a -> a -> a
`mod` n
7))