# -*- coding: utf-8 -*-

################################################################
# zopyx.plone.smashdocs
# (C) 2016,  Andreas Jung, www.zopyx.com, Tuebingen, Germany
################################################################

import os
import zipfile
import mimetypes
import pkg_resources
import lxml.etree

import plone.api
from zope.interface import alsoProvides
from plone.protect.interfaces import IDisableCSRFProtection
from plone import namedfile
from plone.app.textfield.value import RichTextValue
from Products.CMFPlone.utils import safe_unicode
from pp.client.plone.browser.pdf import ProducePublishView

from zopyx.smashdocs.sdxml2html import sdxml2html
from .smashdocument import SmashDocument
from ..i18n import MessageFactory as _


class Converters(SmashDocument):

    def __init__(self, context, request):
        super(Converters, self).__init__(context, request)
        alsoProvides(self.request, IDisableCSRFProtection)

    def asHTML(self):
        """ Produce & Publish callback """
        obj = self.context['sdxml']['index.html']
        return obj.text.output

    def supplementary_css(self):
        """ Produce & Publish callback """
        obj = self.context['sdxml']['styles.css']
        return obj.file.open().read()

    def cleanup_xml(self, xml):
        root = lxml.etree.fromstring(xml)
        return lxml.etree.tostring(root, encoding='utf8', pretty_print=True)

    def store_as_image(self, fn_or_data, obj_id, container, delete=True):
        """ Store image file or data as Plone 'Image' object """

        if not container:
            container = self.context

        if obj_id in container.objectIds():
            plone.api.content.delete(container[obj_id])

        mt, _ = mimetypes.guess_type(obj_id)
        obj = plone.api.content.create(
            type='Image',
            id=obj_id,
            title=obj_id,
            container=container)
        obj.image = namedfile.NamedBlobImage(
            fn_or_data,
            filename=safe_unicode(obj_id),
            contentType=mt)

    def store_as_document(self, fn_or_data, obj_id, container=None, delete=True):
        """ Store HTML file or data as Plone 'Document' object """

        if not container:
            container = self.context

        if obj_id in container.objectIds():
            plone.api.content.delete(container[obj_id])

        obj = plone.api.content.create(
            type='Document',
            id=obj_id,
            title=obj_id,
            container=container)

        obj.text = RichTextValue(fn_or_data, 'text/html', 'text/html')

    def store_as_file(self, fn_or_data, obj_id, container=None, delete=True):
        """ Store binary content of `out_fn` as Plone 'File' object """

        if not container:
            container = self.context

        if obj_id in container.objectIds():
            plone.api.content.delete(container[obj_id])

        obj = plone.api.content.create(
            type='File',
            id=obj_id,
            title=obj_id,
            container=container)

        mt, _ = mimetypes.guess_type(obj_id)
        if fn_or_data.startswith(os.path.sep):
            with open(fn_or_data, 'rb') as fp:
                obj.file = namedfile.NamedBlobImage(
                    fp.read(),
                    filename=unicode(obj_id),
                    contentType=mt)
            if delete:
                os.unlink(fn_or_data)
        else:
            obj.file = namedfile.NamedBlobImage(
                fn_or_data,
                filename=unicode(obj_id),
                contentType=mt)

    def convert_docx(self):
        sd = self.smashdocs
        templates = sd.list_templates()
        out_fn = sd.export_document(
            document_id=self.context.document_id,
            format='docx',
            user_id=self.user_id,
            template_id=templates[0]['id'])
        self.store_as_file(out_fn, 'index.docx')
        self.portal_message(_(u'Stored as {}').format('index.docx'))
        return self.request.response.redirect(self.context.absolute_url())

    def convert_sdxml(self):
        sd = self.smashdocs
        out_fn = sd.export_document(
            document_id=self.context.document_id,
            format='sdxml',
            user_id=self.user_id)
        self.store_as_file(out_fn, 'index_sdxml.zip', delete=False)
        self.unpack_zip(out_fn, 'sdxml')
        self.context.reindexObject()
        self.portal_message(_(u'Stored as {}').format('index_sdxml.zip'))
        return self.request.response.redirect(self.context.absolute_url())

    def convert_pdf(self):
        transformations = [
            'fixImagePaths',
            'makeImagesLocal'
        ]
        view = ProducePublishView(self.context, self.request)
        out_fn = view(
            transformations=transformations,
            supplementary_css=self.supplementary_css())
        self.store_as_file(out_fn, 'index.pdf')
        self.portal_message(_(u'Stored as {}').format('index.pdf'))
        return self.request.response.redirect(self.context.absolute_url())

    def convert_epub(self):
        transformations = [
            'fixImagePaths',
            'makeImagesLocal'
        ]
        view = ProducePublishView(self.context, self.request)
        out_fn = view(
            transformations=transformations,
            supplementary_css=self.supplementary_css())
        self.store_as_file(out_fn, 'index.epub')
        self.portal_message(_(u'Stored as {}').format('index.epub'))
        return self.request.response.redirect(self.context.absolute_url())

    def convert_html(self):

        sd = self.smashdocs

        out_fn = sd.export_document(
            document_id=self.context.document_id,
            format='html',
            user_id=self.user_id)

        if 'index_html.zip' in self.context.objectIds():
            plone.api.content.delete(self.context['index_html.zip'])

        self.store_as_file(out_fn, 'index_html.zip',
                           self.context, delete=False)

        # unpack packed HTML ZIP file

        # create 'html' subfolder
        if 'html' in self.context.objectIds():
            plone.api.content.delete(self.context['html'])
        folder = plone.api.content.create(
            container=self.context,
            type='Folder',
            id='html',
            title='html')

        # create 'images' subfolder
        plone.api.content.create(
            container=folder,
            type='Folder',
            id='images',
            title='images')

        # unpack ZIP file
        self.unpack_zip(out_fn, 'html')
        self.context.reindexObject()

        os.unlink(out_fn)
        self.portal_message(_(u'Stored as html folder'))
        return self.request.response.redirect(self.context.absolute_url())

    def unpack_zip(self, zip_fn, folder_id):

        if folder_id in self.context.objectIds():
            plone.api.content.delete(self.context[folder_id])

        folder = plone.api.content.create(
            type='Folder',
            container=self.context,
            id=folder_id,
            title=folder_id)

        images = plone.api.content.create(
            type='Folder',
            container=folder,
            id='images',
            title='images')

        with zipfile.ZipFile(zip_fn, 'r') as zf:
            for name in zf.namelist():

                data = zf.read(name)

                if name == 'index.html':
                    # SD generated HTML with self-contained styles

                    self.store_as_document(data, name, folder)

                elif name == 'sd.xml':

                    # SD internal XML
                    data = self.cleanup_xml(data)
                    self.store_as_file(data, 'sd.xml', folder)

                    # generate our own HTML
                    html = sdxml2html.sdxml2html_data(
                        data, image_prefix='images')
                    self.store_as_document(html, 'index.html', folder)

                    # add our own stylesheet
                    styles = pkg_resources.resource_string(
                        'zopyx.smashdocs.sdxml2html', 'styles.css')
                    self.store_as_file(styles, 'styles.css', folder)

                else:
                    basename = os.path.basename(name)
                    self.store_as_image(data, basename, images)
