--------------------------------------------------------------------------------
-- |
-- Module      :  Ipe.IpeToIpe
-- Copyright   :  (C) Frank Staals
-- License     :  see the LICENSE file
-- Maintainer  :  Frank Staals
--
-- Use 'ipetoipe' to generate pdf files.
--
-- Note that all functions in this module require that 'ipetoipe' is
-- installed (it is bundled with ipe) and available on the path.

--------------------------------------------------------------------------------
module Ipe.IpeToIpe where

import           Data.Range
import           Ipe.Types (IpeFile)
import           Ipe.Writer (writeIpeFile, IpeWriteText)
import           System.Directory (getTemporaryDirectory, removeFile)
import           System.FilePath
import qualified System.Process.Typed as Process
import           System.Random

--------------------------------------------------------------------------------

-- | Call 'ipetoipe' to produce an image of the specified type.
ipeToIpeWith                          :: Options -- ^ the options to use
                                      -> FileType -- ^ output file type
                                      -> FilePath -- ^ input file path
                                      -> FilePath -- ^ output file path
                                      -> IO ()
ipeToIpeWith :: Options -> FileType -> FilePath -> FilePath -> IO ()
ipeToIpeWith Options
options FileType
fType FilePath
inFp FilePath
outFp =
    ProcessConfig () () () -> (Process () () () -> IO ()) -> IO ()
forall (m :: * -> *) stdin stdout stderr a.
MonadUnliftIO m =>
ProcessConfig stdin stdout stderr
-> (Process stdin stdout stderr -> m a) -> m a
Process.withProcessWait ProcessConfig () () ()
processCfg ((Process () () () -> IO ()) -> IO ())
-> (Process () () () -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Process () () ()
_iperenderProc -> () -> IO ()
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
  where
    processCfg :: ProcessConfig () () ()
processCfg = FilePath -> [FilePath] -> ProcessConfig () () ()
Process.proc FilePath
"ipetoipe" [FilePath]
args
    args :: [FilePath]
args = [ FilePath
"-" FilePath -> FilePath -> FilePath
forall a. Semigroup a => a -> a -> a
<> FileType -> FilePath
forall a. Show a => a -> FilePath
show FileType
fType ] [FilePath] -> [FilePath] -> [FilePath]
forall a. Semigroup a => a -> a -> a
<>
           [[FilePath]] -> [FilePath]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [ [ FilePath
"-pages", Range Int -> FilePath
forall a. Show a => Range a -> FilePath
pageRange Range Int
r ] | PageRange Range Int
r <- [Options -> PageRange
pages Options
options] ] [FilePath] -> [FilePath] -> [FilePath]
forall a. Semigroup a => a -> a -> a
<>
           [[FilePath]] -> [FilePath]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [ [ FilePath
"-view", Int -> Int -> FilePath
forall a a. (Show a, Show a) => a -> a -> FilePath
pageView Int
p Int
v ] | Just (Int
p,Int
v) <- [Options -> Maybe (Int, Int)
singleView Options
options] ] [FilePath] -> [FilePath] -> [FilePath]
forall a. Semigroup a => a -> a -> a
<>
           [ FilePath
"-export" | Export
Export Export -> Export -> Bool
forall a. Eq a => a -> a -> Bool
== Options -> Export
export Options
options ] [FilePath] -> [FilePath] -> [FilePath]
forall a. Semigroup a => a -> a -> a
<>
           [ FilePath
"-runlatex" | Options -> Bool
runLatex Options
options] [FilePath] -> [FilePath] -> [FilePath]
forall a. Semigroup a => a -> a -> a
<>
           [ FilePath
"-nozip"      | NoZip
NoZip NoZip -> NoZip -> Bool
forall a. Eq a => a -> a -> Bool
== Options -> NoZip
nozip Options
options ] [FilePath] -> [FilePath] -> [FilePath]
forall a. Semigroup a => a -> a -> a
<>
           [ FilePath
inFp
           , FilePath
outFp
           ]
    pageRange :: Range a -> FilePath
pageRange (Range' a
l a
u) = a -> FilePath
forall a. Show a => a -> FilePath
show a
l FilePath -> FilePath -> FilePath
forall a. Semigroup a => a -> a -> a
<> FilePath
"-" FilePath -> FilePath -> FilePath
forall a. Semigroup a => a -> a -> a
<> a -> FilePath
forall a. Show a => a -> FilePath
show a
u
    pageView :: a -> a -> FilePath
pageView a
p a
v = a -> FilePath
forall a. Show a => a -> FilePath
show a
p FilePath -> FilePath -> FilePath
forall a. Semigroup a => a -> a -> a
<> FilePath
"-" FilePath -> FilePath -> FilePath
forall a. Semigroup a => a -> a -> a
<> a -> FilePath
forall a. Show a => a -> FilePath
show a
v


-- | Call 'ipetoipe' with the default options.
ipeToIpe :: FileType -> FilePath -> FilePath -> IO ()
ipeToIpe :: FileType -> FilePath -> FilePath -> IO ()
ipeToIpe = Options -> FileType -> FilePath -> FilePath -> IO ()
ipeToIpeWith Options
defaultOptions

-- | Write an ipe file to disk as an ipe readable pdf file.
--
-- Note that like all other functions in this module, this requires
-- 'ipetoipe' to be installed (it is bundled with ipe) and available
-- on the path.
--
-- Note this will write soem intermediate file to your system temp dir.
writeIpeFileAsPdf      :: IpeWriteText r => FilePath -> IpeFile r -> IO ()
writeIpeFileAsPdf :: FilePath -> IpeFile r -> IO ()
writeIpeFileAsPdf FilePath
fp IpeFile r
f = do Int
num    <- forall a (m :: * -> *). (Random a, MonadIO m) => m a
forall (m :: * -> *). (Random Int, MonadIO m) => m Int
randomIO @Int
                            FilePath
tempDir <- IO FilePath
getTemporaryDirectory
                            let xmlFp :: FilePath
xmlFp = FilePath
tempDir FilePath -> FilePath -> FilePath
</> FilePath
"writeipepdf" FilePath -> FilePath -> FilePath
forall a. Semigroup a => a -> a -> a
<> Int -> FilePath
forall a. Show a => a -> FilePath
show Int
num FilePath -> FilePath -> FilePath
<.> FilePath
"ipe"
                            FilePath -> IpeFile r -> IO ()
forall r. IpeWriteText r => FilePath -> IpeFile r -> IO ()
writeIpeFile FilePath
xmlFp IpeFile r
f
                            FileType -> FilePath -> FilePath -> IO ()
ipeToIpe FileType
PDF FilePath
xmlFp FilePath
fp
                            FilePath -> IO ()
removeFile FilePath
xmlFp


data FileType = PDF | XML
  deriving (FileType -> FileType -> Bool
(FileType -> FileType -> Bool)
-> (FileType -> FileType -> Bool) -> Eq FileType
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: FileType -> FileType -> Bool
$c/= :: FileType -> FileType -> Bool
== :: FileType -> FileType -> Bool
$c== :: FileType -> FileType -> Bool
Eq,Int -> FileType
FileType -> Int
FileType -> [FileType]
FileType -> FileType
FileType -> FileType -> [FileType]
FileType -> FileType -> FileType -> [FileType]
(FileType -> FileType)
-> (FileType -> FileType)
-> (Int -> FileType)
-> (FileType -> Int)
-> (FileType -> [FileType])
-> (FileType -> FileType -> [FileType])
-> (FileType -> FileType -> [FileType])
-> (FileType -> FileType -> FileType -> [FileType])
-> Enum FileType
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
enumFromThenTo :: FileType -> FileType -> FileType -> [FileType]
$cenumFromThenTo :: FileType -> FileType -> FileType -> [FileType]
enumFromTo :: FileType -> FileType -> [FileType]
$cenumFromTo :: FileType -> FileType -> [FileType]
enumFromThen :: FileType -> FileType -> [FileType]
$cenumFromThen :: FileType -> FileType -> [FileType]
enumFrom :: FileType -> [FileType]
$cenumFrom :: FileType -> [FileType]
fromEnum :: FileType -> Int
$cfromEnum :: FileType -> Int
toEnum :: Int -> FileType
$ctoEnum :: Int -> FileType
pred :: FileType -> FileType
$cpred :: FileType -> FileType
succ :: FileType -> FileType
$csucc :: FileType -> FileType
Enum)

instance Show FileType where
  show :: FileType -> FilePath
show = \case
    FileType
PDF -> FilePath
"pdf"
    FileType
XML -> FilePath
"xml"

data Export = RetainIpeInfo | Export
  deriving (Int -> Export -> FilePath -> FilePath
[Export] -> FilePath -> FilePath
Export -> FilePath
(Int -> Export -> FilePath -> FilePath)
-> (Export -> FilePath)
-> ([Export] -> FilePath -> FilePath)
-> Show Export
forall a.
(Int -> a -> FilePath -> FilePath)
-> (a -> FilePath) -> ([a] -> FilePath -> FilePath) -> Show a
showList :: [Export] -> FilePath -> FilePath
$cshowList :: [Export] -> FilePath -> FilePath
show :: Export -> FilePath
$cshow :: Export -> FilePath
showsPrec :: Int -> Export -> FilePath -> FilePath
$cshowsPrec :: Int -> Export -> FilePath -> FilePath
Show,Export -> Export -> Bool
(Export -> Export -> Bool)
-> (Export -> Export -> Bool) -> Eq Export
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Export -> Export -> Bool
$c/= :: Export -> Export -> Bool
== :: Export -> Export -> Bool
$c== :: Export -> Export -> Bool
Eq,Int -> Export
Export -> Int
Export -> [Export]
Export -> Export
Export -> Export -> [Export]
Export -> Export -> Export -> [Export]
(Export -> Export)
-> (Export -> Export)
-> (Int -> Export)
-> (Export -> Int)
-> (Export -> [Export])
-> (Export -> Export -> [Export])
-> (Export -> Export -> [Export])
-> (Export -> Export -> Export -> [Export])
-> Enum Export
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
enumFromThenTo :: Export -> Export -> Export -> [Export]
$cenumFromThenTo :: Export -> Export -> Export -> [Export]
enumFromTo :: Export -> Export -> [Export]
$cenumFromTo :: Export -> Export -> [Export]
enumFromThen :: Export -> Export -> [Export]
$cenumFromThen :: Export -> Export -> [Export]
enumFrom :: Export -> [Export]
$cenumFrom :: Export -> [Export]
fromEnum :: Export -> Int
$cfromEnum :: Export -> Int
toEnum :: Int -> Export
$ctoEnum :: Int -> Export
pred :: Export -> Export
$cpred :: Export -> Export
succ :: Export -> Export
$csucc :: Export -> Export
Enum)

type PageNumber = Int
type ViewNumber = Int

data MarkedView = All | OnlyMarkedViews
  deriving (Int -> MarkedView -> FilePath -> FilePath
[MarkedView] -> FilePath -> FilePath
MarkedView -> FilePath
(Int -> MarkedView -> FilePath -> FilePath)
-> (MarkedView -> FilePath)
-> ([MarkedView] -> FilePath -> FilePath)
-> Show MarkedView
forall a.
(Int -> a -> FilePath -> FilePath)
-> (a -> FilePath) -> ([a] -> FilePath -> FilePath) -> Show a
showList :: [MarkedView] -> FilePath -> FilePath
$cshowList :: [MarkedView] -> FilePath -> FilePath
show :: MarkedView -> FilePath
$cshow :: MarkedView -> FilePath
showsPrec :: Int -> MarkedView -> FilePath -> FilePath
$cshowsPrec :: Int -> MarkedView -> FilePath -> FilePath
Show,MarkedView -> MarkedView -> Bool
(MarkedView -> MarkedView -> Bool)
-> (MarkedView -> MarkedView -> Bool) -> Eq MarkedView
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: MarkedView -> MarkedView -> Bool
$c/= :: MarkedView -> MarkedView -> Bool
== :: MarkedView -> MarkedView -> Bool
$c== :: MarkedView -> MarkedView -> Bool
Eq,Int -> MarkedView
MarkedView -> Int
MarkedView -> [MarkedView]
MarkedView -> MarkedView
MarkedView -> MarkedView -> [MarkedView]
MarkedView -> MarkedView -> MarkedView -> [MarkedView]
(MarkedView -> MarkedView)
-> (MarkedView -> MarkedView)
-> (Int -> MarkedView)
-> (MarkedView -> Int)
-> (MarkedView -> [MarkedView])
-> (MarkedView -> MarkedView -> [MarkedView])
-> (MarkedView -> MarkedView -> [MarkedView])
-> (MarkedView -> MarkedView -> MarkedView -> [MarkedView])
-> Enum MarkedView
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
enumFromThenTo :: MarkedView -> MarkedView -> MarkedView -> [MarkedView]
$cenumFromThenTo :: MarkedView -> MarkedView -> MarkedView -> [MarkedView]
enumFromTo :: MarkedView -> MarkedView -> [MarkedView]
$cenumFromTo :: MarkedView -> MarkedView -> [MarkedView]
enumFromThen :: MarkedView -> MarkedView -> [MarkedView]
$cenumFromThen :: MarkedView -> MarkedView -> [MarkedView]
enumFrom :: MarkedView -> [MarkedView]
$cenumFrom :: MarkedView -> [MarkedView]
fromEnum :: MarkedView -> Int
$cfromEnum :: MarkedView -> Int
toEnum :: Int -> MarkedView
$ctoEnum :: Int -> MarkedView
pred :: MarkedView -> MarkedView
$cpred :: MarkedView -> MarkedView
succ :: MarkedView -> MarkedView
$csucc :: MarkedView -> MarkedView
Enum)

data NoZip = NoZip | Zip
  deriving (Int -> NoZip -> FilePath -> FilePath
[NoZip] -> FilePath -> FilePath
NoZip -> FilePath
(Int -> NoZip -> FilePath -> FilePath)
-> (NoZip -> FilePath)
-> ([NoZip] -> FilePath -> FilePath)
-> Show NoZip
forall a.
(Int -> a -> FilePath -> FilePath)
-> (a -> FilePath) -> ([a] -> FilePath -> FilePath) -> Show a
showList :: [NoZip] -> FilePath -> FilePath
$cshowList :: [NoZip] -> FilePath -> FilePath
show :: NoZip -> FilePath
$cshow :: NoZip -> FilePath
showsPrec :: Int -> NoZip -> FilePath -> FilePath
$cshowsPrec :: Int -> NoZip -> FilePath -> FilePath
Show,NoZip -> NoZip -> Bool
(NoZip -> NoZip -> Bool) -> (NoZip -> NoZip -> Bool) -> Eq NoZip
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: NoZip -> NoZip -> Bool
$c/= :: NoZip -> NoZip -> Bool
== :: NoZip -> NoZip -> Bool
$c== :: NoZip -> NoZip -> Bool
Eq,Int -> NoZip
NoZip -> Int
NoZip -> [NoZip]
NoZip -> NoZip
NoZip -> NoZip -> [NoZip]
NoZip -> NoZip -> NoZip -> [NoZip]
(NoZip -> NoZip)
-> (NoZip -> NoZip)
-> (Int -> NoZip)
-> (NoZip -> Int)
-> (NoZip -> [NoZip])
-> (NoZip -> NoZip -> [NoZip])
-> (NoZip -> NoZip -> [NoZip])
-> (NoZip -> NoZip -> NoZip -> [NoZip])
-> Enum NoZip
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
enumFromThenTo :: NoZip -> NoZip -> NoZip -> [NoZip]
$cenumFromThenTo :: NoZip -> NoZip -> NoZip -> [NoZip]
enumFromTo :: NoZip -> NoZip -> [NoZip]
$cenumFromTo :: NoZip -> NoZip -> [NoZip]
enumFromThen :: NoZip -> NoZip -> [NoZip]
$cenumFromThen :: NoZip -> NoZip -> [NoZip]
enumFrom :: NoZip -> [NoZip]
$cenumFrom :: NoZip -> [NoZip]
fromEnum :: NoZip -> Int
$cfromEnum :: NoZip -> Int
toEnum :: Int -> NoZip
$ctoEnum :: Int -> NoZip
pred :: NoZip -> NoZip
$cpred :: NoZip -> NoZip
succ :: NoZip -> NoZip
$csucc :: NoZip -> NoZip
Enum)

data PageRange = EntireFile
               | PageRange (Range PageNumber) -- ^ only closed ranges are supported.
               deriving (Int -> PageRange -> FilePath -> FilePath
[PageRange] -> FilePath -> FilePath
PageRange -> FilePath
(Int -> PageRange -> FilePath -> FilePath)
-> (PageRange -> FilePath)
-> ([PageRange] -> FilePath -> FilePath)
-> Show PageRange
forall a.
(Int -> a -> FilePath -> FilePath)
-> (a -> FilePath) -> ([a] -> FilePath -> FilePath) -> Show a
showList :: [PageRange] -> FilePath -> FilePath
$cshowList :: [PageRange] -> FilePath -> FilePath
show :: PageRange -> FilePath
$cshow :: PageRange -> FilePath
showsPrec :: Int -> PageRange -> FilePath -> FilePath
$cshowsPrec :: Int -> PageRange -> FilePath -> FilePath
Show,PageRange -> PageRange -> Bool
(PageRange -> PageRange -> Bool)
-> (PageRange -> PageRange -> Bool) -> Eq PageRange
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: PageRange -> PageRange -> Bool
$c/= :: PageRange -> PageRange -> Bool
== :: PageRange -> PageRange -> Bool
$c== :: PageRange -> PageRange -> Bool
Eq)

data Options = Options { Options -> Export
export     :: Export
                       , Options -> PageRange
pages      :: PageRange
                       , Options -> Maybe (Int, Int)
singleView :: Maybe (PageNumber,ViewNumber)
                       , Options -> MarkedView
markedView :: MarkedView
                       , Options -> Bool
runLatex   :: Bool
                       , Options -> NoZip
nozip      :: NoZip
                       } deriving (Int -> Options -> FilePath -> FilePath
[Options] -> FilePath -> FilePath
Options -> FilePath
(Int -> Options -> FilePath -> FilePath)
-> (Options -> FilePath)
-> ([Options] -> FilePath -> FilePath)
-> Show Options
forall a.
(Int -> a -> FilePath -> FilePath)
-> (a -> FilePath) -> ([a] -> FilePath -> FilePath) -> Show a
showList :: [Options] -> FilePath -> FilePath
$cshowList :: [Options] -> FilePath -> FilePath
show :: Options -> FilePath
$cshow :: Options -> FilePath
showsPrec :: Int -> Options -> FilePath -> FilePath
$cshowsPrec :: Int -> Options -> FilePath -> FilePath
Show,Options -> Options -> Bool
(Options -> Options -> Bool)
-> (Options -> Options -> Bool) -> Eq Options
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Options -> Options -> Bool
$c/= :: Options -> Options -> Bool
== :: Options -> Options -> Bool
$c== :: Options -> Options -> Bool
Eq)

defaultOptions :: Options
defaultOptions :: Options
defaultOptions = Export
-> PageRange
-> Maybe (Int, Int)
-> MarkedView
-> Bool
-> NoZip
-> Options
Options Export
RetainIpeInfo
                         PageRange
EntireFile
                         Maybe (Int, Int)
forall a. Maybe a
Nothing -- default : entire file
                         MarkedView
All
                         Bool
False
                         NoZip
Zip