{-# LANGUAGE
    QuasiQuotes
  , RecordWildCards
  , UnicodeSyntax
  #-}
-- |An internal module for generating Haskell modules eith an
-- arbitrary file implanted.
module Network.HTTP.Lucu.Implant
    ( Input(..)

    , originalLen
    , gzippedLen
    , useGZip

    , openInput
    )
    where
import Codec.Compression.GZip
import Control.Applicative
import qualified Data.ByteString.Lazy as L
import Data.Convertible.Base
import Data.Convertible.Instances.Ascii ()
import Data.Digest.Pure.SHA
import Data.Maybe
import Data.Time
import Network.HTTP.Lucu.ETag
import Network.HTTP.Lucu.MIMEType
import Network.HTTP.Lucu.MIMEType.DefaultExtensionMap
import Network.HTTP.Lucu.MIMEType.Guess
import Network.HTTP.Lucu.Utils
import Prelude.Unicode

data Input
    = Input {
        iPath    ∷ !FilePath
      , iLastMod ∷ !UTCTime
      , iType    ∷ !MIMEType
      , iETag    ∷ !ETag
      , iRawData ∷ !L.ByteString
      , iGZipped ∷ !L.ByteString
      }

originalLen ∷ Input → Integer
originalLen (Input {..})
    = fromIntegral $ L.length iRawData

gzippedLen ∷ Input → Integer
gzippedLen (Input {..})
    = fromIntegral $ L.length iGZipped

useGZip ∷ Input → Bool
useGZip i
    = originalLen i ≥ gzippedLen i

openInput ∷ FilePath → Maybe MIMEType → Maybe ETag → IO Input
openInput fpath ctype etag
    = do lastMod ← lastModified fpath
         input   ← openInputFile fpath
         return Input {
                  iPath    = fpath
                , iLastMod = lastMod
                , iType    = fromMaybe octetStream
                             $ ctype <|> guessType fpath
                , iETag    = fromMaybe (mkETagFromInput input) etag
                , iRawData = input
                , iGZipped = compressWith compParams input
                }
    where
      octetStream ∷ MIMEType
      octetStream = [mimeType| application/octet-stream |]

      compParams ∷ CompressParams
      compParams = defaultCompressParams {
                     compressLevel = bestCompression
                   }

lastModified ∷ FilePath → IO UTCTime
lastModified "-"   = getCurrentTime
lastModified fpath = getLastModified fpath

openInputFile ∷ FilePath → IO L.ByteString
openInputFile "-"   = L.getContents
openInputFile fpath = L.readFile fpath

guessType ∷ FilePath → Maybe MIMEType
guessType = guessTypeByFileName defaultExtensionMap

mkETagFromInput ∷ L.ByteString → ETag
mkETagFromInput input
    = strongETag $ convertUnsafe
                 $ "SHA-1:" ⧺ showDigest (sha1 input)