{-# LANGUAGE OverloadedStrings #-}

module Network.Wai.Application.CGI.Git.Conduit
    ( byteStringToBuilder
    , toResponseSource
    , parseHeader
    ) where

import Blaze.ByteString.Builder (Builder)
import qualified Blaze.ByteString.Builder as BB (fromByteString)
import Control.Applicative
import Data.Attoparsec.ByteString
import Data.ByteString (ByteString)
import Data.CaseInsensitive (CI(..), mk)
import Data.Conduit
import Data.Conduit.Attoparsec
import qualified Data.Conduit.List as CL
import Data.Word
import Network.HTTP.Types

----------------------------------------------------------------
byteStringToBuilder :: ByteString -> Builder
byteStringToBuilder = BB.fromByteString

----------------------------------------------------------------
toResponseSource ::
       ResumableSource IO ByteString -> IO (Source IO (Flush Builder))
toResponseSource rsrc = do
    (src, _) <- unwrapResumable rsrc
    return $ src $= CL.map (Chunk . byteStringToBuilder)

----------------------------------------------------------------
parseHeader :: Sink ByteString IO RequestHeaders
parseHeader = sinkParser parseHeader'

parseHeader' :: Parser RequestHeaders
parseHeader' = stop <|> loop
  where
    stop = [] <$ (crlf <|> endOfInput)
    loop = (:) <$> keyVal <*> parseHeader'

type RequestHeader = (CI ByteString, ByteString)

keyVal :: Parser RequestHeader
keyVal = do
    key <- takeTill (wcollon ==)
    _ <- word8 wcollon
    skipWhile (wspace ==)
    val <- takeTill (`elem` [wlf, wcr])
    crlf
    return (mk key, val)

crlf :: Parser ()
crlf = (cr >> (lf <|> return ())) <|> lf

cr :: Parser ()
cr = () <$ word8 wcr

lf :: Parser ()
lf = () <$ word8 wlf

wcollon :: Word8
wcollon = 58

wcr :: Word8
wcr = 13

wlf :: Word8
wlf = 10

wspace :: Word8
wspace = 32