"""A special directive for including a matplotlib plot.

Given a path to a .py file, it includes the source code inline, then:

- On HTML, will include a .png with a link to a high-res .png.

- On LaTeX, will include a .pdf

This directive supports all of the options of the `image` directive,
except for `target` (since plot will add its own target).

Additionally, if the :include-source: option is provided, the literal
source will be included inline, as well as a link to the source.
"""

import sys, os, glob, shutil
from docutils.parsers.rst import directives

try:
    # docutils 0.4
    from docutils.parsers.rst.directives.images import align
except ImportError:
    # docutils 0.5
    from docutils.parsers.rst.directives.images import Image
    align = Image.align


import matplotlib
import IPython.Shell
matplotlib.use('Agg')
import matplotlib.pyplot as plt

mplshell = IPython.Shell.MatplotlibShell('mpl')

options = {'alt': directives.unchanged,
           'height': directives.length_or_unitless,
           'width': directives.length_or_percentage_or_unitless,
           'scale': directives.nonnegative_int,
           'align': align,
           'class': directives.class_option,
           'include-source': directives.flag }

template = """
.. htmlonly::

   [`source code <../%(srcdir)s/%(basename)s.py>`__,
   `png <../%(srcdir)s/%(basename)s.hires.png>`__,
   `pdf <../%(srcdir)s/%(basename)s.pdf>`__]

   .. image:: ../%(srcdir)s/%(basename)s.png
%(options)s

.. latexonly::
   .. image:: ../%(srcdir)s/%(basename)s.pdf
%(options)s

"""

def makefig(fullpath, outdir):
    """
    run a pyplot script and save the low and high res PNGs and a PDF in _static
    """

    fullpath = str(fullpath)  # todo, why is unicode breaking this
    formats = [('png', 100),
               ('hires.png', 200),
               ('pdf', 72),
               ]

    basedir, fname = os.path.split(fullpath)
    basename, ext = os.path.splitext(fname)
    all_exists = True

    if basedir != outdir:
        shutil.copyfile(fullpath, os.path.join(outdir, fname))

    for format, dpi in formats:
        outname = os.path.join(outdir, '%s.%s' % (basename, format))
        if not os.path.exists(outname):
            all_exists = False
            break

    if all_exists:
        print '    already have %s'%fullpath
        return

    print '    building %s'%fullpath
    plt.close('all')    # we need to clear between runs
    matplotlib.rcdefaults()

    mplshell.magic_run(fullpath)
    for format, dpi in formats:
        outname = os.path.join(outdir, '%s.%s' % (basename, format))
        if os.path.exists(outname): continue
        plt.savefig(outname, dpi=dpi)

def run(arguments, options, state_machine, lineno):
    reference = directives.uri(arguments[0])
    basedir, fname = os.path.split(reference)
    basename, ext = os.path.splitext(fname)

    # todo - should we be using the _static dir for the outdir, I am
    # not sure we want to corrupt that dir with autogenerated files
    # since it also has permanent files in it which makes it difficult
    # to clean (save an rm -rf followed by and svn up)
    srcdir = 'pyplots'

    makefig(os.path.join(srcdir, reference), srcdir)

    # todo: it is not great design to assume the makefile is putting
    # the figs into the right place, so we may want to do that here instead.

    if options.has_key('include-source'):
        lines = ['.. literalinclude:: ../pyplots/%(reference)s' % locals()]
        del options['include-source']
    else:
        lines = []

    options = ['      :%s: %s' % (key, val) for key, val in
               options.items()]
    options = "\n".join(options)

    lines.extend((template % locals()).split('\n'))

    state_machine.insert_input(
        lines, state_machine.input_lines.source(0))
    return []


try:
    from docutils.parsers.rst import Directive
except ImportError:
    from docutils.parsers.rst.directives import _directives

    def plot_directive(name, arguments, options, content, lineno,
                       content_offset, block_text, state, state_machine):
        return run(arguments, options, state_machine, lineno)
    plot_directive.__doc__ = __doc__
    plot_directive.arguments = (1, 0, 1)
    plot_directive.options = options

    _directives['plot'] = plot_directive
else:
    class plot_directive(Directive):
        required_arguments = 1
        optional_arguments = 0
        final_argument_whitespace = True
        option_spec = options
        def run(self):
            return run(self.arguments, self.options,
                       self.state_machine, self.lineno)
    plot_directive.__doc__ = __doc__

    directives.register_directive('plot', plot_directive)

