{-# LANGUAGE Unsafe #-}
{-|
Module      : Text.Pandoc.Filter.Scripting
Copyright   : (c) Laurent P René de Cotret, 2018
License     : MIT
Maintainer  : laurent.decotret@outlook.com
Stability   : internal
Portability : portable

This module defines types and functions that help
with running Python scripts.
-}

module Text.Pandoc.Filter.Scripting (
      runTempPythonScript
    , addPlotCapture
    , hasBlockingShowCall
    , PythonScript
    , ScriptResult(..)
) where

import System.Exit          (ExitCode(..))
import System.FilePath      ((</>))
import System.IO.Temp       (getCanonicalTemporaryDirectory)
import System.Process.Typed (runProcess, shell)

import Data.Monoid          (Any(..))

-- | String representation of a Python script

type PythonScript = String

-- | Possible result of running a Python script

data ScriptResult = ScriptSuccess
                  | ScriptFailure Int

-- | Take a python script in string form, write it in a temporary directory,

-- then execute it. 

runTempPythonScript :: PythonScript    -- ^ Content of the script

                    -> IO ScriptResult -- ^ Result with exit code.

runTempPythonScript script = do
            -- Write script to temporary directory

            scriptPath <- (</> "pandoc-pyplot.py") <$>  getCanonicalTemporaryDirectory
            writeFile scriptPath script
            -- Execute script

            ec <- runProcess $ shell $ "python " <> (show scriptPath)
            case ec of
                ExitSuccess -> return ScriptSuccess
                ExitFailure code -> return $ ScriptFailure code

-- | Modify a Python plotting script to save the figure to a filename.

addPlotCapture :: FilePath          -- ^ Path where to save the figure

               -> PythonScript      -- ^ Raw code block

               -> PythonScript      -- ^ Code block with added capture

addPlotCapture fname content =
    mconcat [ content
            , "\nimport matplotlib.pyplot as plt"  -- Just in case

            , "\nplt.savefig(" <> show fname <> ")\n\n"
            ]

-- | Detect the presence of a blocking show call, for example "plt.show()"

hasBlockingShowCall :: PythonScript -> Bool
hasBlockingShowCall script = anyOf
        [ "plt.show()" `elem` scriptLines
        , "matplotlib.pyplot.show()" `elem` scriptLines
        ]
    where
        scriptLines = lines script
        anyOf xs = getAny $ mconcat $ Any <$> xs