    {-# LANGUAGE OverloadedStrings #-}
    -- |
    -- Module      : Data.PEM.Writer
    -- License     : BSD-style
    -- Maintainer  : Vincent Hanquez <vincent@snarc.org>
    -- Stability   : experimental
    -- Portability : portable
    --
    module Data.PEM.Writer
        ( pemWriteLBS
        , pemWriteBS
        ) where

    import Data.PEM.Types
    import Data.ByteString (ByteString)
    import qualified Data.ByteString as B
    import qualified Data.ByteString.Char8 as BC
    import qualified Data.ByteString.Lazy as L
    import           Data.ByteArray.Encoding (Base(Base64), convertToBase)

    -- | write a PEM structure to a builder
    pemWrite :: PEM -> L.ByteString
    pemWrite pem = L.fromChunks $ ([begin,header]++section++[end])
        where begin   = B.concat ["-----BEGIN ", sectionName, "-----\n"]
              end     = B.concat ["-----END ", sectionName, "-----\n" ]
              section :: [ByteString]
              section = map encodeLine $ splitChunks $ pemContent pem
              header :: ByteString
              header  = if null $ pemHeader pem
                            then B.empty
                            else B.concat ((concatMap toHeader (pemHeader pem)) ++ ["\n"])
              toHeader :: (String, ByteString) -> [ByteString]
              toHeader (k,v) = [ BC.pack k, ":", v, "\n" ]
              -- expect only ASCII. need to find a type to represent it.
              sectionName = BC.pack $ pemName pem
              encodeLine l = convertToBase Base64 l `B.append` "\n"

              splitChunks b
                      | B.length b > 48 = let (x,y) = B.splitAt 48 b in x : splitChunks y
                      | otherwise       = [b]

    -- | convert a PEM structure to a bytestring
    pemWriteBS :: PEM -> ByteString
    pemWriteBS = B.concat . L.toChunks . pemWrite

    -- | convert a PEM structure to a lazy bytestring
    pemWriteLBS :: PEM -> L.ByteString
    pemWriteLBS = pemWrite