{-# LANGUAGE CPP #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}

module Data.FuzzyTime.Types
  ( module Data.FuzzyTime.Types,
    DayOfWeek (..),
  )
where

import Control.DeepSeq (NFData)
import Data.Fixed (Pico)
import Data.Int (Int16)
import Data.Time (Day, DayOfWeek (Friday, Monday, Saturday, Sunday, Thursday, Tuesday, Wednesday), LocalTime, TimeOfDay)
import Data.Validity (Validity (validate), declare, decorate, genericValidate, valid)
import Data.Validity.Time ()
import Data.Word (Word8)
import GHC.Generics (Generic)

data AmbiguousLocalTime
  = OnlyDaySpecified !Day
  | BothTimeAndDay !LocalTime
  deriving (Int -> AmbiguousLocalTime -> ShowS
[AmbiguousLocalTime] -> ShowS
AmbiguousLocalTime -> String
(Int -> AmbiguousLocalTime -> ShowS)
-> (AmbiguousLocalTime -> String)
-> ([AmbiguousLocalTime] -> ShowS)
-> Show AmbiguousLocalTime
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> AmbiguousLocalTime -> ShowS
showsPrec :: Int -> AmbiguousLocalTime -> ShowS
$cshow :: AmbiguousLocalTime -> String
show :: AmbiguousLocalTime -> String
$cshowList :: [AmbiguousLocalTime] -> ShowS
showList :: [AmbiguousLocalTime] -> ShowS
Show, AmbiguousLocalTime -> AmbiguousLocalTime -> Bool
(AmbiguousLocalTime -> AmbiguousLocalTime -> Bool)
-> (AmbiguousLocalTime -> AmbiguousLocalTime -> Bool)
-> Eq AmbiguousLocalTime
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: AmbiguousLocalTime -> AmbiguousLocalTime -> Bool
== :: AmbiguousLocalTime -> AmbiguousLocalTime -> Bool
$c/= :: AmbiguousLocalTime -> AmbiguousLocalTime -> Bool
/= :: AmbiguousLocalTime -> AmbiguousLocalTime -> Bool
Eq, (forall x. AmbiguousLocalTime -> Rep AmbiguousLocalTime x)
-> (forall x. Rep AmbiguousLocalTime x -> AmbiguousLocalTime)
-> Generic AmbiguousLocalTime
forall x. Rep AmbiguousLocalTime x -> AmbiguousLocalTime
forall x. AmbiguousLocalTime -> Rep AmbiguousLocalTime x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. AmbiguousLocalTime -> Rep AmbiguousLocalTime x
from :: forall x. AmbiguousLocalTime -> Rep AmbiguousLocalTime x
$cto :: forall x. Rep AmbiguousLocalTime x -> AmbiguousLocalTime
to :: forall x. Rep AmbiguousLocalTime x -> AmbiguousLocalTime
Generic)

instance Validity AmbiguousLocalTime

instance NFData AmbiguousLocalTime

data FuzzyLocalTime
  = FuzzyLocalTimeDay !FuzzyDay
  | FuzzyLocalTimeTimeOfDay !FuzzyTimeOfDay
  | FuzzyLocalTimeBoth !FuzzyDay !FuzzyTimeOfDay
  deriving (Int -> FuzzyLocalTime -> ShowS
[FuzzyLocalTime] -> ShowS
FuzzyLocalTime -> String
(Int -> FuzzyLocalTime -> ShowS)
-> (FuzzyLocalTime -> String)
-> ([FuzzyLocalTime] -> ShowS)
-> Show FuzzyLocalTime
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> FuzzyLocalTime -> ShowS
showsPrec :: Int -> FuzzyLocalTime -> ShowS
$cshow :: FuzzyLocalTime -> String
show :: FuzzyLocalTime -> String
$cshowList :: [FuzzyLocalTime] -> ShowS
showList :: [FuzzyLocalTime] -> ShowS
Show, FuzzyLocalTime -> FuzzyLocalTime -> Bool
(FuzzyLocalTime -> FuzzyLocalTime -> Bool)
-> (FuzzyLocalTime -> FuzzyLocalTime -> Bool) -> Eq FuzzyLocalTime
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: FuzzyLocalTime -> FuzzyLocalTime -> Bool
== :: FuzzyLocalTime -> FuzzyLocalTime -> Bool
$c/= :: FuzzyLocalTime -> FuzzyLocalTime -> Bool
/= :: FuzzyLocalTime -> FuzzyLocalTime -> Bool
Eq, (forall x. FuzzyLocalTime -> Rep FuzzyLocalTime x)
-> (forall x. Rep FuzzyLocalTime x -> FuzzyLocalTime)
-> Generic FuzzyLocalTime
forall x. Rep FuzzyLocalTime x -> FuzzyLocalTime
forall x. FuzzyLocalTime -> Rep FuzzyLocalTime x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. FuzzyLocalTime -> Rep FuzzyLocalTime x
from :: forall x. FuzzyLocalTime -> Rep FuzzyLocalTime x
$cto :: forall x. Rep FuzzyLocalTime x -> FuzzyLocalTime
to :: forall x. Rep FuzzyLocalTime x -> FuzzyLocalTime
Generic)

instance Validity FuzzyLocalTime

instance NFData FuzzyLocalTime

data FuzzyTimeOfDay
  = SameTime
  | Noon
  | Midnight
  | Morning
  | Evening
  | AtHour Int
  | AtMinute Int Int
  | AtExact TimeOfDay
  | HoursDiff Int -- Max 24
  | MinutesDiff Int -- Max 24 * 60
  | SecondsDiff Pico -- Max 24 * 60 * 60
  deriving (Int -> FuzzyTimeOfDay -> ShowS
[FuzzyTimeOfDay] -> ShowS
FuzzyTimeOfDay -> String
(Int -> FuzzyTimeOfDay -> ShowS)
-> (FuzzyTimeOfDay -> String)
-> ([FuzzyTimeOfDay] -> ShowS)
-> Show FuzzyTimeOfDay
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> FuzzyTimeOfDay -> ShowS
showsPrec :: Int -> FuzzyTimeOfDay -> ShowS
$cshow :: FuzzyTimeOfDay -> String
show :: FuzzyTimeOfDay -> String
$cshowList :: [FuzzyTimeOfDay] -> ShowS
showList :: [FuzzyTimeOfDay] -> ShowS
Show, FuzzyTimeOfDay -> FuzzyTimeOfDay -> Bool
(FuzzyTimeOfDay -> FuzzyTimeOfDay -> Bool)
-> (FuzzyTimeOfDay -> FuzzyTimeOfDay -> Bool) -> Eq FuzzyTimeOfDay
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: FuzzyTimeOfDay -> FuzzyTimeOfDay -> Bool
== :: FuzzyTimeOfDay -> FuzzyTimeOfDay -> Bool
$c/= :: FuzzyTimeOfDay -> FuzzyTimeOfDay -> Bool
/= :: FuzzyTimeOfDay -> FuzzyTimeOfDay -> Bool
Eq, (forall x. FuzzyTimeOfDay -> Rep FuzzyTimeOfDay x)
-> (forall x. Rep FuzzyTimeOfDay x -> FuzzyTimeOfDay)
-> Generic FuzzyTimeOfDay
forall x. Rep FuzzyTimeOfDay x -> FuzzyTimeOfDay
forall x. FuzzyTimeOfDay -> Rep FuzzyTimeOfDay x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. FuzzyTimeOfDay -> Rep FuzzyTimeOfDay x
from :: forall x. FuzzyTimeOfDay -> Rep FuzzyTimeOfDay x
$cto :: forall x. Rep FuzzyTimeOfDay x -> FuzzyTimeOfDay
to :: forall x. Rep FuzzyTimeOfDay x -> FuzzyTimeOfDay
Generic)

instance Validity FuzzyTimeOfDay where
  validate :: FuzzyTimeOfDay -> Validation
validate FuzzyTimeOfDay
ftod =
    [Validation] -> Validation
forall a. Monoid a => [a] -> a
mconcat
      [ FuzzyTimeOfDay -> Validation
forall a. (Generic a, GValidity (Rep a)) => a -> Validation
genericValidate FuzzyTimeOfDay
ftod,
        case FuzzyTimeOfDay
ftod of
          AtHour Int
h ->
            [Validation] -> Validation
forall a. Monoid a => [a] -> a
mconcat
              [ String -> Bool -> Validation
declare String
"The hour is positive" (Bool -> Validation) -> Bool -> Validation
forall a b. (a -> b) -> a -> b
$ Int
h Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
0,
                String -> Bool -> Validation
declare String
"The hours are fewer than 24" (Bool -> Validation) -> Bool -> Validation
forall a b. (a -> b) -> a -> b
$ Int
h Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
24
              ]
          AtMinute Int
h Int
m ->
            [Validation] -> Validation
forall a. Monoid a => [a] -> a
mconcat
              [ String -> Bool -> Validation
declare String
"The hour is positive" (Bool -> Validation) -> Bool -> Validation
forall a b. (a -> b) -> a -> b
$ Int
h Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
0,
                String -> Bool -> Validation
declare String
"The hours are fewer than 24" (Bool -> Validation) -> Bool -> Validation
forall a b. (a -> b) -> a -> b
$ Int
h Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
24,
                String -> Bool -> Validation
declare String
"The minute is positive" (Bool -> Validation) -> Bool -> Validation
forall a b. (a -> b) -> a -> b
$ Int
m Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
0,
                String -> Bool -> Validation
declare String
"The minutes are fewer than 60" (Bool -> Validation) -> Bool -> Validation
forall a b. (a -> b) -> a -> b
$ Int
m Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
60
              ]
          HoursDiff Int
hs ->
            [Validation] -> Validation
forall a. Monoid a => [a] -> a
mconcat
              [String -> Bool -> Validation
declare String
"The hours difference is no less than 24h" (Bool -> Validation) -> Bool -> Validation
forall a b. (a -> b) -> a -> b
$ Int -> Int
forall a. Num a => a -> a
abs Int
hs Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
24]
          MinutesDiff Int
ms ->
            [Validation] -> Validation
forall a. Monoid a => [a] -> a
mconcat
              [ String -> Bool -> Validation
declare String
"The minutes difference is no less than 1440m" (Bool -> Validation) -> Bool -> Validation
forall a b. (a -> b) -> a -> b
$
                  Int -> Int
forall a. Num a => a -> a
abs Int
ms Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
24 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
60
              ]
          SecondsDiff Pico
ms ->
            [Validation] -> Validation
forall a. Monoid a => [a] -> a
mconcat
              [ String -> Bool -> Validation
declare String
"The seconds difference is no less than 86400s" (Bool -> Validation) -> Bool -> Validation
forall a b. (a -> b) -> a -> b
$
                  Pico -> Pico
forall a. Num a => a -> a
abs Pico
ms Pico -> Pico -> Bool
forall a. Ord a => a -> a -> Bool
< Pico
24 Pico -> Pico -> Pico
forall a. Num a => a -> a -> a
* Pico
60 Pico -> Pico -> Pico
forall a. Num a => a -> a -> a
* Pico
60
              ]
          FuzzyTimeOfDay
_ -> Validation
valid
      ]

instance NFData FuzzyTimeOfDay

data FuzzyDay
  = Yesterday
  | Now
  | Today
  | Tomorrow
  | OnlyDay !Word8
  | DayInMonth !Word8 !Word8
  | DiffDays !Int16
  | DiffWeeks !Int16
  | DiffMonths !Int16
  | DayOfTheWeek !DayOfWeek !Int16 -- Extra diff weeks
  | ExactDay !Day
  deriving (Int -> FuzzyDay -> ShowS
[FuzzyDay] -> ShowS
FuzzyDay -> String
(Int -> FuzzyDay -> ShowS)
-> (FuzzyDay -> String) -> ([FuzzyDay] -> ShowS) -> Show FuzzyDay
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> FuzzyDay -> ShowS
showsPrec :: Int -> FuzzyDay -> ShowS
$cshow :: FuzzyDay -> String
show :: FuzzyDay -> String
$cshowList :: [FuzzyDay] -> ShowS
showList :: [FuzzyDay] -> ShowS
Show, FuzzyDay -> FuzzyDay -> Bool
(FuzzyDay -> FuzzyDay -> Bool)
-> (FuzzyDay -> FuzzyDay -> Bool) -> Eq FuzzyDay
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: FuzzyDay -> FuzzyDay -> Bool
== :: FuzzyDay -> FuzzyDay -> Bool
$c/= :: FuzzyDay -> FuzzyDay -> Bool
/= :: FuzzyDay -> FuzzyDay -> Bool
Eq, (forall x. FuzzyDay -> Rep FuzzyDay x)
-> (forall x. Rep FuzzyDay x -> FuzzyDay) -> Generic FuzzyDay
forall x. Rep FuzzyDay x -> FuzzyDay
forall x. FuzzyDay -> Rep FuzzyDay x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. FuzzyDay -> Rep FuzzyDay x
from :: forall x. FuzzyDay -> Rep FuzzyDay x
$cto :: forall x. Rep FuzzyDay x -> FuzzyDay
to :: forall x. Rep FuzzyDay x -> FuzzyDay
Generic)

instance Validity FuzzyDay where
  validate :: FuzzyDay -> Validation
validate FuzzyDay
fd =
    [Validation] -> Validation
forall a. Monoid a => [a] -> a
mconcat
      [ FuzzyDay -> Validation
forall a. (Generic a, GValidity (Rep a)) => a -> Validation
genericValidate FuzzyDay
fd,
        case FuzzyDay
fd of
          OnlyDay Word8
di ->
            String -> Validation -> Validation
decorate String
"OnlyDay" (Validation -> Validation) -> Validation -> Validation
forall a b. (a -> b) -> a -> b
$
              [Validation] -> Validation
forall a. Monoid a => [a] -> a
mconcat
                [ String -> Bool -> Validation
declare String
"The day is strictly positive" (Bool -> Validation) -> Bool -> Validation
forall a b. (a -> b) -> a -> b
$ Word8
di Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
>= Word8
1,
                  String -> Bool -> Validation
declare String
"The day is less than or equal to 31" (Bool -> Validation) -> Bool -> Validation
forall a b. (a -> b) -> a -> b
$ Word8
di Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
31
                ]
          DayInMonth Word8
mi Word8
di ->
            String -> Validation -> Validation
decorate String
"DayInMonth" (Validation -> Validation) -> Validation -> Validation
forall a b. (a -> b) -> a -> b
$
              [Validation] -> Validation
forall a. Monoid a => [a] -> a
mconcat
                [ String -> Bool -> Validation
declare String
"The day is strictly positive" (Bool -> Validation) -> Bool -> Validation
forall a b. (a -> b) -> a -> b
$ Word8
di Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
>= Word8
1,
                  String -> Bool -> Validation
declare String
"The day is less than or equal to 31" (Bool -> Validation) -> Bool -> Validation
forall a b. (a -> b) -> a -> b
$ Word8
di Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
31,
                  String -> Bool -> Validation
declare String
"The month is strictly positive" (Bool -> Validation) -> Bool -> Validation
forall a b. (a -> b) -> a -> b
$ Word8
mi Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
>= Word8
1,
                  String -> Bool -> Validation
declare String
"The month is less than or equal to 12" (Bool -> Validation) -> Bool -> Validation
forall a b. (a -> b) -> a -> b
$ Word8
mi Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
<= Word8
12
                ]
          FuzzyDay
_ -> Validation
valid
      ]

instance NFData FuzzyDay

deriving instance Generic DayOfWeek

#if !MIN_VERSION_time(1,11,1)
instance NFData DayOfWeek
#endif