\begin{code}
{-# LANGUAGE DeriveGeneric     #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards   #-}
{-# LANGUAGE StrictData        #-}
module Network.Tox.SaveData.Friend where

import           Data.Binary               (Binary (..))
import qualified Data.Binary.Get           as Get
import qualified Data.Binary.Put           as Put
import qualified Data.ByteString           as BS
import           Data.MessagePack          (MessagePack)
import           Data.Word                 (Word32, Word64, Word8)
import           GHC.Generics              (Generic)
import           Network.Tox.Crypto.Key    (PublicKey)
import           Test.QuickCheck.Arbitrary (Arbitrary, arbitrary)
\end{code}

Friend:

The integers in this structure are stored in Big Endian format.

\begin{tabular}{l|l}
  Length        & Contents \\
  \hline
  \texttt{1}    & \texttt{uint8\_t} Status \\
  \texttt{32}   & Long term public key \\
  \texttt{1024} & Friend request message as a byte string \\
  \texttt{1}    & PADDING \\
  \texttt{2}    & \texttt{uint16\_t} Size of the friend request message \\
  \texttt{128}  & Name as a byte string \\
  \texttt{2}    & \texttt{uint16\_t} Size of the name \\
  \texttt{1007} & Status message as a byte string \\
  \texttt{1}    & PADDING \\
  \texttt{2}    & \texttt{uint16\_t} Size of the status message \\
  \texttt{1}    & \texttt{uint8\_t} User status (see also: \texttt{USERSTATUS}) \\
  \texttt{3}    & PADDING \\
  \texttt{4}    & \texttt{uint32\_t} Nospam (only used for sending a friend request) \\
  \texttt{8}    & \texttt{uint64\_t} Last seen time \\
\end{tabular}

Status can be one of:

\begin{tabular}{l|l}
  Status & Meaning \\
  \hline
  0      & Not a friend \\
  1      & Friend added \\
  2      & Friend request sent \\
  3      & Confirmed friend \\
  4      & Friend online \\
\end{tabular}

\begin{code}

data Friend = Friend
    { Friend -> Word8
status        :: Word8
    , Friend -> PublicKey
publicKey     :: PublicKey
    , Friend -> ByteString
friendRequest :: BS.ByteString
    , Friend -> ByteString
name          :: BS.ByteString
    , Friend -> ByteString
statusMessage :: BS.ByteString
    , Friend -> Word8
userStatus    :: Word8
    , Friend -> Word32
nospam        :: Word32
    , Friend -> Word64
lastSeenTime  :: Word64
    }
    deriving (Friend -> Friend -> Bool
(Friend -> Friend -> Bool)
-> (Friend -> Friend -> Bool) -> Eq Friend
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Friend -> Friend -> Bool
$c/= :: Friend -> Friend -> Bool
== :: Friend -> Friend -> Bool
$c== :: Friend -> Friend -> Bool
Eq, Int -> Friend -> ShowS
[Friend] -> ShowS
Friend -> String
(Int -> Friend -> ShowS)
-> (Friend -> String) -> ([Friend] -> ShowS) -> Show Friend
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Friend] -> ShowS
$cshowList :: [Friend] -> ShowS
show :: Friend -> String
$cshow :: Friend -> String
showsPrec :: Int -> Friend -> ShowS
$cshowsPrec :: Int -> Friend -> ShowS
Show, ReadPrec [Friend]
ReadPrec Friend
Int -> ReadS Friend
ReadS [Friend]
(Int -> ReadS Friend)
-> ReadS [Friend]
-> ReadPrec Friend
-> ReadPrec [Friend]
-> Read Friend
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [Friend]
$creadListPrec :: ReadPrec [Friend]
readPrec :: ReadPrec Friend
$creadPrec :: ReadPrec Friend
readList :: ReadS [Friend]
$creadList :: ReadS [Friend]
readsPrec :: Int -> ReadS Friend
$creadsPrec :: Int -> ReadS Friend
Read, (forall x. Friend -> Rep Friend x)
-> (forall x. Rep Friend x -> Friend) -> Generic Friend
forall x. Rep Friend x -> Friend
forall x. Friend -> Rep Friend x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep Friend x -> Friend
$cfrom :: forall x. Friend -> Rep Friend x
Generic)

instance MessagePack Friend

maxFriendRequestLen :: Int
maxFriendRequestLen :: Int
maxFriendRequestLen = Int
1024

maxNameLen :: Int
maxNameLen :: Int
maxNameLen = Int
128

maxStatusMessageLen :: Int
maxStatusMessageLen :: Int
maxStatusMessageLen = Int
1007

instance Binary Friend where
    get :: Get Friend
get = do
        Word8
status           <- Get Word8
Get.getWord8
        PublicKey
publicKey        <- Get PublicKey
forall t. Binary t => Get t
get
        ByteString
friendRequest'   <- Int -> Get ByteString
Get.getByteString Int
maxFriendRequestLen
        Word8
_                <- Get Word8
Get.getWord8
        Word16
friendRequestLen <- Get Word16
Get.getWord16be
        ByteString
name'            <- Int -> Get ByteString
Get.getByteString Int
maxNameLen
        Word16
nameLen          <- Get Word16
Get.getWord16be
        ByteString
statusMessage'   <- Int -> Get ByteString
Get.getByteString Int
maxStatusMessageLen
        Word8
_                <- Get Word8
Get.getWord8
        Word16
statusMessageLen <- Get Word16
Get.getWord16be
        Word8
userStatus       <- Get Word8
Get.getWord8
        ByteString
_                <- Int -> Get ByteString
Get.getByteString Int
3
        Word32
nospam           <- Get Word32
Get.getWord32be
        Word64
lastSeenTime     <- Get Word64
Get.getWord64be

        let friendRequest :: ByteString
friendRequest = Int -> ByteString -> ByteString
BS.take (Word16 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word16
friendRequestLen) ByteString
friendRequest'
        let name :: ByteString
name = Int -> ByteString -> ByteString
BS.take (Word16 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word16
nameLen) ByteString
name'
        let statusMessage :: ByteString
statusMessage = Int -> ByteString -> ByteString
BS.take (Word16 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word16
statusMessageLen) ByteString
statusMessage'

        Friend -> Get Friend
forall (m :: * -> *) a. Monad m => a -> m a
return Friend :: Word8
-> PublicKey
-> ByteString
-> ByteString
-> ByteString
-> Word8
-> Word32
-> Word64
-> Friend
Friend{Word8
Word32
Word64
ByteString
PublicKey
statusMessage :: ByteString
name :: ByteString
friendRequest :: ByteString
lastSeenTime :: Word64
nospam :: Word32
userStatus :: Word8
publicKey :: PublicKey
status :: Word8
lastSeenTime :: Word64
nospam :: Word32
userStatus :: Word8
statusMessage :: ByteString
name :: ByteString
friendRequest :: ByteString
publicKey :: PublicKey
status :: Word8
..}

    put :: Friend -> Put
put Friend {Word8
Word32
Word64
ByteString
PublicKey
lastSeenTime :: Word64
nospam :: Word32
userStatus :: Word8
statusMessage :: ByteString
name :: ByteString
friendRequest :: ByteString
publicKey :: PublicKey
status :: Word8
lastSeenTime :: Friend -> Word64
nospam :: Friend -> Word32
userStatus :: Friend -> Word8
statusMessage :: Friend -> ByteString
name :: Friend -> ByteString
friendRequest :: Friend -> ByteString
publicKey :: Friend -> PublicKey
status :: Friend -> Word8
..} = do
        let friendRequestLen :: Int
friendRequestLen = ByteString -> Int
BS.length ByteString
friendRequest
        let friendRequest' :: ByteString
friendRequest' = ByteString
friendRequest
                ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> Int -> Word8 -> ByteString
BS.replicate (Int
maxFriendRequestLen Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
friendRequestLen) Word8
0

        let nameLen :: Int
nameLen = ByteString -> Int
BS.length ByteString
name
        let name' :: ByteString
name' = ByteString
name
                ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> Int -> Word8 -> ByteString
BS.replicate (Int
maxNameLen Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
nameLen) Word8
0

        let statusMessageLen :: Int
statusMessageLen = ByteString -> Int
BS.length ByteString
statusMessage
        let statusMessage' :: ByteString
statusMessage' = ByteString
statusMessage
                ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> Int -> Word8 -> ByteString
BS.replicate (Int
maxStatusMessageLen Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
statusMessageLen) Word8
0

        Word8 -> Put
Put.putWord8            Word8
status
        PublicKey -> Put
forall t. Binary t => t -> Put
put                     PublicKey
publicKey
        ByteString -> Put
Put.putByteString       ByteString
friendRequest'
        Word8 -> Put
Put.putWord8            Word8
0
        Word16 -> Put
Put.putWord16be         (Int -> Word16
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
friendRequestLen)
        ByteString -> Put
Put.putByteString       ByteString
name'
        Word16 -> Put
Put.putWord16be         (Int -> Word16
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
nameLen)
        ByteString -> Put
Put.putByteString       ByteString
statusMessage'
        Word8 -> Put
Put.putWord8            Word8
0
        Word16 -> Put
Put.putWord16be         (Int -> Word16
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
statusMessageLen)
        Word8 -> Put
Put.putWord8            Word8
userStatus
        ByteString -> Put
Put.putByteString       ByteString
"\0\0\0"
        Word32 -> Put
Put.putWord32be         Word32
nospam
        Word64 -> Put
Put.putWord64be         Word64
lastSeenTime

instance Arbitrary Friend where
    arbitrary :: Gen Friend
arbitrary = Word8
-> PublicKey
-> ByteString
-> ByteString
-> ByteString
-> Word8
-> Word32
-> Word64
-> Friend
Friend
        (Word8
 -> PublicKey
 -> ByteString
 -> ByteString
 -> ByteString
 -> Word8
 -> Word32
 -> Word64
 -> Friend)
-> Gen Word8
-> Gen
     (PublicKey
      -> ByteString
      -> ByteString
      -> ByteString
      -> Word8
      -> Word32
      -> Word64
      -> Friend)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Gen Word8
forall a. Arbitrary a => Gen a
arbitrary
        Gen
  (PublicKey
   -> ByteString
   -> ByteString
   -> ByteString
   -> Word8
   -> Word32
   -> Word64
   -> Friend)
-> Gen PublicKey
-> Gen
     (ByteString
      -> ByteString -> ByteString -> Word8 -> Word32 -> Word64 -> Friend)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Gen PublicKey
forall a. Arbitrary a => Gen a
arbitrary
        Gen
  (ByteString
   -> ByteString -> ByteString -> Word8 -> Word32 -> Word64 -> Friend)
-> Gen ByteString
-> Gen
     (ByteString -> ByteString -> Word8 -> Word32 -> Word64 -> Friend)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> ([Word8] -> ByteString
BS.pack ([Word8] -> ByteString)
-> ([Word8] -> [Word8]) -> [Word8] -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> [Word8] -> [Word8]
forall a. Int -> [a] -> [a]
take Int
maxFriendRequestLen ([Word8] -> ByteString) -> Gen [Word8] -> Gen ByteString
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Gen [Word8]
forall a. Arbitrary a => Gen a
arbitrary)
        Gen
  (ByteString -> ByteString -> Word8 -> Word32 -> Word64 -> Friend)
-> Gen ByteString
-> Gen (ByteString -> Word8 -> Word32 -> Word64 -> Friend)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> ([Word8] -> ByteString
BS.pack ([Word8] -> ByteString)
-> ([Word8] -> [Word8]) -> [Word8] -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> [Word8] -> [Word8]
forall a. Int -> [a] -> [a]
take Int
maxNameLen ([Word8] -> ByteString) -> Gen [Word8] -> Gen ByteString
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Gen [Word8]
forall a. Arbitrary a => Gen a
arbitrary)
        Gen (ByteString -> Word8 -> Word32 -> Word64 -> Friend)
-> Gen ByteString -> Gen (Word8 -> Word32 -> Word64 -> Friend)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> ([Word8] -> ByteString
BS.pack ([Word8] -> ByteString)
-> ([Word8] -> [Word8]) -> [Word8] -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> [Word8] -> [Word8]
forall a. Int -> [a] -> [a]
take Int
maxStatusMessageLen ([Word8] -> ByteString) -> Gen [Word8] -> Gen ByteString
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Gen [Word8]
forall a. Arbitrary a => Gen a
arbitrary)
        Gen (Word8 -> Word32 -> Word64 -> Friend)
-> Gen Word8 -> Gen (Word32 -> Word64 -> Friend)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Gen Word8
forall a. Arbitrary a => Gen a
arbitrary
        Gen (Word32 -> Word64 -> Friend)
-> Gen Word32 -> Gen (Word64 -> Friend)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Gen Word32
forall a. Arbitrary a => Gen a
arbitrary
        Gen (Word64 -> Friend) -> Gen Word64 -> Gen Friend
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Gen Word64
forall a. Arbitrary a => Gen a
arbitrary

\end{code}