    {-# LANGUAGE EmptyDataDecls #-}
    -- |
    -- Module      : Network.TLS.Record.Types
    -- License     : BSD-style
    -- Maintainer  : Vincent Hanquez <vincent@snarc.org>
    -- Stability   : experimental
    -- Portability : unknown
    --
    -- The Record Protocol takes messages to be transmitted, fragments the
    -- data into manageable blocks, optionally compresses the data, applies
    -- a MAC, encrypts, and transmits the result.  Received data is
    -- decrypted, verified, decompressed, reassembled, and then delivered to
    -- higher-level clients.
    --
    module Network.TLS.Record.Types
            ( Header(..)
            , ProtocolType(..)
            , packetType
            -- * TLS Records
            , Record(..)
            -- * TLS Record fragment and constructors
            , Fragment
            , fragmentPlaintext
            , fragmentCiphertext
            , fragmentGetBytes
            , Plaintext
            , Compressed
            , Ciphertext
            -- * manipulate record
            , onRecordFragment
            , fragmentCompress
            , fragmentCipher
            , fragmentUncipher
            , fragmentUncompress
            -- * serialize record
            , rawToRecord
            , recordToRaw
            , recordToHeader
            ) where

    import Network.TLS.Struct
    import Network.TLS.State
    import qualified Data.ByteString as B
    import Control.Applicative ((<$>))

    -- | Represent a TLS record.
    data Record a = Record !ProtocolType !Version !(Fragment a) deriving (Show,Eq)

    newtype Fragment a = Fragment Bytes deriving (Show,Eq)

    data Plaintext
    data Compressed
    data Ciphertext

    fragmentPlaintext :: Bytes -> Fragment Plaintext
    fragmentPlaintext bytes = Fragment bytes

    fragmentCiphertext :: Bytes -> Fragment Ciphertext
    fragmentCiphertext bytes = Fragment bytes

    fragmentGetBytes :: Fragment a -> Bytes
    fragmentGetBytes (Fragment bytes) = bytes

    onRecordFragment :: Record a -> (Fragment a -> TLSSt (Fragment b)) -> TLSSt (Record b)
    onRecordFragment (Record pt ver frag) f = Record pt ver <$> f frag

    fragmentMap :: (Bytes -> TLSSt Bytes) -> Fragment a -> TLSSt (Fragment b)
    fragmentMap f (Fragment b) = Fragment <$> f b

    -- | turn a plaintext record into a compressed record using the compression function supplied
    fragmentCompress :: (Bytes -> TLSSt Bytes) -> Fragment Plaintext -> TLSSt (Fragment Compressed)
    fragmentCompress f = fragmentMap f

    -- | turn a compressed record into a ciphertext record using the cipher function supplied
    fragmentCipher :: (Bytes -> TLSSt Bytes) -> Fragment Compressed -> TLSSt (Fragment Ciphertext)
    fragmentCipher f = fragmentMap f

    -- | turn a ciphertext fragment into a compressed fragment using the cipher function supplied
    fragmentUncipher :: (Bytes -> TLSSt Bytes) -> Fragment Ciphertext -> TLSSt (Fragment Compressed)
    fragmentUncipher f = fragmentMap f

    -- | turn a compressed fragment into a plaintext fragment using the decompression function supplied
    fragmentUncompress :: (Bytes -> TLSSt Bytes) -> Fragment Compressed -> TLSSt (Fragment Plaintext)
    fragmentUncompress f = fragmentMap f

    -- | turn a record into an header and bytes
    recordToRaw :: Record a -> (Header, Bytes)
    recordToRaw (Record pt ver (Fragment bytes)) = (Header pt ver (fromIntegral $ B.length bytes), bytes)

    -- | turn a header and a fragment into a record
    rawToRecord :: Header -> Fragment a -> Record a
    rawToRecord (Header pt ver _) fragment = Record pt ver fragment

    -- | turn a record into a header
    recordToHeader :: Record a -> Header
    recordToHeader (Record pt ver (Fragment bytes)) = Header pt ver (fromIntegral $ B.length bytes)