{-# 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 qualified Data.OpenApi as O3
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
$cfrom :: forall x. DayOfWeek -> Rep DayOfWeek x
from :: forall x. DayOfWeek -> Rep DayOfWeek x
$cto :: forall x. Rep DayOfWeek x -> DayOfWeek
to :: forall x. Rep DayOfWeek x -> DayOfWeek
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
$cshowsPrec :: Int -> DayOfWeek -> ShowS
showsPrec :: Int -> DayOfWeek -> ShowS
$cshow :: DayOfWeek -> String
show :: DayOfWeek -> String
$cshowList :: [DayOfWeek] -> ShowS
showList :: [DayOfWeek] -> ShowS
Show, DayOfWeek -> DayOfWeek -> Bool
(DayOfWeek -> DayOfWeek -> Bool)
-> (DayOfWeek -> DayOfWeek -> Bool) -> Eq DayOfWeek
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: DayOfWeek -> DayOfWeek -> Bool
== :: DayOfWeek -> DayOfWeek -> Bool
$c/= :: DayOfWeek -> DayOfWeek -> Bool
/= :: DayOfWeek -> DayOfWeek -> Bool
Eq, DayOfWeek -> ()
(DayOfWeek -> ()) -> NFData DayOfWeek
forall a. (a -> ()) -> NFData a
$crnf :: DayOfWeek -> ()
rnf :: DayOfWeek -> ()
NFData, [DayOfWeek] -> Value
[DayOfWeek] -> Encoding
DayOfWeek -> Value
DayOfWeek -> Encoding
(DayOfWeek -> Value)
-> (DayOfWeek -> Encoding)
-> ([DayOfWeek] -> Value)
-> ([DayOfWeek] -> Encoding)
-> ToJSON DayOfWeek
forall a.
(a -> Value)
-> (a -> Encoding)
-> ([a] -> Value)
-> ([a] -> Encoding)
-> ToJSON a
$ctoJSON :: DayOfWeek -> Value
toJSON :: DayOfWeek -> Value
$ctoEncoding :: DayOfWeek -> Encoding
toEncoding :: DayOfWeek -> Encoding
$ctoJSONList :: [DayOfWeek] -> Value
toJSONList :: [DayOfWeek] -> Value
$ctoEncodingList :: [DayOfWeek] -> Encoding
toEncodingList :: [DayOfWeek] -> Encoding
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
$cparseJSON :: Value -> Parser DayOfWeek
parseJSON :: Value -> Parser DayOfWeek
$cparseJSONList :: Value -> Parser [DayOfWeek]
parseJSONList :: 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
$cdeclareNamedSchema :: Proxy DayOfWeek -> Declare (Definitions Schema) NamedSchema
declareNamedSchema :: Proxy DayOfWeek -> Declare (Definitions Schema) NamedSchema
ToSchema, Typeable DayOfWeek
Typeable DayOfWeek
-> (Proxy DayOfWeek -> Declare (Definitions Schema) NamedSchema)
-> ToSchema DayOfWeek
Proxy DayOfWeek -> Declare (Definitions Schema) NamedSchema
forall a.
Typeable a
-> (Proxy a -> Declare (Definitions Schema) NamedSchema)
-> ToSchema a
$cdeclareNamedSchema :: Proxy DayOfWeek -> Declare (Definitions Schema) NamedSchema
declareNamedSchema :: Proxy DayOfWeek -> Declare (Definitions Schema) NamedSchema
O3.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))