{-|
Module      : $header$
Copyright   : (c) Laurent P René de Cotret, 2020
License     : GNU GPL, version 2 or above
Maintainer  : laurent.decotret@outlook.com
Stability   : internal
Portability : portable

Prelude for renderers, containing some helpful utilities.
-}

module Text.Pandoc.Filter.Plot.Renderers.Prelude (

      module Prelude
    , module Text.Pandoc.Filter.Plot.Monad
    , Text
    , st
    , unpack
    , commandSuccess
    , existsOnPath
    , executable
    , OutputSpec(..)
) where

import           Data.Maybe                    (isJust)
import           Data.Text                     (Text, unpack)

import           System.Directory              (findExecutable)
import           System.Exit                   (ExitCode(..))

import           Text.Shakespeare.Text         (st)

import           Text.Pandoc.Filter.Plot.Monad


-- | Check that the supplied command results in

-- an exit code of 0 (i.e. no errors)

commandSuccess :: Text -> PlotM Bool
commandSuccess :: Text -> PlotM Bool
commandSuccess s :: Text
s = do
    (ec :: ExitCode
ec, _) <- Text -> PlotM (ExitCode, Text)
runCommand Text
s
    Bool -> PlotM Bool
forall (m :: * -> *) a. Monad m => a -> m a
return (Bool -> PlotM Bool) -> Bool -> PlotM Bool
forall a b. (a -> b) -> a -> b
$ ExitCode
ec ExitCode -> ExitCode -> Bool
forall a. Eq a => a -> a -> Bool
== ExitCode
ExitSuccess


-- | Checks that an executable is available on path, at all.

existsOnPath :: FilePath -> IO Bool
existsOnPath :: FilePath -> IO Bool
existsOnPath fp :: FilePath
fp = FilePath -> IO (Maybe FilePath)
findExecutable FilePath
fp IO (Maybe FilePath) -> (Maybe FilePath -> IO Bool) -> IO Bool
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (Maybe FilePath -> Bool) -> IO (Maybe FilePath) -> IO Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Maybe FilePath -> Bool
forall a. Maybe a -> Bool
isJust (IO (Maybe FilePath) -> IO Bool)
-> (Maybe FilePath -> IO (Maybe FilePath))
-> Maybe FilePath
-> IO Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Maybe FilePath -> IO (Maybe FilePath)
forall (m :: * -> *) a. Monad m => a -> m a
return


-- | Try to find the executable and normalise its path.

-- If it cannot be found, it is left unchanged - just in case.

tryToFindExe :: String -> IO FilePath
tryToFindExe :: FilePath -> IO FilePath
tryToFindExe fp :: FilePath
fp = FilePath -> IO (Maybe FilePath)
findExecutable FilePath
fp IO (Maybe FilePath)
-> (Maybe FilePath -> IO FilePath) -> IO FilePath
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= IO FilePath
-> (FilePath -> IO FilePath) -> Maybe FilePath -> IO FilePath
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (FilePath -> IO FilePath
forall (m :: * -> *) a. Monad m => a -> m a
return FilePath
fp) FilePath -> IO FilePath
forall (m :: * -> *) a. Monad m => a -> m a
return


-- | Path to the executable of a toolkit. If the executable can

-- be found, then it will be the full path to it.

executable :: Toolkit -> PlotM FilePath
executable :: Toolkit -> PlotM FilePath
executable Matplotlib   = (Configuration -> FilePath) -> PlotM FilePath
forall a. (Configuration -> a) -> PlotM a
asksConfig Configuration -> FilePath
matplotlibExe   PlotM FilePath -> (FilePath -> PlotM FilePath) -> PlotM FilePath
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= IO FilePath -> PlotM FilePath
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO FilePath -> PlotM FilePath)
-> (FilePath -> IO FilePath) -> FilePath -> PlotM FilePath
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> IO FilePath
tryToFindExe
executable PlotlyPython = (Configuration -> FilePath) -> PlotM FilePath
forall a. (Configuration -> a) -> PlotM a
asksConfig Configuration -> FilePath
plotlyPythonExe PlotM FilePath -> (FilePath -> PlotM FilePath) -> PlotM FilePath
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= IO FilePath -> PlotM FilePath
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO FilePath -> PlotM FilePath)
-> (FilePath -> IO FilePath) -> FilePath -> PlotM FilePath
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> IO FilePath
tryToFindExe
executable PlotlyR      = (Configuration -> FilePath) -> PlotM FilePath
forall a. (Configuration -> a) -> PlotM a
asksConfig Configuration -> FilePath
plotlyRExe      PlotM FilePath -> (FilePath -> PlotM FilePath) -> PlotM FilePath
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= IO FilePath -> PlotM FilePath
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO FilePath -> PlotM FilePath)
-> (FilePath -> IO FilePath) -> FilePath -> PlotM FilePath
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> IO FilePath
tryToFindExe
executable Matlab       = (Configuration -> FilePath) -> PlotM FilePath
forall a. (Configuration -> a) -> PlotM a
asksConfig Configuration -> FilePath
matlabExe       PlotM FilePath -> (FilePath -> PlotM FilePath) -> PlotM FilePath
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= IO FilePath -> PlotM FilePath
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO FilePath -> PlotM FilePath)
-> (FilePath -> IO FilePath) -> FilePath -> PlotM FilePath
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> IO FilePath
tryToFindExe
executable Mathematica  = (Configuration -> FilePath) -> PlotM FilePath
forall a. (Configuration -> a) -> PlotM a
asksConfig Configuration -> FilePath
mathematicaExe  PlotM FilePath -> (FilePath -> PlotM FilePath) -> PlotM FilePath
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= IO FilePath -> PlotM FilePath
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO FilePath -> PlotM FilePath)
-> (FilePath -> IO FilePath) -> FilePath -> PlotM FilePath
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> IO FilePath
tryToFindExe
executable Octave       = (Configuration -> FilePath) -> PlotM FilePath
forall a. (Configuration -> a) -> PlotM a
asksConfig Configuration -> FilePath
octaveExe       PlotM FilePath -> (FilePath -> PlotM FilePath) -> PlotM FilePath
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= IO FilePath -> PlotM FilePath
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO FilePath -> PlotM FilePath)
-> (FilePath -> IO FilePath) -> FilePath -> PlotM FilePath
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> IO FilePath
tryToFindExe
executable GGPlot2      = (Configuration -> FilePath) -> PlotM FilePath
forall a. (Configuration -> a) -> PlotM a
asksConfig Configuration -> FilePath
ggplot2Exe      PlotM FilePath -> (FilePath -> PlotM FilePath) -> PlotM FilePath
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= IO FilePath -> PlotM FilePath
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO FilePath -> PlotM FilePath)
-> (FilePath -> IO FilePath) -> FilePath -> PlotM FilePath
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> IO FilePath
tryToFindExe
executable GNUPlot      = (Configuration -> FilePath) -> PlotM FilePath
forall a. (Configuration -> a) -> PlotM a
asksConfig Configuration -> FilePath
gnuplotExe      PlotM FilePath -> (FilePath -> PlotM FilePath) -> PlotM FilePath
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= IO FilePath -> PlotM FilePath
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO FilePath -> PlotM FilePath)
-> (FilePath -> IO FilePath) -> FilePath -> PlotM FilePath
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> IO FilePath
tryToFindExe
executable Graphviz     = (Configuration -> FilePath) -> PlotM FilePath
forall a. (Configuration -> a) -> PlotM a
asksConfig Configuration -> FilePath
graphvizExe     PlotM FilePath -> (FilePath -> PlotM FilePath) -> PlotM FilePath
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= IO FilePath -> PlotM FilePath
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO FilePath -> PlotM FilePath)
-> (FilePath -> IO FilePath) -> FilePath -> PlotM FilePath
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> IO FilePath
tryToFindExe


-- | Internal description of all information 

-- needed to output a figure.

data OutputSpec = OutputSpec 
    { OutputSpec -> FigureSpec
oFigureSpec    :: FigureSpec    -- ^ Figure spec

    , OutputSpec -> FilePath
oScriptPath    :: FilePath      -- ^ Path to the script to render

    , OutputSpec -> FilePath
oFigurePath    :: FilePath      -- ^ Figure output path

    }