-- | Platform dependent previewing of PDF files. On Windows, we try to
-- run Acrobat Reader. On Mac, we try to run Preview. On Linux, we try
-- to run Acrobat Reader or Xpdf. If this fails, we abort the program
-- with a platform dependent error message.

module Quipper.Utils.Preview where

import Control.Exception
import System.Environment
import System.Exit
import System.Info
import System.IO
import System.IO.Error
import System.Process

-- | Sequentially try one or more IO computations, until one of them
-- completes without an IO error. If all of them fail, re-throw the
-- error from the last one.
try_several_IO :: [IO a] -> IO a
try_several_IO [] = error "try_several_IO"
try_several_IO [h] = do
  catchIOError h (\e -> throw e)
try_several_IO (h:t) = do
  catchIOError h (\e -> try_several_IO t)

-- | @'system_pdf_viewer' zoom pdffile@: Call a system-specific PDF
-- viewer on /pdffile/ file. The /zoom/ argument is out of 100 and may
-- or may not be ignored by the viewer.
system_pdf_viewer :: Double -> String -> IO ()
system_pdf_viewer zoom pdffile = do
  envList <- getEnvironment
  if (elem ("OS", "Windows_NT") envList) then
    windows_pdf_viewer zoom pdffile
    else if (os == "darwin") then
    macos_pdf_viewer zoom pdffile
    else
    linux_pdf_viewer zoom pdffile

-- | Like 'system_pdf_viewer', but specialized to Windows.
windows_pdf_viewer :: Double -> String -> IO ()
windows_pdf_viewer zoom pdffile = catchIOError body handler
  where
    body = do
      r <- system ("start /WAIT AcroRd32 " ++ pdffile)
      case r of
        ExitSuccess -> return ()
        ExitFailure n -> acrord32_error n
    handler e = do
      name <- getProgName
      hPutStrLn stderr $ name ++ ": unable to preview PDF file. Please ensure that Acrobat Reader is installed."
      exitFailure
    acrord32_error n = do
      name <- getProgName
      hPutStrLn stderr $ name ++ ": unable to preview PDF file. Please ensure that Acrobat Reader is installed."
      exitFailure
      

-- | Like 'system_pdf_viewer', but specialized to Mac OS.
macos_pdf_viewer :: Double -> String -> IO ()
macos_pdf_viewer zoom pdffile = catchIOError body handler
  where
    body = do
      rawSystem "open" [pdffile]
      rawSystem "sleep" ["1"] -- required or the file may be deleted too soon
      return ()
    handler e = do
      name <- getProgName
      hPutStrLn stderr $ name ++ ": unable to preview PDF file. There seems to be a problem with Preview."
      exitFailure
      
-- | Like 'system_pdf_viewer', but specialized to Linux.
linux_pdf_viewer :: Double -> String -> IO ()
linux_pdf_viewer zoom pdffile = catchIOError body handler
  where
    body = do
      try_several_IO [
        rawSystem "acroread" ["/a", "zoom=" ++ show zoom, pdffile],
        rawSystem "xpdf" ["-z", show zoom, pdffile]
        ]
      return ()
    handler e = do
      name <- getProgName
      hPutStrLn stderr $ name ++ ": unable to preview PDF file. Please ensure that either Acrobat Reader or Xpdf are installed."
      exitFailure