{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE Safe #-}
{-# LANGUAGE TypeApplications #-}

-- |
-- Module      : Data.Char.Emoji.Clock
-- Description : A module that defines emoji that display a clock.
-- Maintainer  : hapytexeu+gh@gmail.com
-- Stability   : experimental
-- Portability : POSIX
--
-- The emoji have 24 clock emoji, each time with 30 minutes difference.
module Data.Char.Emoji.Clock
  ( -- * Clock emoji
    Clock,
    hours,
    minutes30,
    clock,
    closestClock,
  )
where

import Control.DeepSeq (NFData)
import Data.Bits (shiftL, shiftR, (.|.))
import Data.Bool (bool)
import Data.Char (chr, ord)
import Data.Char.Core (UnicodeCharacter (fromUnicodeChar, isInCharRange, toUnicodeChar), UnicodeText (isInTextRange), generateIsInTextRange')
import Data.Data (Data)
import Data.Hashable (Hashable)
import GHC.Enum (toEnumError)
import GHC.Generics (Generic)
import Test.QuickCheck.Arbitrary (Arbitrary (arbitrary), arbitraryBoundedEnum)

-- | A 'Clock' object that can be converted to a unicode character that displays
-- a clock with the given time. The 'Clock' has an 'hours' field that contains
-- the given hours between 0 and 12, and a 'minutes30' field that if 'True',
-- means that the clock is half past that hour.
data Clock = Clock
  { -- | The number of hours on the given clock. Is between 0 and 12. For 0, the 'minutes30' is 'True'; and for 12, the 'minutes30' is 'False'.
    Clock -> Int
hours :: Int,
    -- | Is 'True' if it is half past the given hour on the 'Clock'.
    Clock -> Bool
minutes30 :: Bool
  }
  deriving (Typeable Clock
Typeable Clock
-> (forall (c :: * -> *).
    (forall d b. Data d => c (d -> b) -> d -> c b)
    -> (forall g. g -> c g) -> Clock -> c Clock)
-> (forall (c :: * -> *).
    (forall b r. Data b => c (b -> r) -> c r)
    -> (forall r. r -> c r) -> Constr -> c Clock)
-> (Clock -> Constr)
-> (Clock -> DataType)
-> (forall (t :: * -> *) (c :: * -> *).
    Typeable t =>
    (forall d. Data d => c (t d)) -> Maybe (c Clock))
-> (forall (t :: * -> * -> *) (c :: * -> *).
    Typeable t =>
    (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c Clock))
-> ((forall b. Data b => b -> b) -> Clock -> Clock)
-> (forall r r'.
    (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> Clock -> r)
-> (forall r r'.
    (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> Clock -> r)
-> (forall u. (forall d. Data d => d -> u) -> Clock -> [u])
-> (forall u. Int -> (forall d. Data d => d -> u) -> Clock -> u)
-> (forall (m :: * -> *).
    Monad m =>
    (forall d. Data d => d -> m d) -> Clock -> m Clock)
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> Clock -> m Clock)
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> Clock -> m Clock)
-> Data Clock
Clock -> Constr
Clock -> DataType
(forall b. Data b => b -> b) -> Clock -> Clock
forall a.
Typeable a
-> (forall (c :: * -> *).
    (forall d b. Data d => c (d -> b) -> d -> c b)
    -> (forall g. g -> c g) -> a -> c a)
-> (forall (c :: * -> *).
    (forall b r. Data b => c (b -> r) -> c r)
    -> (forall r. r -> c r) -> Constr -> c a)
-> (a -> Constr)
-> (a -> DataType)
-> (forall (t :: * -> *) (c :: * -> *).
    Typeable t =>
    (forall d. Data d => c (t d)) -> Maybe (c a))
-> (forall (t :: * -> * -> *) (c :: * -> *).
    Typeable t =>
    (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c a))
-> ((forall b. Data b => b -> b) -> a -> a)
-> (forall r r'.
    (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> a -> r)
-> (forall r r'.
    (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> a -> r)
-> (forall u. (forall d. Data d => d -> u) -> a -> [u])
-> (forall u. Int -> (forall d. Data d => d -> u) -> a -> u)
-> (forall (m :: * -> *).
    Monad m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> Data a
forall u. Int -> (forall d. Data d => d -> u) -> Clock -> u
forall u. (forall d. Data d => d -> u) -> Clock -> [u]
forall r r'.
(r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> Clock -> r
forall r r'.
(r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> Clock -> r
forall (m :: * -> *).
Monad m =>
(forall d. Data d => d -> m d) -> Clock -> m Clock
forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> Clock -> m Clock
forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c Clock
forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> Clock -> c Clock
forall (t :: * -> *) (c :: * -> *).
Typeable t =>
(forall d. Data d => c (t d)) -> Maybe (c Clock)
forall (t :: * -> * -> *) (c :: * -> *).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c Clock)
$cgfoldl :: forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> Clock -> c Clock
gfoldl :: forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> Clock -> c Clock
$cgunfold :: forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c Clock
gunfold :: forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c Clock
$ctoConstr :: Clock -> Constr
toConstr :: Clock -> Constr
$cdataTypeOf :: Clock -> DataType
dataTypeOf :: Clock -> DataType
$cdataCast1 :: forall (t :: * -> *) (c :: * -> *).
Typeable t =>
(forall d. Data d => c (t d)) -> Maybe (c Clock)
dataCast1 :: forall (t :: * -> *) (c :: * -> *).
Typeable t =>
(forall d. Data d => c (t d)) -> Maybe (c Clock)
$cdataCast2 :: forall (t :: * -> * -> *) (c :: * -> *).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c Clock)
dataCast2 :: forall (t :: * -> * -> *) (c :: * -> *).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c Clock)
$cgmapT :: (forall b. Data b => b -> b) -> Clock -> Clock
gmapT :: (forall b. Data b => b -> b) -> Clock -> Clock
$cgmapQl :: forall r r'.
(r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> Clock -> r
gmapQl :: forall r r'.
(r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> Clock -> r
$cgmapQr :: forall r r'.
(r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> Clock -> r
gmapQr :: forall r r'.
(r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> Clock -> r
$cgmapQ :: forall u. (forall d. Data d => d -> u) -> Clock -> [u]
gmapQ :: forall u. (forall d. Data d => d -> u) -> Clock -> [u]
$cgmapQi :: forall u. Int -> (forall d. Data d => d -> u) -> Clock -> u
gmapQi :: forall u. Int -> (forall d. Data d => d -> u) -> Clock -> u
$cgmapM :: forall (m :: * -> *).
Monad m =>
(forall d. Data d => d -> m d) -> Clock -> m Clock
gmapM :: forall (m :: * -> *).
Monad m =>
(forall d. Data d => d -> m d) -> Clock -> m Clock
$cgmapMp :: forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> Clock -> m Clock
gmapMp :: forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> Clock -> m Clock
$cgmapMo :: forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> Clock -> m Clock
gmapMo :: forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> Clock -> m Clock
Data, Clock -> Clock -> Bool
(Clock -> Clock -> Bool) -> (Clock -> Clock -> Bool) -> Eq Clock
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Clock -> Clock -> Bool
== :: Clock -> Clock -> Bool
$c/= :: Clock -> Clock -> Bool
/= :: Clock -> Clock -> Bool
Eq, (forall x. Clock -> Rep Clock x)
-> (forall x. Rep Clock x -> Clock) -> Generic Clock
forall x. Rep Clock x -> Clock
forall x. Clock -> Rep Clock x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. Clock -> Rep Clock x
from :: forall x. Clock -> Rep Clock x
$cto :: forall x. Rep Clock x -> Clock
to :: forall x. Rep Clock x -> Clock
Generic, Eq Clock
Eq Clock
-> (Clock -> Clock -> Ordering)
-> (Clock -> Clock -> Bool)
-> (Clock -> Clock -> Bool)
-> (Clock -> Clock -> Bool)
-> (Clock -> Clock -> Bool)
-> (Clock -> Clock -> Clock)
-> (Clock -> Clock -> Clock)
-> Ord Clock
Clock -> Clock -> Bool
Clock -> Clock -> Ordering
Clock -> Clock -> Clock
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: Clock -> Clock -> Ordering
compare :: Clock -> Clock -> Ordering
$c< :: Clock -> Clock -> Bool
< :: Clock -> Clock -> Bool
$c<= :: Clock -> Clock -> Bool
<= :: Clock -> Clock -> Bool
$c> :: Clock -> Clock -> Bool
> :: Clock -> Clock -> Bool
$c>= :: Clock -> Clock -> Bool
>= :: Clock -> Clock -> Bool
$cmax :: Clock -> Clock -> Clock
max :: Clock -> Clock -> Clock
$cmin :: Clock -> Clock -> Clock
min :: Clock -> Clock -> Clock
Ord, ReadPrec [Clock]
ReadPrec Clock
Int -> ReadS Clock
ReadS [Clock]
(Int -> ReadS Clock)
-> ReadS [Clock]
-> ReadPrec Clock
-> ReadPrec [Clock]
-> Read Clock
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
$creadsPrec :: Int -> ReadS Clock
readsPrec :: Int -> ReadS Clock
$creadList :: ReadS [Clock]
readList :: ReadS [Clock]
$creadPrec :: ReadPrec Clock
readPrec :: ReadPrec Clock
$creadListPrec :: ReadPrec [Clock]
readListPrec :: ReadPrec [Clock]
Read, Int -> Clock -> ShowS
[Clock] -> ShowS
Clock -> String
(Int -> Clock -> ShowS)
-> (Clock -> String) -> ([Clock] -> ShowS) -> Show Clock
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Clock -> ShowS
showsPrec :: Int -> Clock -> ShowS
$cshow :: Clock -> String
show :: Clock -> String
$cshowList :: [Clock] -> ShowS
showList :: [Clock] -> ShowS
Show)

instance Hashable Clock

instance NFData Clock

instance Bounded Clock where
  minBound :: Clock
minBound = Int -> Bool -> Clock
Clock Int
0 Bool
True
  maxBound :: Clock
maxBound = Int -> Bool -> Clock
Clock Int
12 Bool
False

instance Enum Clock where
  fromEnum :: Clock -> Int
fromEnum (Clock Int
h Bool
m30) = Int -> Int
forall a. Enum a => a -> a
pred (Int -> Int -> Int
forall a. Bits a => a -> Int -> a
shiftL Int
h Int
1 Int -> Int -> Int
forall a. Bits a => a -> a -> a
.|. Int -> Int -> Bool -> Int
forall a. a -> a -> Bool -> a
bool Int
0 Int
1 Bool
m30)
  toEnum :: Int -> Clock
toEnum Int
hm30
    | Int
hm30 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
0 Bool -> Bool -> Bool
|| Int
hm30 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
23 = String -> Int -> (Clock, Clock) -> Clock
forall a b. Show a => String -> Int -> (a, a) -> b
toEnumError String
"Clock" Int
hm30 (Clock
forall a. Bounded a => a
minBound :: Clock, Clock
forall a. Bounded a => a
maxBound)
    | Bool
otherwise = Int -> Bool -> Clock
Clock (Int -> Int -> Int
forall a. Bits a => a -> Int -> a
shiftR Int
hm30' Int
1) (Int -> Bool
forall a. Integral a => a -> Bool
odd Int
hm30')
    where
      hm30' :: Int
hm30' = Int -> Int
forall a. Enum a => a -> a
succ Int
hm30
  enumFrom :: Clock -> [Clock]
enumFrom = (Clock -> Clock -> [Clock]
forall a. Enum a => a -> a -> [a]
`enumFromTo` Clock
forall a. Bounded a => a
maxBound)
  enumFromThen :: Clock -> Clock -> [Clock]
enumFromThen Clock
x Clock
y = Clock -> Clock -> Clock -> [Clock]
forall a. Enum a => a -> a -> a -> [a]
enumFromThenTo Clock
x Clock
y Clock
forall a. Bounded a => a
maxBound

-- | Generate the 'Clock' object that is the closest to the given hours and
-- minutes.
closestClock ::
  -- | The number of hours.
  Int ->
  -- | The number of minutes, must be between 0 and 60.
  Int ->
  -- | The clock object that is the closest to the given hours and minutes.
  Clock
closestClock :: Int -> Int -> Clock
closestClock Int
h Int
m
  | Int
m Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
15 = Int -> Bool -> Clock
clock Int
h Bool
False
  | Int
m Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
45 = Int -> Bool -> Clock
clock Int
h Bool
True
  | Bool
otherwise = Int -> Bool -> Clock
clock (Int
h Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) Bool
False

-- | Construct a 'Clock' object with the given number of hours, and a 'Bool'ean
-- that indicates if it is half past that hour.
-- The function will ensure that the hours are between 0 and 12 (both inclusive).
-- For half past 12, we use half past 0, for 12 hours, we use simply 12.
clock ::
  -- | The given hour of the clock, can be any value, but will be set between 1 and 12.
  Int ->
  -- | A 'Bool'ean that indicates if it is half past that hour, so 'True' means we add 30 minutes.
  Bool ->
  -- | A clock object that represents the time that is passed through an hour and .
  Clock
clock :: Int -> Bool -> Clock
clock Int
h Bool
b
  | Bool
b Bool -> Bool -> Bool
&& Int
h' Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
12 = Int -> Bool -> Clock
Clock Int
0 Bool
True
  | Bool
otherwise = Int -> Bool -> Clock
Clock Int
h' Bool
b
  where
    h' :: Int
h' = Int -> Int -> Int
forall a. Integral a => a -> a -> a
mod (Int
h Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) Int
12 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1

instance Arbitrary Clock where
  arbitrary :: Gen Clock
arbitrary = Gen Clock
forall a. (Bounded a, Enum a) => Gen a
arbitraryBoundedEnum

instance UnicodeCharacter Clock where
  toUnicodeChar :: Clock -> Char
toUnicodeChar (Clock Int
h Bool
False) = Int -> Char
chr (Int
0x1f54f Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
h)
  toUnicodeChar (Clock Int
h Bool
True) = Int -> Char
chr (Int
0x1f55c Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int -> Int -> Int
forall a. Integral a => a -> a -> a
mod (Int
h Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) Int
12)
  fromUnicodeChar :: Char -> Maybe Clock
fromUnicodeChar Char
c
    | Char
c Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
< Char
'\x1f550' = Maybe Clock
forall a. Maybe a
Nothing
    | Char
c Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
< Char
'\x1f55c' = Clock -> Maybe Clock
forall a. a -> Maybe a
Just (Int -> Bool -> Clock
Clock (Char -> Int
ord Char
c Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
0x1f54f) Bool
False)
    | Char
c Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
< Char
'\x1f568' = Clock -> Maybe Clock
forall a. a -> Maybe a
Just (Int -> Bool -> Clock
Clock (Int -> Int -> Int
forall a. Integral a => a -> a -> a
mod (Char -> Int
ord Char
c Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
0x1f55b) Int
12) Bool
True)
    | Bool
otherwise = Maybe Clock
forall a. Maybe a
Nothing
  isInCharRange :: Char -> Bool
isInCharRange Char
c = Char
'\x1f550' Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
c Bool -> Bool -> Bool
&& Char
c Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
'\x1f567'

instance UnicodeText Clock where
  isInTextRange :: Text -> Bool
isInTextRange = forall a. UnicodeCharacter a => Text -> Bool
generateIsInTextRange' @Clock