content: {-# LANGUAGE OverloadedStrings #-}
  
  -- |A serializer for RDF as N-Triples
  -- <http://www.w3.org/TR/rdf-testcases/#ntriples>.
  
  module Text.RDF.RDF4H.NTriplesSerializer
    ( NTriplesSerializer(NTriplesSerializer)
    ) where
  
  import Data.RDF.Types
  import Data.RDF.Query (expandTriples)
  import qualified Data.Text as T
  import qualified Data.Text.IO as T
  import System.IO
  
  data NTriplesSerializer = NTriplesSerializer
  
  instance RdfSerializer NTriplesSerializer where
    hWriteRdf _     = _writeRdf
    writeRdf  _     = _writeRdf stdout
    hWriteH   _ _ _ = return ()
    writeH    _   _ = return ()
    hWriteTs  _     = _writeTriples
    writeTs   _     = _writeTriples stdout
    hWriteT   _     = _writeTriple
    writeT    _     = _writeTriple stdout
    hWriteN   _     = _writeNode
    writeN    _     = _writeNode stdout
  
  _writeRdf :: Rdf a => Handle -> RDF a -> IO ()
  _writeRdf h = _writeTriples h . expandTriples
  
  _writeTriples :: Handle -> Triples -> IO ()
  _writeTriples h = mapM_ (_writeTriple h)
  
  _writeTriple :: Handle -> Triple -> IO ()
  _writeTriple h (Triple s p o) =
    _writeNode h s >> hPutChar h ' ' >>
    _writeNode h p >> hPutChar h ' ' >>
    _writeNode h o >> hPutStrLn h " ."
  
  _writeNode :: Handle -> Node -> IO ()
  _writeNode h node = case node of
    (UNode s)  -> hPutChar h '<' >> T.hPutStr h s >> hPutChar h '>'
    (BNode gId) -> T.hPutStr h "_:" >> T.hPutStr h gId
    (BNodeGen i)-> T.hPutStr h "_:genid" >> hPutStr h (show i)
    (LNode n)   -> _writeLValue h n
  
  _writeLValue :: Handle -> LValue -> IO ()
  _writeLValue h lv = case lv of
    (PlainL lit)       -> _writeLiteralString h lit
    (PlainLL lit lang) -> _writeLiteralString h lit >>
                            hPutChar h '@' >>
                            T.hPutStr h lang
    (TypedL lit dtype) -> _writeLiteralString h lit >>
                            hPutStr h "^^<" >>
                            T.hPutStr h dtype >>
                            hPutChar h '>'
  
  _writeLiteralString:: Handle -> T.Text -> IO ()
  _writeLiteralString h ls = do
    hPutChar h '"'
    T.hPutStr h $ T.concatMap escapeChar ls
    hPutChar h '"'
    where escapeChar '\n' = "\\n"
          escapeChar '\t' = "\\t"
          escapeChar '\r' = "\\r"
          escapeChar '"'  = "\\\""
          escapeChar '\\' = "\\\\"
          escapeChar c    = T.singleton c
  