#!/usr/bin/env python
'''
svg_and_media_zip_output.py
An extention which collects all images to the documents directory and
creates a zip archive containing all images and the document

Copyright (C) 2005 Pim Snel, pim@lingewoud.com
Copyright (C) 2008 Aaron Spike, aaron@ekips.org
Copyright (C) 2011 Nicolas Dufour, nicoduf@yahoo.fr
    * Fix for a bug related to special caracters in the path (LP #456248).
    * Fix for Windows support (LP #391307 ).
    * Font list and image directory features.

this is  the first Python script  ever created
its based on embedimage.py

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

TODOs
- fix bug: not saving existing .zip after a Collect for Output is run
     this bug occurs because after running an effect extention the inkscape:output_extension is reset to svg.inkscape
     the file name is still xxx.zip. after saving again the file xxx.zip is written with a plain .svg which
     looks like a corrupt zip
- maybe add better extention
- consider switching to lzma in order to allow cross platform compression with no encoding problem...
'''

import inkex
import urlparse
import urllib
import os, os.path
import string
import zipfile
import shutil
import sys
import tempfile
import simplestyle
import gettext
import locale
locale.setlocale(locale.LC_ALL, '')
_ = gettext.gettext

class CompressedMediaOutput(inkex.Effect):
    def __init__(self):
        inkex.Effect.__init__(self)
        if os.name == 'nt':
            self.encoding = "cp437"
        else:
            self.encoding = "latin-1"
        self.text_tags = ['{http://www.w3.org/2000/svg}tspan',
                            '{http://www.w3.org/2000/svg}text',
                            '{http://www.w3.org/2000/svg}flowRoot',
                            '{http://www.w3.org/2000/svg}flowPara',
                            '{http://www.w3.org/2000/svg}flowSpan']
        self.OptionParser.add_option("--image_dir",
                                     action="store", type="string",
                                     dest="image_dir", default="",
                                     help="Image directory")
        self.OptionParser.add_option("--font_list",
                                     action="store", type="inkbool",
                                     dest="font_list", default=False,
                                     help="Add font list")
        self.OptionParser.add_option("--tab",
                                     action="store", type="string",
                                     dest="tab",
                                     help="The selected UI-tab when OK was pressed")

    def output(self):
        '''
        Writes the temporary compressed file to its destination
        and removes the temporary directory.
        '''
        out = open(self.zip_file,'rb')
        if os.name == 'nt':
            try:
                import msvcrt
                msvcrt.setmode(1, os.O_BINARY)
            except:
                pass
        sys.stdout.write(out.read())
        out.close()
        shutil.rmtree(self.tmp_dir)

    def collect_images(self, docname, z):
        '''
        Collects all images in the document
        and copy them to the temporary directory.
        '''
        if locale.getpreferredencoding():
          dir_locale = locale.getpreferredencoding()
        else:
          dir_locale = "UTF-8"
        dir = unicode(self.options.image_dir, dir_locale)
        for node in self.document.xpath('//svg:image', namespaces=inkex.NSS):
            xlink = node.get(inkex.addNS('href',u'xlink'))
            if (xlink[:4] != 'data'):
                absref = node.get(inkex.addNS('absref',u'sodipodi'))
                url = urlparse.urlparse(xlink)
                href = urllib.url2pathname(url.path)
                
                if (href != None):
                    absref = os.path.realpath(href)

                absref = unicode(absref, "utf-8")
                image_path = os.path.join(dir, os.path.basename(absref))
                
                if (os.path.isfile(absref)):
                    shutil.copy(absref, self.tmp_dir)
                    z.write(absref, image_path.encode(self.encoding))
                elif (os.path.isfile(os.path.join(self.tmp_dir, absref))):
                    # TODO: please explain why this clause is necessary
                    shutil.copy(os.path.join(self.tmp_dir, absref), self.tmp_dir)
                    z.write(os.path.join(self.tmp_dir, absref), image_path.encode(self.encoding))
                else:
                    inkex.errormsg(_('Could not locate file: %s') % absref)

                node.set(inkex.addNS('href',u'xlink'), image_path)
                #node.set(inkex.addNS('absref',u'sodipodi'), image_path)

    def collect_SVG(self, docstripped, z):
        '''
        Copy SVG document to the temporary directory
        and add it to the temporary compressed file
        '''
        dst_file = os.path.join(self.tmp_dir, docstripped)
        stream = open(dst_file,'w')
        self.document.write(stream)
        stream.close()
        z.write(dst_file,docstripped.encode(self.encoding)+'.svg')

    def is_text(self, node):
        '''
        Returns true if the tag in question is an element that
        can hold text.
        '''
        return node.tag in self.text_tags

    def get_fonts(self, node):
        '''
        Given a node, returns a list containing all the fonts that
        the node is using.
        '''
        fonts = []
        s = ''
        if 'style' in node.attrib:
            s = simplestyle.parseStyle(node.attrib['style'])
        if not s:
            return fonts
            
        if s.has_key('font-family'):
            if s.has_key('font-weight'):
                fonts.append(s['font-family'] + ' ' + s['font-weight'])
            else:
                fonts.append(s['font-family'])
        elif s.has_key('-inkscape-font-specification'):
            fonts.append(s['-inkscape-font-specification'])
        return fonts

    def list_fonts(self, z):
        '''
        Walks through nodes, building a list of all fonts found, then
        reports to the user with that list.
        Based on Craig Marshall's replace_font.py
        '''
        items = []
        nodes = []
        items = self.document.getroot().getiterator()
        nodes.extend(filter(self.is_text, items))
        fonts_found = []
        for node in nodes:
            for f in self.get_fonts(node):
                if not f in fonts_found:
                    fonts_found.append(f)
        findings = sorted(fonts_found)
        # Write list to the temporary compressed file
        filename = 'fontlist.txt'
        dst_file = os.path.join(self.tmp_dir, filename)
        stream = open(dst_file,'w')
        if len(findings) == 0:
            stream.write(_("Didn't find any fonts in this document/selection."))
        else:
            if len(findings) == 1:
                stream.write(_("Found the following font only: %s") % findings[0])
            else:
                stream.write(_("Found the following fonts:\n%s") % '\n'.join(findings))
        stream.close()
        z.write(dst_file, filename)


    def effect(self):
        docroot = self.document.getroot()
        docname = docroot.get(inkex.addNS('docname',u'sodipodi'))
        #inkex.errormsg(_('Locale: %s') % locale.getpreferredencoding())
        if docname is None:
            docname = self.args[-1]
        # TODO: replace whatever extention
        docstripped = os.path.basename(docname.replace('.zip', ''))
        docstripped = docstripped.replace('.svg', '')
        docstripped = docstripped.replace('.svgz', '')
        # Create os temp dir
        self.tmp_dir = tempfile.mkdtemp()
        # Create destination zip in same directory as the document
        self.zip_file = os.path.join(self.tmp_dir, docstripped) + '.zip'
        z = zipfile.ZipFile(self.zip_file, 'w')

        self.collect_images(docname, z)
        self.collect_SVG(docstripped, z)
        if self.options.font_list == True:
            self.list_fonts(z)
        z.close()


if __name__ == '__main__':   #pragma: no cover
    e = CompressedMediaOutput()
    e.affect()


# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99
