#!/bin/bash /home/richmit/bin/ruby
# -*- Mode:Ruby; Coding:us-ascii-unix; fill-column:160 -*-

################################################################################################################################################################
##
# @file      latexit.rb
# @author    Mitch Richling <https://www.mitchr.me/>
# @Copyright Copyright 2010,2011 by Mitch Richling.  All rights reserved.
# @brief     Typeset a snippet of LaTeX, and display it.@EOL
# @Std       Ruby 1.8
# @license
#
# ================================================================================================================================================================
# Copyright (c) 1994-2015, Mitchell Jay Richling <https://www.mitchr.me> All rights reserved.
# 
# Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
# 
# 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer.
# 
# 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation and/or
#    other materials provided with the distribution.
# 
# 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without
#    specific prior written permission.
# 
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# ================================================================================================================================================================
#
# @Notes
#
# Feed it LaTeX code via STDIN or as the first unrecognized argument, and it will typeset it, crop it, and display it on
# the screen.
#
#   Three step flow:  
#      0) read it 
#      1) typeset it  
#      2) crop it     
#      3) display it  (-s3)
#
# The ideal tool chain for steps 1-3) varies by platform:
#      Linux     -- pdflatex, pdfcrop, & xpdf.
#      MacOS X   -- xpdf may be replaced with Preview (via open).  
#      Old UNIX  -- latex, dvips, & gv.  
#
# The script makes an attempt to guess the best tool chain from what is available on the platform.  The last step may be
# skipped via -s3.
#
# I normally use this script inside Emacs.  A tiny elisp wrapper allows me to highlight a bit of LaTeX and then fed to
# this script for display.  Emacs rocks!
#            
################################################################################################################################################################

#---------------------------------------------------------------------------------------------------------------------------------------------------------------
possibleFlows = [[['pdflatex: pdflatex %FILE%.tex'],                                 # If we don't use LaTeX standalone, then we have a crop step
                  ["pdfcrop: /bin/sh -c 'pdfcrop %FILE%.pdf %FILE%-c.pdf'"],
                  ['xpdf: xpdf -fullscreen -z page %FILE%-c.pdf', 
                   'evince: evince -s %FILE%-c.pdf', 
                   'okular: okular --presentation %FILE%-c.pdf', 
                   'acroread: acroread %FILE%-c.pdf', 
                   'open: open %FILE%-c.pdf']],
                 [['latex: latex %FILE%.tex'],
                  ['dvips: dvips -E -o %FILE%.eps %FILE%.dvi'],             
                  ['gv: gv -presentation %FILE%.eps', 
                   #'gv: gv `xwininfo -root | grep .-geometry` -antialias %FILE%.eps', 
                   'ghostview: ghostview %FILE%.eps']],
                 [['pdflatex: pdflatex %FILE%.tex'], 
                  ['xpdf: xpdf -geometry 1000x300 -z page %FILE%.pdf',
                   'acroread: acroread %FILE%.pdf', 
                   'open: open %FILE%.pdf']],
                 [['latex: latex %FILE%.tex'], 
                  ['xdvi: xdvi %FILE%.dvi']]
                ];

#---------------------------------------------------------------------------------------------------------------------------------------------------------------
cmdLineCmds = Hash.new(nil)
skipSteps   = Hash.new(nil)
doDoxygen   = TRUE
while ( !(ARGV.empty?) && (tmp = ARGV[0].match(/^-+([cs])([0-9]+)/))) do
  optn = tmp[1]
  step = tmp[2].to_i
  #puts("OPTN: #{optn}  STEP: #{step}")
  ARGV.shift
  if    (optn == 'c') then
    cmdLineCmds[step] = ARGV.shift
    STDERR.puts("ERROR(latexit.rb): The -c option is not yet supported")
    exit
  elsif (optn == 's') then
    skipSteps[step] = 1
    if(step != 3) then
      STDERR.puts("ERROR(latexit.rb): The -s option is only supported with step 3")
      exit
    end
  end
end

#---------------------------------------------------------------------------------------------------------------------------------------------------------------
cleanFlow = Array.new
cleanFlowPath = Array.new
possibleFlows.each do |flow|
  goodFlow = true
  flow.each do |flowStep|
    cleanFlowStep = nil
    flowStep.each do |stepOption|
      tmp = stepOption.match(/^([^:]+):/);
      tool = tmp[1]
      ENV['PATH'].split(':').each do |pathComp|
        posBin = pathComp + '/' + tool
        if (FileTest.exist?(posBin)) then
          cleanFlowStep = posBin
          break
        end
      end
      if (cleanFlowStep) then
        cleanFlow.push(stepOption)
        cleanFlowPath.push(cleanFlowStep)
        break
      else
        puts("WARNING: Results may be substandard.  Missing tool: #{tool}")
      end
    end
    if ( !(cleanFlowStep)) then
      cleanFlow     = Array.new
      cleanFlowPath = Array.new
      goodFlow = false
      break
    end
    if !(goodFlow) then
      break
    end
  end
  if (goodFlow) then
    break
  end
end

#---------------------------------------------------------------------------------------------------------------------------------------------------------------
if ( cleanFlow.empty?) then
  puts("Could not find enough tools to work!")
else
  fileName = 'temp'

  Dir.chdir('/tmp/')

  system("rm -f /tmp/#{fileName}.pdf")
  system("rm -f /tmp/#{fileName}.tex")
  system("rm -f /tmp/#{fileName}.aux")
  system("rm -f /tmp/#{fileName}.log")
  system("rm -f /tmp/#{fileName}.pdf")
  system("rm -f /tmp/#{fileName}-p.pdf")

  doubleSlashMode = 'auto'
  lineZapRE = {/^\s*(\/\/)+\s*/ => 0,  # c99, c++
               /^\s*#+\s*/      => 0,  # sh, R, perl, ruby
               /^\s*\!+\s*/     => 0,  # F90, F95, F03, F08
               /^\s*C+\s*/      => 0,  # F77
               /^\s*;+\s*/      => 0}  # lisp, elisp

  puts("GENERATING TEX...")
  open("#{fileName}.tex", "w") do |file|
    #file.puts('\documentclass{standalone} \usepackage{amssymb} \usepackage{amsmath} \begin{document} \pagestyle{empty} \setlength{\parindent}{0pt} \setlength{\parskip}{10pt} ')
    file.puts('\documentclass{article}    \usepackage[paperwidth=25in,paperheight=20in]{geometry} \usepackage{amssymb} \usepackage{amsmath} \begin{document} \pagestyle{empty} \setlength{\parindent}{0pt} \setlength{\parskip}{10pt} \begin{minipage}{7in} \setlength{\parindent}{0pt} \setlength{\parskip}{2ex plus 0.5ex minus 0.2ex} ')
    if ( (ARGV[0].nil?) || (ARGV[0]=='-') ) then
      lineArray = STDIN.readlines()
      # Figure out which prefixes are on all lines.  Figure out if all \ chars appear in pairs if doubleSlashMode==auto
      lineCount = 0
      checkDoubleSlashes = (doubleSlashMode == 'auto')
      if checkDoubleSlashes then
        doubleSlashMode = true
      end
      lineArray.each do |line|
        lineZapRE.each_key do |theRe|
          if ( (line.match(theRe)) || (line.match(/^\s*$/))) then
            lineZapRE[theRe] += 1
          end
        end
        line.scan(/\\+/) do |tok|
          if ( (tok.length % 2) != 0) then
            checkDoubleSlashes = false
            doubleSlashMode    = false
          end
        end
        lineCount += 1
      end
      zapRE = nil
      lineZapRE.each do |theRe, lCnt|
        if (lineCount == lCnt) then
          zapRE = theRe
        end
      end
      # Process each line, and push into TeX file
      lineArray.each do |line|
        if (zapRE) then
          line = line.sub(zapRE, '')
        end
        if (doubleSlashMode) then
          line = line.gsub('\\\\', '\\')
        end
        if(doDoxygen) then
          line = line.gsub(/[@\\]f\$/, '$')
          line = line.gsub(/[@\\]f[\[\]]/, '$$')
        end
        file.puts(line)
      end
    else
      file.puts(ARGV[0])
    end
    #file.puts('\end{document}')
    file.puts('\end{minipage} \end{document}')
  end

  # execute flow: Render, crop, and view
  step = 1
  cleanFlow.each_with_index do |commandAndLine, index|
    if ( !(skipSteps.member?(step))) then
      commandPath = cleanFlowPath[index]
      command, commandLine = commandAndLine.split(/:\s+/, 2)
      puts("FLOW STEP: #{step} COMMAND: #{command.inspect}")
      system(commandLine.gsub(command, commandPath).gsub('%FILE%', 'temp'))
    end
    step += 1
  end
end