{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE OverloadedStrings #-}

-- | Provides base types and utility functions needed for modules in Discord.Internal.Types
module Discord.Internal.Types.Prelude where

import Data.Bits
import Data.Word

import Data.Aeson.Types
import Data.Time.Clock
import qualified Data.Text as T
import Data.Time.Clock.POSIX
import Control.Monad (mzero)

import Data.Functor.Compose (Compose(Compose, getCompose))
import Data.Bifunctor (first)

-- | Authorization token for the Discord API
data Auth = Auth T.Text
  deriving (Int -> Auth -> ShowS
[Auth] -> ShowS
Auth -> String
(Int -> Auth -> ShowS)
-> (Auth -> String) -> ([Auth] -> ShowS) -> Show Auth
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Auth] -> ShowS
$cshowList :: [Auth] -> ShowS
show :: Auth -> String
$cshow :: Auth -> String
showsPrec :: Int -> Auth -> ShowS
$cshowsPrec :: Int -> Auth -> ShowS
Show, Auth -> Auth -> Bool
(Auth -> Auth -> Bool) -> (Auth -> Auth -> Bool) -> Eq Auth
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Auth -> Auth -> Bool
$c/= :: Auth -> Auth -> Bool
== :: Auth -> Auth -> Bool
$c== :: Auth -> Auth -> Bool
Eq, Eq Auth
Eq Auth
-> (Auth -> Auth -> Ordering)
-> (Auth -> Auth -> Bool)
-> (Auth -> Auth -> Bool)
-> (Auth -> Auth -> Bool)
-> (Auth -> Auth -> Bool)
-> (Auth -> Auth -> Auth)
-> (Auth -> Auth -> Auth)
-> Ord Auth
Auth -> Auth -> Bool
Auth -> Auth -> Ordering
Auth -> Auth -> Auth
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
min :: Auth -> Auth -> Auth
$cmin :: Auth -> Auth -> Auth
max :: Auth -> Auth -> Auth
$cmax :: Auth -> Auth -> Auth
>= :: Auth -> Auth -> Bool
$c>= :: Auth -> Auth -> Bool
> :: Auth -> Auth -> Bool
$c> :: Auth -> Auth -> Bool
<= :: Auth -> Auth -> Bool
$c<= :: Auth -> Auth -> Bool
< :: Auth -> Auth -> Bool
$c< :: Auth -> Auth -> Bool
compare :: Auth -> Auth -> Ordering
$ccompare :: Auth -> Auth -> Ordering
$cp1Ord :: Eq Auth
Ord)


-- | Get the raw token formatted for use with the websocket gateway
authToken :: Auth -> T.Text
authToken :: Auth -> Text
authToken (Auth Text
tok) = let token :: Text
token = Text -> Text
T.strip Text
tok
                           bot :: Text
bot = if Text
"Bot " Text -> Text -> Bool
`T.isPrefixOf` Text
token then Text
"" else Text
"Bot "
                       in Text
bot Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
token

-- | A unique integer identifier. Can be used to calculate the creation date of an entity.
newtype Snowflake = Snowflake Word64
  deriving (Eq Snowflake
Eq Snowflake
-> (Snowflake -> Snowflake -> Ordering)
-> (Snowflake -> Snowflake -> Bool)
-> (Snowflake -> Snowflake -> Bool)
-> (Snowflake -> Snowflake -> Bool)
-> (Snowflake -> Snowflake -> Bool)
-> (Snowflake -> Snowflake -> Snowflake)
-> (Snowflake -> Snowflake -> Snowflake)
-> Ord Snowflake
Snowflake -> Snowflake -> Bool
Snowflake -> Snowflake -> Ordering
Snowflake -> Snowflake -> Snowflake
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
min :: Snowflake -> Snowflake -> Snowflake
$cmin :: Snowflake -> Snowflake -> Snowflake
max :: Snowflake -> Snowflake -> Snowflake
$cmax :: Snowflake -> Snowflake -> Snowflake
>= :: Snowflake -> Snowflake -> Bool
$c>= :: Snowflake -> Snowflake -> Bool
> :: Snowflake -> Snowflake -> Bool
$c> :: Snowflake -> Snowflake -> Bool
<= :: Snowflake -> Snowflake -> Bool
$c<= :: Snowflake -> Snowflake -> Bool
< :: Snowflake -> Snowflake -> Bool
$c< :: Snowflake -> Snowflake -> Bool
compare :: Snowflake -> Snowflake -> Ordering
$ccompare :: Snowflake -> Snowflake -> Ordering
$cp1Ord :: Eq Snowflake
Ord, Snowflake -> Snowflake -> Bool
(Snowflake -> Snowflake -> Bool)
-> (Snowflake -> Snowflake -> Bool) -> Eq Snowflake
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Snowflake -> Snowflake -> Bool
$c/= :: Snowflake -> Snowflake -> Bool
== :: Snowflake -> Snowflake -> Bool
$c== :: Snowflake -> Snowflake -> Bool
Eq, Integer -> Snowflake
Snowflake -> Snowflake
Snowflake -> Snowflake -> Snowflake
(Snowflake -> Snowflake -> Snowflake)
-> (Snowflake -> Snowflake -> Snowflake)
-> (Snowflake -> Snowflake -> Snowflake)
-> (Snowflake -> Snowflake)
-> (Snowflake -> Snowflake)
-> (Snowflake -> Snowflake)
-> (Integer -> Snowflake)
-> Num Snowflake
forall a.
(a -> a -> a)
-> (a -> a -> a)
-> (a -> a -> a)
-> (a -> a)
-> (a -> a)
-> (a -> a)
-> (Integer -> a)
-> Num a
fromInteger :: Integer -> Snowflake
$cfromInteger :: Integer -> Snowflake
signum :: Snowflake -> Snowflake
$csignum :: Snowflake -> Snowflake
abs :: Snowflake -> Snowflake
$cabs :: Snowflake -> Snowflake
negate :: Snowflake -> Snowflake
$cnegate :: Snowflake -> Snowflake
* :: Snowflake -> Snowflake -> Snowflake
$c* :: Snowflake -> Snowflake -> Snowflake
- :: Snowflake -> Snowflake -> Snowflake
$c- :: Snowflake -> Snowflake -> Snowflake
+ :: Snowflake -> Snowflake -> Snowflake
$c+ :: Snowflake -> Snowflake -> Snowflake
Num, Enum Snowflake
Real Snowflake
Real Snowflake
-> Enum Snowflake
-> (Snowflake -> Snowflake -> Snowflake)
-> (Snowflake -> Snowflake -> Snowflake)
-> (Snowflake -> Snowflake -> Snowflake)
-> (Snowflake -> Snowflake -> Snowflake)
-> (Snowflake -> Snowflake -> (Snowflake, Snowflake))
-> (Snowflake -> Snowflake -> (Snowflake, Snowflake))
-> (Snowflake -> Integer)
-> Integral Snowflake
Snowflake -> Integer
Snowflake -> Snowflake -> (Snowflake, Snowflake)
Snowflake -> Snowflake -> Snowflake
forall a.
Real a
-> Enum a
-> (a -> a -> a)
-> (a -> a -> a)
-> (a -> a -> a)
-> (a -> a -> a)
-> (a -> a -> (a, a))
-> (a -> a -> (a, a))
-> (a -> Integer)
-> Integral a
toInteger :: Snowflake -> Integer
$ctoInteger :: Snowflake -> Integer
divMod :: Snowflake -> Snowflake -> (Snowflake, Snowflake)
$cdivMod :: Snowflake -> Snowflake -> (Snowflake, Snowflake)
quotRem :: Snowflake -> Snowflake -> (Snowflake, Snowflake)
$cquotRem :: Snowflake -> Snowflake -> (Snowflake, Snowflake)
mod :: Snowflake -> Snowflake -> Snowflake
$cmod :: Snowflake -> Snowflake -> Snowflake
div :: Snowflake -> Snowflake -> Snowflake
$cdiv :: Snowflake -> Snowflake -> Snowflake
rem :: Snowflake -> Snowflake -> Snowflake
$crem :: Snowflake -> Snowflake -> Snowflake
quot :: Snowflake -> Snowflake -> Snowflake
$cquot :: Snowflake -> Snowflake -> Snowflake
$cp2Integral :: Enum Snowflake
$cp1Integral :: Real Snowflake
Integral, Int -> Snowflake
Snowflake -> Int
Snowflake -> [Snowflake]
Snowflake -> Snowflake
Snowflake -> Snowflake -> [Snowflake]
Snowflake -> Snowflake -> Snowflake -> [Snowflake]
(Snowflake -> Snowflake)
-> (Snowflake -> Snowflake)
-> (Int -> Snowflake)
-> (Snowflake -> Int)
-> (Snowflake -> [Snowflake])
-> (Snowflake -> Snowflake -> [Snowflake])
-> (Snowflake -> Snowflake -> [Snowflake])
-> (Snowflake -> Snowflake -> Snowflake -> [Snowflake])
-> Enum Snowflake
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
enumFromThenTo :: Snowflake -> Snowflake -> Snowflake -> [Snowflake]
$cenumFromThenTo :: Snowflake -> Snowflake -> Snowflake -> [Snowflake]
enumFromTo :: Snowflake -> Snowflake -> [Snowflake]
$cenumFromTo :: Snowflake -> Snowflake -> [Snowflake]
enumFromThen :: Snowflake -> Snowflake -> [Snowflake]
$cenumFromThen :: Snowflake -> Snowflake -> [Snowflake]
enumFrom :: Snowflake -> [Snowflake]
$cenumFrom :: Snowflake -> [Snowflake]
fromEnum :: Snowflake -> Int
$cfromEnum :: Snowflake -> Int
toEnum :: Int -> Snowflake
$ctoEnum :: Int -> Snowflake
pred :: Snowflake -> Snowflake
$cpred :: Snowflake -> Snowflake
succ :: Snowflake -> Snowflake
$csucc :: Snowflake -> Snowflake
Enum, Num Snowflake
Ord Snowflake
Num Snowflake
-> Ord Snowflake -> (Snowflake -> Rational) -> Real Snowflake
Snowflake -> Rational
forall a. Num a -> Ord a -> (a -> Rational) -> Real a
toRational :: Snowflake -> Rational
$ctoRational :: Snowflake -> Rational
$cp2Real :: Ord Snowflake
$cp1Real :: Num Snowflake
Real, Eq Snowflake
Snowflake
Eq Snowflake
-> (Snowflake -> Snowflake -> Snowflake)
-> (Snowflake -> Snowflake -> Snowflake)
-> (Snowflake -> Snowflake -> Snowflake)
-> (Snowflake -> Snowflake)
-> (Snowflake -> Int -> Snowflake)
-> (Snowflake -> Int -> Snowflake)
-> Snowflake
-> (Int -> Snowflake)
-> (Snowflake -> Int -> Snowflake)
-> (Snowflake -> Int -> Snowflake)
-> (Snowflake -> Int -> Snowflake)
-> (Snowflake -> Int -> Bool)
-> (Snowflake -> Maybe Int)
-> (Snowflake -> Int)
-> (Snowflake -> Bool)
-> (Snowflake -> Int -> Snowflake)
-> (Snowflake -> Int -> Snowflake)
-> (Snowflake -> Int -> Snowflake)
-> (Snowflake -> Int -> Snowflake)
-> (Snowflake -> Int -> Snowflake)
-> (Snowflake -> Int -> Snowflake)
-> (Snowflake -> Int)
-> Bits Snowflake
Int -> Snowflake
Snowflake -> Bool
Snowflake -> Int
Snowflake -> Maybe Int
Snowflake -> Snowflake
Snowflake -> Int -> Bool
Snowflake -> Int -> Snowflake
Snowflake -> Snowflake -> Snowflake
forall a.
Eq a
-> (a -> a -> a)
-> (a -> a -> a)
-> (a -> a -> a)
-> (a -> a)
-> (a -> Int -> a)
-> (a -> Int -> a)
-> a
-> (Int -> a)
-> (a -> Int -> a)
-> (a -> Int -> a)
-> (a -> Int -> a)
-> (a -> Int -> Bool)
-> (a -> Maybe Int)
-> (a -> Int)
-> (a -> Bool)
-> (a -> Int -> a)
-> (a -> Int -> a)
-> (a -> Int -> a)
-> (a -> Int -> a)
-> (a -> Int -> a)
-> (a -> Int -> a)
-> (a -> Int)
-> Bits a
popCount :: Snowflake -> Int
$cpopCount :: Snowflake -> Int
rotateR :: Snowflake -> Int -> Snowflake
$crotateR :: Snowflake -> Int -> Snowflake
rotateL :: Snowflake -> Int -> Snowflake
$crotateL :: Snowflake -> Int -> Snowflake
unsafeShiftR :: Snowflake -> Int -> Snowflake
$cunsafeShiftR :: Snowflake -> Int -> Snowflake
shiftR :: Snowflake -> Int -> Snowflake
$cshiftR :: Snowflake -> Int -> Snowflake
unsafeShiftL :: Snowflake -> Int -> Snowflake
$cunsafeShiftL :: Snowflake -> Int -> Snowflake
shiftL :: Snowflake -> Int -> Snowflake
$cshiftL :: Snowflake -> Int -> Snowflake
isSigned :: Snowflake -> Bool
$cisSigned :: Snowflake -> Bool
bitSize :: Snowflake -> Int
$cbitSize :: Snowflake -> Int
bitSizeMaybe :: Snowflake -> Maybe Int
$cbitSizeMaybe :: Snowflake -> Maybe Int
testBit :: Snowflake -> Int -> Bool
$ctestBit :: Snowflake -> Int -> Bool
complementBit :: Snowflake -> Int -> Snowflake
$ccomplementBit :: Snowflake -> Int -> Snowflake
clearBit :: Snowflake -> Int -> Snowflake
$cclearBit :: Snowflake -> Int -> Snowflake
setBit :: Snowflake -> Int -> Snowflake
$csetBit :: Snowflake -> Int -> Snowflake
bit :: Int -> Snowflake
$cbit :: Int -> Snowflake
zeroBits :: Snowflake
$czeroBits :: Snowflake
rotate :: Snowflake -> Int -> Snowflake
$crotate :: Snowflake -> Int -> Snowflake
shift :: Snowflake -> Int -> Snowflake
$cshift :: Snowflake -> Int -> Snowflake
complement :: Snowflake -> Snowflake
$ccomplement :: Snowflake -> Snowflake
xor :: Snowflake -> Snowflake -> Snowflake
$cxor :: Snowflake -> Snowflake -> Snowflake
.|. :: Snowflake -> Snowflake -> Snowflake
$c.|. :: Snowflake -> Snowflake -> Snowflake
.&. :: Snowflake -> Snowflake -> Snowflake
$c.&. :: Snowflake -> Snowflake -> Snowflake
$cp1Bits :: Eq Snowflake
Bits)

instance Show Snowflake where
  show :: Snowflake -> String
show (Snowflake Word64
a) = Word64 -> String
forall a. Show a => a -> String
show Word64
a

instance Read Snowflake where
  readsPrec :: Int -> ReadS Snowflake
readsPrec Int
p = Compose ((->) String) [] (Snowflake, String) -> ReadS Snowflake
forall k1 (f :: k1 -> *) k2 (g :: k2 -> k1) (a :: k2).
Compose f g a -> f (g a)
getCompose (Compose ((->) String) [] (Snowflake, String) -> ReadS Snowflake)
-> Compose ((->) String) [] (Snowflake, String) -> ReadS Snowflake
forall a b. (a -> b) -> a -> b
$ (Word64 -> Snowflake) -> (Word64, String) -> (Snowflake, String)
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first Word64 -> Snowflake
Snowflake ((Word64, String) -> (Snowflake, String))
-> Compose ((->) String) [] (Word64, String)
-> Compose ((->) String) [] (Snowflake, String)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (String -> [(Word64, String)])
-> Compose ((->) String) [] (Word64, String)
forall k k1 (f :: k -> *) (g :: k1 -> k) (a :: k1).
f (g a) -> Compose f g a
Compose (Int -> String -> [(Word64, String)]
forall a. Read a => Int -> ReadS a
readsPrec Int
p)

instance ToJSON Snowflake where
  toJSON :: Snowflake -> Value
toJSON (Snowflake Word64
snowflake) = Text -> Value
String (Text -> Value) -> (String -> Text) -> String -> Value
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
T.pack (String -> Value) -> String -> Value
forall a b. (a -> b) -> a -> b
$ Word64 -> String
forall a. Show a => a -> String
show Word64
snowflake

instance FromJSON Snowflake where
  parseJSON :: Value -> Parser Snowflake
parseJSON (String Text
snowflake) = Snowflake -> Parser Snowflake
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Snowflake -> Parser Snowflake)
-> (String -> Snowflake) -> String -> Parser Snowflake
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Snowflake
forall a. Read a => String -> a
read (String -> Parser Snowflake) -> String -> Parser Snowflake
forall a b. (a -> b) -> a -> b
$ Text -> String
T.unpack Text
snowflake
  parseJSON Value
_ = Parser Snowflake
forall (m :: * -> *) a. MonadPlus m => m a
mzero

type ChannelId = Snowflake
type GuildId = Snowflake
type MessageId = Snowflake
type EmojiId = Snowflake
type UserId = Snowflake
type OverwriteId = Snowflake
type RoleId = Snowflake
type IntegrationId = Snowflake
type WebhookId = Snowflake
type ParentId = Snowflake

-- | Gets a creation date from a snowflake.
snowflakeCreationDate :: Snowflake -> UTCTime
snowflakeCreationDate :: Snowflake -> UTCTime
snowflakeCreationDate Snowflake
x = POSIXTime -> UTCTime
posixSecondsToUTCTime (POSIXTime -> UTCTime)
-> (Snowflake -> POSIXTime) -> Snowflake -> UTCTime
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Snowflake -> POSIXTime
forall a b. (Real a, Fractional b) => a -> b
realToFrac
  (Snowflake -> UTCTime) -> Snowflake -> UTCTime
forall a b. (a -> b) -> a -> b
$ Snowflake
1420070400 Snowflake -> Snowflake -> Snowflake
forall a. Num a => a -> a -> a
+ Snowflake -> Snowflake -> Snowflake
forall a. Integral a => a -> a -> a
quot (Snowflake -> Int -> Snowflake
forall a. Bits a => a -> Int -> a
shiftR Snowflake
x Int
22) Snowflake
1000

-- | Default timestamp
epochTime :: UTCTime
epochTime :: UTCTime
epochTime = POSIXTime -> UTCTime
posixSecondsToUTCTime POSIXTime
0