{- Tex.Join
Gregory W. Schwartz

Collects the functions pertaining to the joining and compiling of separate tex
files.
-}

{-# LANGUAGE OverloadedStrings #-}

module Tex.Join
  ( joinTex
  ) where

-- Remote
import System.Environment (getArgs)
import System.IO (openTempFile, hClose)
import Turtle
import qualified Control.Concurrent.Async as A
import qualified Control.Foldl as Fold
import qualified Data.Set as Set
import qualified Data.Text as T
import qualified Filesystem.Path as FP

-- Local


newtype BibFile = BibFile { unBibFile :: FP.FilePath }

-- | Export the file to latex. Not used due as there is no simple way to have
-- custom configuration seemingly.
exportFileOrg :: FP.FilePath -> IO ()
exportFileOrg file = procs
                       "emacs"
                       [ format fp file
                       , "--batch"
                       , "-l", "~/.emacs.d/init.el"
                       , "--eval", "(run-hooks 'emacs-startup-hook)"
                       , "--eval", "(setq org-latex-logfiles-extensions (quote (\"lof\" \"lot\" \"tex~\" \"aux\" \"idx\" \"out\" \"toc\" \"nav\" \"snm\" \"vrb\" \"dvi\" \"fdb_latexmk\" \"blg\" \"brf\" \"fls\" \"entoc\" \"ps\" \"spl\" \"bbl\" \"xml\" \"run.xml\" \"blg\" \"cb\" \"cb2\")))"
                       , "--eval", "(org-mode)"
                       , "--eval", "(org-latex-export-to-pdf)"
                       , "--kill"
                       ]
                       mempty

-- | Export the file to latex.
exportFileTex :: FP.FilePath -> IO ()
exportFileTex file = procs
                       "latexmk"
                       [ "-pdf"
                       , format fp file
                       ]
                       mempty

-- | Get the biber bib file from the tex file.
runBiber :: FP.FilePath -> IO ()
runBiber file = procs
                  "biber"
                  [ format fp . FP.dropExtension $ file
                  , "--output-format", "bibtex"
                  ]
                  mempty

-- | Get biber output name.
toBiberFile :: FP.FilePath -> FP.FilePath
toBiberFile =
  fromText . flip mappend "_biber.bib" . format fp . FP.dropExtension

-- | Replace a bibresource line.
replaceBibresource :: T.Text -> Pattern T.Text
replaceBibresource bib = (text "addbibresource{" <> plus (notChar '}'))
                      *> pure ("addbibresource{" <> bib)

-- | Re-export with new bib, returning pdf.
finalExport :: BibFile -> FP.FilePath -> IO [FP.FilePath]
finalExport (BibFile bib) file = reduce Fold.list $ do
  tmp <- mktempfile "." (format fp file)

  output tmp
    . sed (text "\\begin{document}" *> pure "\\begin{document}\n\\nocite{*}")
    . sed (replaceBibresource $ format fp bib)
    . input
    $ file

  liftIO $ exportFileTex tmp

  -- Clean up
  procs "latexmk" ["-c", format fp tmp] mempty

  return $ FP.replaceExtension tmp "pdf"

-- | Re-export with new bib, returning pdf.
bibliographyExport :: BibFile -> IO ()
bibliographyExport (BibFile bib) = sh $ do
  let bibliographyFile = FP.replaceExtension bib "tex"
      contents = [ "\\documentclass{article}"
                 , "\\usepackage[utf8]{inputenc}"
                 , "\\usepackage[T1]{fontenc}"
                 , "\\usepackage{helvet}"
                 , "\\renewcommand{\\familydefault}{\\sfdefault}"
                 , "\\usepackage{microtype}"
                 , "\\usepackage[left=0.5in, right=0.5in, top=0.5in, bottom=0.5in]{geometry}"
                 , "\\usepackage[citestyle=nature,bibstyle=nature,date=year,firstinits=true,sorting=none,url=false,doi=false,isbn=false,eprint=false,maxbibnames=5]{biblatex}"
                 , "\\addbibresource{" <> format fp bib <> "}"
                 , "\\begin{document}"
                 , "\\nocite{*}"
                 , "\\printbibliography"
                 , "\\end{document}"
                 ]

  output bibliographyFile . toLines . select $ contents

  liftIO $ exportFileTex bibliographyFile

  -- Clean up
  procs "latexmk" ["-c", format fp bibliographyFile] mempty

joinTex :: FP.FilePath -> [FP.FilePath] -> IO ()
joinTex out files = sh $ do
  -- Export files
  liftIO $ A.mapConcurrently_ exportFileTex files

  -- Run biber on files
  liftIO $ A.mapConcurrently_ runBiber files

  -- Combine files, order is important.
  let bibFile = BibFile
              . fromText
              . (<> "_references.bib")
              . format fp
              . FP.dropExtension
              $ out
  output (unBibFile bibFile) . cat . fmap (input . toBiberFile) $ files

  -- Export final files
  pdfs <- fmap mconcat . liftIO . A.mapConcurrently (finalExport bibFile) $ files

  -- Combine into a single pdf
  procs "pdfjam"
    ( ["--paper", "letterpaper"]
   <> fmap (format fp) pdfs
   <> ["-o", format fp out]
    )
    mempty

  -- Export bibliography
  liftIO $ bibliographyExport bibFile

  -- Cleanup
  rmFiles <- fmap (Set.toList . Set.fromList . mconcat)
           . reduce Fold.list
           $ mapM (flip find "." . contains . text . format fp . FP.dropExtension) pdfs
  mapM_ rm rmFiles