{-# LANGUAGE
    CPP
  , DoAndIfThenElse
  , UnicodeSyntax
  #-}
-- |Type class for things behaves like a 'I.Handle'.
module Network.HTTP.Lucu.HandleLike
    ( HandleLike(..)
    , hPutBuilder
    )
    where
import Blaze.ByteString.Builder (Builder)
import qualified Blaze.ByteString.Builder as BB
import qualified Data.ByteString as B
import qualified Data.ByteString.Lazy.Char8 as L
#if defined(HAVE_SSL)
import qualified OpenSSL.Session as SSL
import OpenSSL.X509
#endif
import Prelude.Unicode
import qualified System.IO as I

class HandleLike h where
    hGetLBS  h  IO L.ByteString

    hGetBS   h  Int  IO B.ByteString
    hPutBS   h  B.ByteString  IO ()

#if defined(HAVE_SSL)
    hGetPeerCert  h  IO (Maybe X509)
    hGetPeerCert = const $ return Nothing
#endif
    hIsSSL  h  Bool
    hIsSSL _ = False

    hFlush   h  IO ()
    hClose   h  IO ()

instance HandleLike I.Handle where
    hGetLBS = L.hGetContents

    hGetBS  = B.hGet
    hPutBS  = B.hPut

    hFlush  = I.hFlush
    hClose  = I.hClose

#if defined(HAVE_SSL)
instance HandleLike SSL.SSL where
    hGetLBS = SSL.lazyRead

    hGetBS  = SSL.read
    hPutBS  = SSL.write

    hGetPeerCert s
        = do isValid <- SSL.getVerifyResult s
             if isValid then
                 SSL.getPeerCertificate s
             else
                 return Nothing
    hIsSSL _ = True

    hFlush _ = return () -- No need to do anything.
    hClose s = SSL.shutdown s SSL.Bidirectional
#endif

hPutBuilder  HandleLike h  h  Builder  IO ()
{-# INLINE hPutBuilder #-}
hPutBuilder = BB.toByteStringIO  hPutBS