module Foundation.Conduit
    ( Conduit
    , ResourceT
    , ZipSink (..)
    , await
    , awaitForever
    , yield
    , yields
    , yieldOr
    , leftover
    , runConduit
    , runConduitPure
    , runConduitRes
    , fuse
    , (.|)
    , sourceFile
    , sourceHandle
    , sinkFile
    , sinkHandle
    , sinkList
    , bracketConduit
    ) where

import Foundation.Conduit.Internal
import Foundation.Collection
import Foundation.IO
import Foundation.IO.File
import Basement.Compat.Base
import Foundation.Monad.Base
import Foundation.Array
import Foundation
import System.IO (Handle)


infixr 2 .|
-- | Operator version of 'fuse'.
(.|) :: Monad m => Conduit a b m () -> Conduit b c m r -> Conduit a c m r
(.|) = fuse
{-# INLINE (.|) #-}

sourceFile :: MonadResource m => FilePath -> Conduit i (UArray Word8) m ()
sourceFile fp = bracketConduit
    (openFile fp ReadMode)
    closeFile
    sourceHandle

sourceHandle :: MonadIO m
             => Handle
             -> Conduit i (UArray Word8) m ()
sourceHandle h =
    loop
  where
    defaultChunkSize :: Int
    defaultChunkSize = (32 :: Int) * 1000 - 16
    loop = do
        arr <- liftIO (hGet h defaultChunkSize)
        if null arr
            then return ()
            else yield arr >> loop

-- | Send values downstream.
yields :: (Monad m, Foldable os, Element os ~ o) => os -> Conduit i o m ()
-- FIXME: Should be using mapM_ once that is in Foldable, see #334
yields = foldr ((>>) . yield) (return ())


sinkFile :: MonadResource m => FilePath -> Conduit (UArray Word8) i m ()
sinkFile fp = bracketConduit
    (openFile fp WriteMode)
    closeFile
    sinkHandle

sinkHandle :: MonadIO m
           => Handle
           -> Conduit (UArray Word8) o m ()
sinkHandle h =
    loop
  where
    loop = await >>= maybe
        (return ())
        (\arr -> liftIO (hPut h arr) >> loop)

sinkList :: Monad m => Conduit i o m [i]
sinkList =
    loop id
  where
    loop front = await >>= maybe
        (return (front []))
        (\x -> loop (front . (x:)))