module System.Win32.DHCP.LengthBuffer
  ( LengthBuffer (..)
  , lengthBuffer
  ) where

import Control.Applicative
import Foreign.Ptr
import Foreign.Storable
import System.Win32.Types (DWORD)

import System.Win32.DHCP.DhcpStructure
import Utils (freeptr)

-- |A LengthBuffer is a list of items which can be marshalled in and out
-- of memory with a `DhcpArray` instance. 
data LengthBuffer a = LengthBuffer
    { lbLength :: Int
    , buffer :: [a]
    }

lengthBuffer :: DhcpArray a -> DhcpStructure (LengthBuffer a)
lengthBuffer dict = DhcpStructure
    { peekDhcp = peekLb dict
    , freeDhcp = freeLb dict
    , withDhcp' = withLb' dict
    , sizeDhcp = 8
    }

peekLb :: DhcpArray a -> Ptr (LengthBuffer a) -> IO (LengthBuffer a)
peekLb dict ptr = do
    len <- fromIntegral <$> peek (pNumElements ptr)
    pElements <- peek $ ppElements ptr
    LengthBuffer len <$> peekDhcpArray dict len pElements

freeLb :: DhcpArray a -> (Ptr x -> IO ()) -> Ptr (LengthBuffer a) -> IO ()
freeLb dict freefunc ptr = do
    len <- fromIntegral <$> peek (pNumElements ptr)
    pElements <- peek $ ppElements ptr
    freeDhcpArray dict freefunc len pElements

withLb' :: DhcpArray a -> LengthBuffer a -> Ptr (LengthBuffer a) -> IO r -> IO r
withLb' dict (LengthBuffer _ elems) ptr f =
    withDhcpArray dict elems $ \size pelems -> do
    pokeByteOff ptr 0 (fromIntegral size :: DWORD)
    poke (ppElements ptr) (castPtr pelems)
    f

pNumElements :: Ptr (LengthBuffer a) -> Ptr DWORD
pNumElements ptr = castPtr ptr

ppElements :: Ptr (LengthBuffer a) -> Ptr (Ptr a)
ppElements ptr = castPtr ptr `plusPtr` 4