{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE PatternSynonyms #-}

module Hans.Udp.Packet where

import Data.Serialize (Get,getWord16be,label,Putter,Put,putWord16be)
import Data.Word (Word16)


-- Udp Ports -------------------------------------------------------------------

type UdpPort = Word16

getUdpPort :: Get UdpPort
getUdpPort  = getWord16be
{-# INLINE getUdpPort #-}

putUdpPort :: Putter UdpPort
putUdpPort  = putWord16be
{-# INLINE putUdpPort #-}


-- Udp Header ------------------------------------------------------------------

data UdpHeader = UdpHeader { udpSourcePort :: {-# UNPACK #-} !UdpPort
                           , udpDestPort   :: {-# UNPACK #-} !UdpPort
                           , udpChecksum   :: {-# UNPACK #-} !Word16
                           } deriving (Eq,Show)

emptyUdpHeader :: UdpHeader
emptyUdpHeader  = UdpHeader { udpSourcePort = 0
                            , udpDestPort   = 0
                            , udpChecksum   = 0 }

udpHeaderSize :: Int
udpHeaderSize  = 8

-- | Parse out a @UdpHeader@, and the size of the payload.
getUdpHeader :: Get (UdpHeader,Int)
getUdpHeader  = label "UDP Header" $
  do udpSourcePort <- getUdpPort
     udpDestPort   <- getUdpPort
     len           <- getWord16be
     udpChecksum   <- getWord16be
     return (UdpHeader { .. },fromIntegral len - udpHeaderSize)

-- | Render a @UdpHeader@.
putUdpHeader :: UdpHeader -> Int -> Put
putUdpHeader UdpHeader { .. } bodyLen =
  do putUdpPort  udpSourcePort
     putUdpPort  udpDestPort
     putWord16be (fromIntegral (bodyLen + udpHeaderSize))
     putWord16be 0