module Clckwrks.Markup.Markdown where

import           Clckwrks.Types                (Trust(..))
import           Control.Concurrent      (forkIO)
import           Control.Concurrent.MVar (newEmptyMVar, readMVar, putMVar)
import           Control.Monad.Trans     (MonadIO(liftIO))
import           Data.Text               (Text)
import qualified Data.Text               as T
import qualified Data.Text.IO            as T
import           Text.HTML.SanitizeXSS   (sanitizeBalance)
import           System.Exit             (ExitCode(ExitFailure, ExitSuccess))
import           System.IO               (hClose)
import           System.Process          (waitForProcess, runInteractiveProcess)

-- | run the text through the 'markdown' executable. If successful,
-- and the input is marked 'Untrusted', run the output through
-- xss-sanitize / sanitizeBalance to prevent injection attacks.
markdown :: (MonadIO m) =>
            Maybe [String]       -- ^ override command-line flags
         -> Trust                -- ^ do we trust the author
         -> Text                 -- ^ markdown text
         -> m (Either Text Text) -- ^ Left error, Right html
markdown mArgs trust txt = liftIO $
    do let args = case mArgs of
                    Nothing -> ["--html4tags"]
                    (Just a) -> a
       (inh, outh, errh, ph) <- runInteractiveProcess "markdown" args Nothing Nothing
       _ <- forkIO $ do T.hPutStr inh txt
                        hClose inh
       mvOut <- newEmptyMVar
       _ <- forkIO $ do c <- T.hGetContents outh
                        putMVar mvOut c
       mvErr <- newEmptyMVar
       _ <- forkIO $ do c <- T.hGetContents errh
                        putMVar mvErr c
       ec <- waitForProcess ph
       case ec of
         (ExitFailure _) ->
             do e <- readMVar mvErr
                return (Left e)
         ExitSuccess ->
             do m <- readMVar mvOut
                e <- readMVar mvErr
                return (Right ((if (trust == Untrusted) then sanitizeBalance else id) m))