{-# LANGUAGE GeneralizedNewtypeDeriving #-}

module Data.Conduit.Network.Stream.Internal where

import Control.Applicative
import Control.Monad.Trans
import Control.Monad.Trans.Resource
import Data.Conduit
import Data.ByteString (ByteString)

import qualified Data.ByteString      as BS
import qualified Data.ByteString.Lazy as BL

import Data.Conduit.Network.Stream.Header

-- | 'BL.ByteString' stream
newtype Stream m a = Stream { stream_base :: m a }
  deriving (Monad, MonadIO, Functor, Applicative)

instance MonadTrans Stream where
  lift f = Stream f

instance (MonadThrow m) => MonadThrow (Stream m) where
  monadThrow e = lift $ monadThrow e

instance (MonadResource m, MonadIO m) => MonadResource (Stream m) where
  liftResourceT t = lift $ liftResourceT t

encodeBS :: Monad m => Conduit ByteString (Stream m) ByteString 
encodeBS = awaitForever $ \bs -> do
  yield $ BS.pack (varint $ BS.length bs)
  mapM_ yield $ blocks bs
 where
  blocks bs | BS.null bs = []
            | otherwise  =
              let (f,r) = BS.splitAt 4096 bs
               in f : blocks r

encodeLazyBS :: Monad m => Conduit (Int, BL.ByteString) (Stream m) ByteString
encodeLazyBS = awaitForever $ \(l,bs) -> do
  yield $ BS.pack (varint l)
  mapM_ yield $ BL.toChunks bs