module Data.Binary.Defer.List(ListDefer, newListDefer, readListDefer) where

import System.IO
import Control.Monad
import Foreign (unsafePerformIO)

import Data.Binary.Defer
import Data.Binary.Defer.Internal


data ListDefer a = ListWrite [a]
                 | ListRead {hndl :: Handle, pos :: Int, count :: Int, size :: Int, undef :: a}


instance (BinaryDeferStatic  a, Show a) => Show (ListDefer a) where
    show (ListWrite a) = "(ListDefer " ++ show a ++ ")"
    show x = "(ListDefer " ++ show (readListDefer x 0 (count x)) ++ ")"


instance BinaryDeferStatic a => BinaryDefer (ListDefer a) where
    putDefer hndl (ListWrite xs) = hPutInt hndl (length xs) >> concatMapM (putDefer hndl) xs
        where concatMapM f = liftM concat . mapM f


    get hndl = do
        len <- hGetInt hndl
        pos <- hGetPos hndl
        let res = ListRead hndl pos len (getSize (undef res)) undefined
        hSetPos hndl (pos + (size res * len))
        return res


newListDefer :: BinaryDeferStatic a => [a] -> ListDefer a
newListDefer = ListWrite


-- | Start, Length
readListDefer :: BinaryDeferStatic a => ListDefer a -> Int -> Int -> [a]
readListDefer (ListRead hndl pos count size _) start len
    | start + len > count = error "readListDefer, ran off the end"
    | otherwise = unsafePerformIO $ do
        p <- hGetPos hndl
        hSetPos hndl (pos + (size * start))
        res <- replicateM len (get hndl)
        hSetPos hndl p
        return res