{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE RecordWildCards #-}

-- |
-- Module: BDCS.Import.Conduit
-- Copyright: (c) 2017 Red Hat, Inc.
-- License: LGPL
--
-- Maintainer: https://github.com/weldr
-- Stability: alpha
-- Portability: portable
--
-- Utilities for working with 'Conduit's when importing.

module BDCS.Import.Conduit(getFromURI,
                           ungzipIfCompressed)
 where

import           Conduit(Conduit, Producer, (.|), leftover, sourceFile)
import           Control.Monad.Trans.Resource(MonadResource)
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as BSL
import qualified Data.Conduit.Binary as CB(take)
import           Data.Conduit.Zlib(ungzip)
import           Data.Word(Word8)
import           Network.HTTP.Simple(getResponseBody, httpSource, parseRequest)
import           Network.URI(URI(..))

import           BDCS.Import.URI(showURI, uriToPath)
import           BDCS.Utils.Conduit(identityC)

-- | Load data from a given file: or http: 'URI' into a 'BS.ByteString'.
getFromURI :: MonadResource m => URI -> Producer m BS.ByteString
getFromURI uri@URI{..} | uriScheme == "file:" = sourceFile $ uriToPath uri
                       | otherwise            = do request <- parseRequest $ showURI uri
                                                   httpSource request getResponseBody

-- | If the 'BS.ByteString' in a 'Conduit' is compressed, pass it through ungzip to
-- uncompress it.  Otherwise, pass it through without doing anything.  We determine
-- whether a stream is compressed by looking for the gzip magic bytes at the start
-- of the stream.
ungzipIfCompressed :: MonadResource m => Conduit BS.ByteString m BS.ByteString
ungzipIfCompressed = do
    magic <- CB.take 2
    let nextPipe = if BSL.unpack magic == gzipMagic then ungzip else identityC

    -- send the two bytes we consumed as a leftover, then continue the conduit
    leftover (BSL.toStrict magic) .| nextPipe
    nextPipe
 where
    gzipMagic :: [Word8]
    gzipMagic = [0x1f, 0x8b]