# -*- coding: utf-8 -*-
# See LICENSE.txt for licensing terms

'''
inkscape.py is an rst2pdf extension (e.g. rst2pdf -e inkscape xxx xxxx)
which uses the inkscape program to convert an svg to a PDF, then uses
the vectorpdf code to process the PDF.

.. NOTE::

    The initial version is a proof of concept; uses subprocess in a naive way,
    and doesn't check return from inkscape for errors.
'''

import sys, os, tempfile, subprocess
from weakref import WeakKeyDictionary
from rst2pdf.log import log

from vectorpdf_r2p import VectorPdf
import rst2pdf.image


if sys.platform.startswith('win'):
    # note: this is the default "all users" install location,
    # we might want to provide an option for this
    progname = os.path.expandvars(r'$PROGRAMFILES\Inkscape\inkscape.exe')
else:
    progname = 'inkscape'

class InkscapeImage(VectorPdf):

    # The filecache allows us to only read a given PDF file once
    # for every RstToPdf client object.  This allows this module
    # to usefully cache, while avoiding being the cause of a memory
    # leak in a long-running process.

    source_filecache = WeakKeyDictionary()

    @classmethod
    def available(self):
        return True

    def __init__(self, filename, width=None, height=None, kind='direct',
                                 mask=None, lazy=True, srcinfo=None):
        client, uri = srcinfo
        cache = self.source_filecache.setdefault(client, {})
        pdffname = cache.get(filename)
        if pdffname is None:
            tmpf, pdffname = tempfile.mkstemp(suffix='.pdf')
            os.close(tmpf)
            client.to_unlink.append(pdffname)
            cache[filename] = pdffname
            # which version of inkscape?
            cmd = [progname, '--version']
            exitcode, out, err = InkscapeImage.run_cmd(cmd)
            if out.startswith('Inkscape 0.'):
                # Inkscape 0.x uses -A
                cmd = [progname, os.path.abspath(filename), '-A', pdffname]
            else:
                # Inkscape 1.x uses --export-filename
                cmd = [progname, os.path.abspath(filename), '--export-filename=%s' % pdffname]
            try:
                result = subprocess.call(cmd)
                if result != 0:
                    log.error("Failed to run command: %s", ' '.join(cmd))
            except OSError:
                log.error("Failed to run command: %s", ' '.join(cmd))
                raise
            self.load_xobj((client, pdffname))

        pdfuri = uri.replace(filename, pdffname)
        pdfsrc = client, pdfuri
        VectorPdf.__init__(self, pdfuri, width, height, kind, mask, lazy, pdfsrc)

    @classmethod
    def raster(self, filename, client):
        """Returns a URI to a rasterized version of the image"""
        cache = self.source_filecache.setdefault(client, {})
        pngfname = cache.get(filename+'_raster')
        if pngfname is None:
            tmpf, pngfname = tempfile.mkstemp(suffix='.png')
            os.close(tmpf)
            client.to_unlink.append(pngfname)
            cache[filename+'_raster'] = pngfname
            # which version of inkscape?
            cmd = [progname, '--version']
            exitcode, out, err = InkscapeImage.run_cmd(cmd)
            if out.startswith('Inkscape 0.'):
                # Inkscape 0.x uses -A
                cmd = [progname, os.path.abspath(filename), '-e', pngfname, '-d', str(client.def_dpi)]
            else:
                # Inkscape 1.x uses --export-filename
                cmd = [progname, os.path.abspath(filename), '--export-filename=%s' % pngfname, '-d', str(client.def_dpi)]
            try:
                subprocess.call(cmd)
                return pngfname
            except OSError:
                log.error("Failed to run command: %s", ' '.join(cmd))
                raise
        return None

    @staticmethod
    def run_cmd(cmd):
        """
        Execute a command and return exitcode, stdout and stderr.
        """
        proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        out, err = proc.communicate()
        exitcode = proc.returncode
        return exitcode, out.decode(), err.decode()

def install(createpdf, options):
    ''' Monkey-patch our class in to image as a replacement class for SVGImage.
    '''
    rst2pdf.image.SVGImage = InkscapeImage
