#! /usr/bin/env python
# style_showcase.py
# -*- encoding: utf-8 -*-
"""Make an illustration of a LaTeX style on a sample document.
"""
__version__='1.0.0'
__author__='Jim Hefferon ftpmaint at tug.ctan.org'
__date__='2010-Feb-16'
__notes__="""
"""

import sys, os, os.path, re, optparse
import time, subprocess

DEFAULT_PLAIN_TEXT_FN='plain.text'
DEFAULT_MATH_TEXT_FN='math.text'

DEFAULT_TEMP_DIR='tmp'
DEFAULT_OUTPUT_FN_FORMAT='style_showcase.tex'
DEFAULT_OUTPUT_FN=DEFAULT_OUTPUT_FN_FORMAT  # ?could want % (0,)

DEBUG=False
FORGIVE=False
VERBOSE=False

DEFAULT_DOCUMENTCLASS='article'
DEFAULT_SIZE='10pt'
USEPACKAGE_LIST=None
MATHPACKAGE_LIST=None
EXTRA_LIST=None

DEFAULT_PLAIN_TEXT=r"""
\usepackage{lipsum}
\title{Cartesian closed categories and the price of eggs}
\author{Jane Doe}
\date{September 1994}

\lipsum[1-2]

\section{First section}
\lipsum[3-4]

\subsection{First subsection of first section}
\lipsum[5-7]

\subsection{Second subsection of first section}
\lipsum[8-9]


\section{Second section}
\lipsum[11]

\subsection{First subsection of second section}
\lipsum[12]
"""

DEFAULT_MATH_TEXT=r"""\begin{thm}
Quisque aliquam $x$ ipsum sed turpis.
Pellentesque $y\in K$ laoreet velit nec justo.
Nam sed augue.
Maecenas rutrum quam eu dolor.
\begin{equation}
 \int_5^6 x^2\,dx=A_{xt}
\end{equation}
Fusce consectetuer.
Proin tellus est, luctus vitae, molestie a, mattis et, mauris.
\begin{equation}\begin{split}
 H_c&=\frac{1}{2n} \sum^n_{l=0}(-1)^{l}(n-{l})^{p-2}
 \sum_{l _1+\dots+ l _p=l}\prod^p_{i=1} \binom{n_i}{l _i}\\
 &\quad\cdot[(n-l )-(n_i-l _i)]^{n_i-l _i}\cdot
 \Bigl[(n-l )^2-\sum^p_{j=1}(n_i-l _i)^2\Bigr].
\end{split}\end{equation}
Donec tempor.
Pellentesque habitant morbi tristique senectus et netus et malesuada
fames ac turpis egestas.
\end{thm}

\begin{proof}
Fusce adipiscing justo nec ante.
Nullam in enim.
\begin{equation*}
 \left.\begin{aligned}
 B'&=-\partial\times E,\\
 E'&=\partial\times B - 4\pi j
 \end{aligned}
 \right\}
 \qquad \text{Maxwell's equations}
\end{equation*}
Pellentesque felis orci, sagittis ac, malesuada et, facilisis in, ligula.
Nunc non magna sit amet mi aliquam dictum.
\begin{equation}
 \frac{1}{k}\log_2 c(f)\quad\tfrac{1}{k}\log_2 c(f)\quad
 \sqrt{\frac{1}{k}\log_2 c(f)}\quad\sqrt{\dfrac{1}{k}\log_2 c(f)}
\end{equation}
In mi.
\end{proof}

\lipsum[26]

\begin{defn}
Aenean adipiscing auctor est. Morbi quam
arcu, malesuada sed, volutpat et, elementum sit amet, libero. Duis
accumsan. Curabitur urna.
\begin{equation}
 \begin{pmatrix} a&b&c&d\\
 e&\hdotsfor{3} \end{pmatrix}
\end{equation}
In sed ipsum.
\end{defn}

\begin{lem}
Donec lobortis nibh.
Duis $x\in K_2$ mattis.
Sed cursus lectus quis odio.
Phasellus arcu.
Praesent imperdiet dui in sapien.
\end{lem}

\begin{proof}
Vestibulum tellus pede, auctor a, pellentesque sit amet, vulputate sed, purus.
\begin{align}
 A_1&=N_0(\lambda;\Omega')-\phi(\lambda;\Omega'),\\
 A_2&=\phi(\lambda;\Omega')-\phi(\lambda;\Omega),\\
 \intertext{and}
 A_3&=\mathcal{N}(\lambda;\omega).
\end{align}
Nunc pulvinar, dui at eleifend adipiscing, tellus nulla placerat massa,
sed condimentum nulla tellus sed ligula.
Nulla vitae odio sit amet leo imperdiet blandit.
In vel massa.
\begin{equation*}
 \sum_{\begin{subarray}{l}
       i\in\Lambda\\ 0<j<n
     \end{subarray}}
  P(i,j)
\end{equation*}
Maecenas varius dui at turpis.
Sed odio.
\end{proof}

\begin{thm}
Sed justo.
Maecenas lacinia, turpis sed commodo congue, odio urna elementum nunc,
vitae molestie velit nunc eu sem.
Maecenas enim.
\begin{equation}
 \displaystyle
 \sum_{\substack{0\le i\le m\\ 0<j<n}} P(i,j)
\end{equation}
Proin quis neque nec tortor sollicitudin volutpat.
\end{thm}

\begin{proof}
Sed at ante.
Sed vitae mauris non ante egestas hendrerit.
Cum sociis natoque penatibus et magnis dis parturient montes, nascetur
ridiculus mus.
\begin{equation}\label{xx}
 \begin{split}
 a& =b+c-d\\
  & \quad +e-f\\
  & =g+h\\
  & =i
 \end{split}
\end{equation}
\end{proof}

\begin{cor}
In venenatis $2\leq y,z\leq 5$ facilisis magna.
\begin{math}
 \bigl( \begin{smallmatrix}
   a&b\\ c&d
 \end{smallmatrix} \bigr)
\end{math}
Cras quis mauris.
Aliquam eget magna.
Donec rutrum sagittis mi.
Morbi elementum, est sit amet sollicitudin feugiat, orci magna semper risus,
eu congue nulla metus vel elit.
\end{cor}
"""

def write_to_fh(fh,
               documentclass=None,
               size=None,
               usepackage_list=None,
               mathpackage_list=None,
               extra_list=None,
               plain_text=None,
               math_text=None):
   """Put the text to the file object.
   """
   if documentclass is None:
       documentclass='article'
   if size is None:
       size='10pt'
   top=r"""\documentclass[%s]{%s}
%% This document generated by style_showcase.py by Jim Hefferon, on %s
\usepackage{lipsum}
""" % (size,documentclass,time.asctime())
   fh.write(top)
   if usepackage_list is None:
       usepackage_list=[]
   for package in usepackage_list:
       package_line="""
\usepackage{%s}
""" % (package,)
       fh.write(package_line)
   if not(mathpackage_list is None):
       for package in mathpackage_list:
           if package:
               package_line="""
\usepackage{%s}
""" % (package,)
           fh.write(package_line)
   else:
       fh.write(r"\usepackage{amsmath,amsthm}")
       fh.write(r"""\theoremstyle{plain}
\newtheorem{thm}{Theorem}[section]
\newtheorem{lem}[thm]{Lemma}
\newtheorem{cor}[thm]{Corollary}
\theoremstyle{definition}
\newtheorem{defn}[thm]{Definition}
""")
   if extra_list is None:
       extra_list=[]
   for extra in extra_list:
       extra_line=r"""
%s
""" % (extra,)
       fh.write(extra_line)
   if plain_text is None:
       plain_text=DEFAULT_PLAIN_TEXT
   if math_text is None:
       math_text=DEFAULT_MATH_TEXT
   # Put in the text body
   fh.write(r"""\title{Cartesian closed categories and the price of eggs}
\author{Jane Doe}
\date{September 1994}

\begin{document}
\maketitle
""")
   fh.write(plain_text)
   fh.write(math_text)
   fh.write(r"\end{document}")

def write_to_file(fn,
                 temp_dir,
                 documentclass=None,
                 size=None,
                 usepackage_list=None,
                 mathpackage_list=None,
                 extra_list=None,
                 plain_text=None,
                 math_text=None):
   """Write the text to the given file name, in the directory temp_dir.
   """
   fh=open(temp_dir+os.sep+fn,'w')
   write_to_fh(fh,
               documentclass=documentclass,
               size=size,
               usepackage_list=usepackage_list,
               mathpackage_list=mathpackage_list,
               extra_list=extra_list,
               plain_text=plain_text,
               math_text=math_text)
   fh.close()


def syscall(s):
   """Run the system call
   s  string
   """
   mesg='while running '+repr(s)
   retcode = subprocess.check_call(s,shell=True)
   if retcode < 0:
       raise Exception, mesg+': unexpected return code '+repr(retcode)

def compile_file(fn,temp_dir):
   cwd=os.getcwd()
   os.chdir(temp_dir)
   syscall('pdflatex '+fn)
   syscall('pdflatex '+fn)
   os.chdir(cwd)

def convert_to_png(fn,temp_dir):
   """Convert the .pdf file to two flavors of .png: one like fn_small.png.0
   and the other without the '_small'.
   """
   fn=fn[:-len('.tex')]
   cwd=os.getcwd()
   os.chdir(temp_dir)
   try: # extra .png's from prior runs can fool you
       syscall("rm *.png.*")
   except: # no such files found
       pass
   syscall('convert -geometry 20% '+fn+'.pdf '+fn+'.png')
   for x in range(0,10):
       try:
           syscall('mv '+fn+'.png.'+str(x)+' '+fn+'_small.png.'+str(x))
       except:
           break
   syscall('convert -contrast '+fn+'.pdf '+fn+'.png')
   os.chdir(cwd)

def cleanup(fn,temp_dir):
   """Erase .log files, etc.
   """
   fn=fn[:-len('.tex')]
   cwd=os.getcwd()
   os.chdir(temp_dir)
   for ext in ['.aux','.log','.aux']:
       try:
           syscall('rm '+fn+ext)
       except:
           pass
   os.chdir(cwd)

def generate_sample(fn,
                   temp_dir,
                   documentclass=None,
                   size=None,
                   usepackage_list=None,
                   mathpackage_list=None,
                   extra_list=None,
                   plain_text=None,
                   math_text=None):
   """Generate the sample page.
     fn  string  Name of the .tex file
     temp_dir  string  Subdir where the output goes
     documentclass=None string  LaTeX document class
     size=None  string  Point size of main body text
     usepackage_list=None  list of strings  The packages that will be used in
       the LaTeX document
     mathpackage_list=None  list of strings  The math packages used.
     extra_list=None  list of strings  Extra lines to enter in the .tex
       file.
     plain_text=None  string  Used as the body of the document
     math_text=None  string  Used as the body of the document containing math
   """
   if not(os.path.isdir(temp_dir)):
       os.mkdir(temp_dir)
   write_to_file(fn,
                 temp_dir,
                 documentclass=documentclass,
                 size=size,
                 usepackage_list=usepackage_list,
                 mathpackage_list=mathpackage_list,
                 extra_list=extra_list,
                 plain_text=plain_text,
                 math_text=math_text)
   compile_file(fn,temp_dir)
   convert_to_png(fn,temp_dir)
   cleanup(fn,temp_dir)



#......................................................................
def main(argv=None):
   """The main logic if called from the command line
     argv=None  The arguments to the routine
   """
   # Set the defaults
   if argv is None:
       argv=sys.argv
   # Parse the arguments
   #   First, define all options
   usage="""Illustrate an article style by LaTeX-ing a test document
 %prog  [options] <optional plain text filename> <optional math text filename>
The <filename>s can contain text to set as part of the document."""
   oP=optparse.OptionParser(usage=usage,version=__version__)
   oP.add_option('--output_file','-o',action='store',default=DEFAULT_OUTPUT_FN,dest='output_file',help='Output filename (default: %s)' % (DEFAULT_OUTPUT_FN,))
   oP.add_option('--temp_dir','-t',action='store',default=DEFAULT_TEMP_DIR,dest='temp_dir',help='Directory for output (default: %s)' % (DEFAULT_TEMP_DIR,))
   oP.add_option('--documentclass','-d',action='store',default=DEFAULT_DOCUMENTCLASS,dest='documentclass',help='LaTeX document class (default: %s)' % (DEFAULT_DOCUMENTCLASS,))
   oP.add_option('--size','-s',action='store',default=DEFAULT_SIZE,dest='size',help='Point size of main text (default: %s)' % (DEFAULT_SIZE,))
   oP.add_option('--usepackage','-u',action='append',default=USEPACKAGE_LIST,dest='usepackage_list',help='Use the LaTeX package (default: %s)' % (USEPACKAGE_LIST,))
   oP.add_option('--mathpackage','-m',action='append',default=MATHPACKAGE_LIST,dest='mathpackage_list',help='Use the LaTeX math package (default: %s)' % (MATHPACKAGE_LIST,))
   oP.add_option('--extra','-e',action='append',default=EXTRA_LIST,dest='extra_list',help=' (default: %s)' % (MATHPACKAGE_LIST,))
#     oP.add_option('--DEBUG','-D',action='store_true',default=DEBUG,dest='debug',help='output debugging information (default %s)' % (DEBUG,))
#     oP.add_option('--FORGIVE','-F',action='store_true',default=FORGIVE,dest='forgive',help='continue on failure (default: %s)' % (repr(FORGIVE),))
#     oP.add_option('--VERBOSE','-V',action='store_true',default=VERBOSE,dest='verbose',help='talk a lot (default %s)' % (VERBOSE,))
   opts, args=oP.parse_args(argv[1:])
   # Establish the infrastructure
   # Handle positional arguments
   try:
       plain_text_fn=args[0]
   except:
       plain_text_fn=DEFAULT_PLAIN_TEXT_FN
   plain_text=open(plain_text_fn,'r').read()
   try:
       math_text_fn=args[1]
   except:
       math_text_fn=DEFAULT_MATH_TEXT_FN
   math_text=open(math_text_fn,'r').read()
   # Handle the options
   generate_sample(opts.output_file,
                   opts.temp_dir,
                   documentclass=opts.documentclass,
                   size=opts.size,
                   usepackage_list=opts.usepackage_list,
                   mathpackage_list=opts.mathpackage_list,
                   extra_list=opts.extra_list,
                   plain_text=plain_text,
                   math_text=math_text)


if __name__=='__main__':
   if __notes__.strip():
       util.stdout("Notes for "+__file__+":\n"+__notes__)
   try:
       main(argv=sys.argv)
   except KeyboardInterrupt:
       mesg=sys.argv[0]+u": Keyboard interrupt"
       print >>2, mesg
   sys.exit(0)