# -*- coding: UTF-8 -*-
# vim: fdm=marker

__revision__ = '$Id$'

# Copyright (c) 2005-2009 Piotr Ożarowski
#
# 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 Library 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
# 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA

# You may use and distribute this software under the terms of the
# GNU General Public License, version 2 or later

import os
from gi.repository import Gtk
import gutils
import shutil
import version
import math
from xml.dom import minidom
import logging
from plugins.export import Base
from gettext import gettext as _

log = logging.getLogger("Griffith")


class ExportPlugin(Base):
    name = 'HTML'
    description = _('Plugin exports data using templates')
    author = 'Piotr Ożarowski'
    email = 'piotr@griffith.cc'
    version = '4.0'

    # ==[ configuration - default values ]==========={{{
    settings = {
        'sorting': 'movies_title',
        'sorting2': 'ASC',
        'export_dir': '',
        'template': 2,
        'title': _("Griffith's movies list"),
        'style': 0,
        'custom_style': False,
        'custom_style_file': None,
        'split_num': 50,  # split into x files/pages
        'split_by': 1,  # 0==files, 1==movies
        'poster_convert': False,  # dont convert
        'poster_height': 200,
        'poster_width': 150,
        'poster_mode': 'RGB',  # RGB == color, L == black and white
        'poster_format': 'jpeg'
        }
    fields = {
        'movies_cast': False,
        'movies_classification': False,
        'movies_country': True,
        'movies_genre': True,
        'movies_director': True,
        'movies_image': True,
        'movies_o_site': True,
        'movies_site': True,
        'movies_trailer': True,
        'movies_loaned': False,
        'movies_media_num': True,
        'movies_number': True,
        'movies_o_title': True,
        'movies_plot': False,
        'movies_rating': True,
        'movies_runtime': True,
        'movies_studio': False,
        'movies_seen': True,
        'movies_title': True,
        'movies_year': True,
        'movies_notes': False,
        'movies_screenplay': False,
        'movies_cameraman': False,
        'movies_width': False,
        'movies_height': False,
        'movies_barcode': False,
        #        'movies_region'         : False,
        #        'movies_layers'         : False,
        #        'movies_condition'      : False,
        #        'movies_color'          : False,
        #        'movies_volume_id'      : False,
        #        'movies_collection_id'  : False,
        'media_name': True,
        'collections_name': True,
        'volumes_name': True,
        # 'acodecs_name'          : True,
        'vcodecs_name': True,
        }

    fields_as_columns = {
        'movies_cast': 'cast',
        'movies_classification': 'classification',
        'movies_country': 'country',
        'movies_genre': 'genre',
        'movies_director': 'director',
        'movies_image': 'poster_md5',
        'movies_o_site': 'o_site',
        'movies_site': 'site',
        'movies_trailer': 'trailer',
        'movies_loaned': 'loaned',
        'movies_media_num': 'media_num',
        'movies_number': 'number',
        'movies_o_title': 'o_title',
        'movies_plot': 'plot',
        'movies_rating': 'rating',
        'movies_runtime': 'runtime',
        'movies_studio': 'studio',
        'movies_seen': 'seen',
        'movies_title': 'title',
        'movies_year': 'year',
        'movies_notes': 'notes',
        'movies_screenplay': 'screenplay',
        'movies_cameraman': 'cameraman',
        'movies_width': 'width',
        'movies_height': 'height',
        'movies_barcode': 'barcode',
        #        'movies_region'         : 'region',
        #        'movies_layers'         : 'layers',
        #        'movies_condition'      : 'condition',
        #        'movies_color'          : 'color',
        #        'movies_volume_id'      : 'volume_id',
        #        'movies_collection_id'  : 'collection_id',
        'media_name': 'name',
        'collections_name': 'name',
        'volumes_name': 'name',
        # 'acodecs_name'          : 'name',
        'vcodecs_name': 'name',
        }

    names = {
        _('Cast'): 'movies_cast',
        _('Classification'): 'movies_classification',
        _('Country'): 'movies_country',
        _('Director'): 'movies_director',
        _('Genre'): 'movies_genre',
        _('Image'): 'movies_image',
        _('Official site'): 'movies_o_site',
        _('Site'): 'movies_site',
        _('Trailer'): 'movies_trailer',
        _('Loaned'): 'movies_loaned',
        _('Discs'): 'movies_media_num',
        _('Number'): 'movies_number',
        _('Original Title'): 'movies_o_title',
        _('Plot'): 'movies_plot',
        _('Rating'): 'movies_rating',
        _('Runtime'): 'movies_runtime',
        _('Studio'): 'movies_studio',
        _('Seen it'): 'movies_seen',
        _('Title'): 'movies_title',
        _('Year'): 'movies_year',
        _('Notes'): 'movies_notes',
        _('Screenplay'): 'movies_screenplay',
        _('Cameraman'): 'movies_cameraman',
        _('Width'): 'movies_width',
        _('Height'): 'movies_height',
        _('Barcode'): 'movies_barcode',
        #        _('Region')         : 'movies_region',
        #        _('Layers')         : 'movies_layers',
        #        _('Condition')      : 'movies_condition',
        #        _('Color')          : 'movies_color',
        #        _('Volume')         : 'movies_volume_id',
        #        _('Collection')     : 'movies_collection_id',
        _('Media'): 'media_name',
        _('Collection'): 'collections_name',
        _('Volume'): 'volumes_name',
        # _('Audio codecs')   : 'acodecs_name',
        _('Video codec'): 'vcodecs_name',
        }

    # }}}

    def initialize(self):  # {{{
        self.fields_to_export = []
        for field in ExportPlugin.fields:
            if field == 'movies_image':
                self.fields_to_export.append('movies.poster_md5')
            else:
                pos = field.find('_')
                self.fields_to_export.append("%s.%s" % (field[:pos], field[pos + 1:]))

        self.widgets = {}
        self.style_list = {}
        self.templates = self.make_template_list()
        # glade
        gf = os.path.join(self.locations['glade'], 'exporthtml.ui')
        self.load_configuration()
        self.define_widgets(gf)
        self.fill_widgets()
        return True

    # }}}

    def load_configuration(self):  # {{{
        # persist config
        if self.config is not None:
            config = self.settings
            for name, value in list(config.items()):
                try:
                    tmp = self.config.get(name, value, section='export-html')
                    if isinstance(value, bool):
                        config[name] = bool(int(tmp))
                    elif isinstance(value, int):
                        config[name] = int(tmp)
                    else:
                        config[name] = tmp
                except Exception:
                    pass
            selected_fields = self.config.get('selected_fields', '', section='export-html')
            if selected_fields:
                for name in self.fields:
                    self.fields[name] = False
                selected_fields = selected_fields.split(',')
                for selected_field in selected_fields:
                    if selected_field in self.fields:
                        self.fields[selected_field] = True

    # }}}

    def run(self):
        pass

    def get_node_value_by_language(self, parent, name, language='en'):  # {{{
        nodes = parent.getElementsByTagName(name)
        for node in nodes:
            if node.parentNode != parent:
                continue
            elif node.attributes.get('xml:lang') is not None:
                if node.attributes.get('xml:lang').value == language:
                    return node.firstChild.nodeValue
            else:  # set default value in case node has no xml:lang attribute
                value = node.firstChild.nodeValue
        return value

    # }}}

    def make_template_list(self):  # {{{
        language = 'en'
        if 'LANG' in os.environ:
            language = os.environ['LANG'][:2]
        templates = {}
        j = 0  # number of templates
        dirName = os.path.join(self.locations['share'], 'export_templates')
        items = os.listdir(dirName)
        items.sort()
        for i in items:
            fileName = os.path.join(dirName, i)
            if not os.path.islink(fileName) and os.path.isdir(fileName):
                # clear previous data
                doc = None
                styles = {}
                tpl_name = None
                tpl_author = None
                tpl_email = None
                tpl_version = None
                tpl_ext = None
                tpl_desc = None
                try:
                    doc = minidom.parse(os.path.join(fileName, 'config.xml'))
                except Exception:
                    log.info(
                        "Can't parse configuration file for template: %s" % fileName)
                    continue
                for template in doc.getElementsByTagName('template'):
                    tpl_name = self.get_node_value_by_language(
                        template, 'name', language)
                    tpl_author = template.getElementsByTagName('author')[
                        0].firstChild.nodeValue
                    tpl_email = template.getElementsByTagName('email')[
                        0].firstChild.nodeValue
                    tpl_version = template.getElementsByTagName('version')[
                        0].firstChild.nodeValue
                    tpl_ext = template.getElementsByTagName('extension')[
                        0].firstChild.nodeValue
                    tpl_desc = self.get_node_value_by_language(
                        template, 'description', language)
                    k = 0  # number of styles
                    try:
                        styles_list = template.getElementsByTagName('styles')[
                            0].getElementsByTagName('style')
                        for style in styles_list:
                            tpl_style_name = self.get_node_value_by_language(
                                style, 'name', language)
                            tpl_style_file = style.getElementsByTagName('file')[
                                0].firstChild.nodeValue
                            # get preview if available
                            try:
                                tpl_style_preview = \
                                    style.getElementsByTagName('preview')[
                                        0].firstChild.nodeValue
                            except Exception:
                                tpl_style_preview = None
                            styles[k] = {
                                'name': tpl_style_name,
                                'file': tpl_style_file,
                                'preview': tpl_style_preview
                                }
                            k += 1
                    except Exception:
                        styles = None
                if tpl_name == '':
                    continue
                templates[j] = {
                    'dir': i,
                    'name': tpl_name,
                    'author': tpl_author,
                    'email': tpl_email,
                    'version': tpl_version,
                    'ext': tpl_ext,
                    'desc': tpl_desc,
                    'styles': styles
                    }
                j += 1
        return templates

    # }}}

    # ==[ widgets ]=================================={{{
    def define_widgets(self, glade_file):
        def get(x):
            return builder.get_object(x)

        builder = Gtk.Builder()
        builder.set_translation_domain("griffith")
        builder.add_from_file(glade_file)
        self.widgets = {
            'window': get('w_eh'),
            'fcw': get('fcw'),
            'box_include_1': get('box_include_1'),
            'box_include_2': get('box_include_2'),
            'box_include_3': get('box_include_3'),
            'sb_split_num': get('sb_split_num'),
            'rb_split_files': get('rb_split_files'),
            'rb_split_movies': get('rb_split_movies'),
            'entry_header': get('entry_header'),
            'cb_custom_style': get('cb_custom_style'),
            'cb_reverse': get('cb_reverse'),
            'combo_style': get('combo_style'),
            'combo_sortby': get('combo_sortby'),
            'combo_theme': get('combo_theme'),
            'fcb_custom_style_file': get('fcb_custom_style_file'),
            'l_tpl_author': get('l_tpl_author'),
            'l_tpl_email': get('l_tpl_email'),
            'l_tpl_version': get('l_tpl_version'),
            'l_tpl_desc': get('l_tpl_desc'),
            'image_preview': get('image_preview'),
            'vb_posters': get('vb_posters'),
            'sb_height': get('sb_height'),
            'sb_width': get('sb_width'),
            'cb_black': get('cb_black'),
            'combo_format': get('combo_format'),
            'cb_convert': get('cb_convert'),
            }

        # define handlers for general events
        builder.connect_signals({
            'on_export_button_clicked': self.export_data,
            'on_rb_split_files_toggled': self.on_rb_split_files_toggled,
            'on_rb_split_movies_toggled': self.on_rb_split_movies_toggled,
            'on_cancel_button_clicked': self.on_quit,
            'on_cb_data_toggled': self.on_cb_data_toggled,
            'on_cb_custom_style_toggled': self.on_cb_custom_style_toggled,
            'on_fcb_custom_style_file_activated':
                self.on_fcb_custom_style_file_activated,
            'on_combo_style_changed': self.on_combo_style_changed,
            'on_combo_theme_changed': self.on_combo_theme_changed,
            'on_cb_convert_toggled': self.on_cb_convert_toggled,
            })

    def fill_widgets(self):
        # themes
        for i in self.templates:
            self.widgets['combo_theme'].insert_text(i,
                                                    self.templates[i]['name'])

        # sortby combo
        keys = list(self.names.keys())
        keys.sort()
        j = 0
        pos_o_title = 0
        for i in keys:
            self.widgets['combo_sortby'].append_text(i)
            if self.names[i] == self.settings['sorting']:
                pos_o_title = j
            j += 1
        self.widgets['combo_sortby'].set_wrap_width(3)

        # include data
        j = 0
        k = math.ceil(len(self.names) / float(3))
        for i in keys:
            j += 1
            field = self.names[i]
            self.widgets['cb_' + field] = Gtk.CheckButton(i)
            self.widgets['cb_' + field].set_name("cb_%s" % field)
            self.widgets['cb_' + field].connect('toggled',
                                                self.on_cb_data_toggled)
            self.widgets['cb_' + field].set_active(self.fields[field])
            if j <= k:
                self.widgets['box_include_1'].add(self.widgets["cb_%s" % field])
            elif j <= 2 * k:
                self.widgets['box_include_2'].add(self.widgets["cb_%s" % field])
            else:
                self.widgets['box_include_3'].add(self.widgets["cb_%s" % field])
        self.widgets['box_include_1'].show_all()
        self.widgets['box_include_2'].show_all()
        self.widgets['box_include_3'].show_all()

        # set defaults --------------------------------
        self.widgets['entry_header'].set_text(self.settings['title'])
        self.widgets['combo_sortby'].set_active(pos_o_title)
        if self.settings['sorting2'] == 'DESC':
            self.widgets['cb_reverse'].set_active(True)
        else:
            self.widgets['cb_reverse'].set_active(False)
        # template and theme
        style = self.settings[
            'style']  # save it temporary because change of the template set it 0
        self.widgets['combo_theme'].set_active(self.settings['template'])
        self.widgets['combo_style'].set_active(style)
        self.widgets['cb_custom_style'].set_active(
            self.settings['custom_style'])
        if self.settings['custom_style_file']:
            self.widgets['fcb_custom_style_file'].set_filename(
                self.settings['custom_style_file'])
        # spliting
        self.widgets['sb_split_num'].set_value(self.settings['split_num'])
        if self.settings['split_by'] == 0:
            self.widgets['rb_split_files'].set_active(True)
        else:
            self.widgets['rb_split_movies'].set_active(True)
        # posters
        self.widgets['combo_format'].set_active(0)
        if self.settings['poster_format'] == 'PNG':
            self.widgets['combo_format'].set_active(1)
        elif self.settings['poster_format'] == 'GIF':
            self.widgets['combo_format'].set_active(2)
        if self.settings['poster_convert'] and self.settings[
            'poster_convert'] is True:
            self.widgets['cb_convert'].set_active(True)
            self.widgets['vb_posters'].set_sensitive(True)
        else:
            self.widgets['cb_convert'].set_active(False)
            self.widgets['vb_posters'].set_sensitive(False)
        self.widgets['sb_height'].set_value(self.settings['poster_height'])
        self.widgets['sb_width'].set_value(self.settings['poster_width'])
        if self.settings['poster_mode'] == 'L':
            self.widgets['cb_black'].set_active(True)
        # destination dir
        if self.settings['export_dir']:
            self.widgets['fcw'].set_current_folder(self.settings['export_dir'])

    # }}}

    # ==[ callbacks ]================================{{{
    # buttons:
    def on_quit(self, widget=None):
        self.widgets['window'].destroy()

    # data tab -------------------------------------# {{{
    def on_rb_split_files_toggled(self, widget):
        self.settings['split_by'] = 0  # files

    def on_rb_split_movies_toggled(self, widget):
        self.settings['split_by'] = 1  # movies

    # export frame
    def on_cb_data_toggled(self, widget):
        self.fields[gutils.after(widget.get_name(), 'cb_')] = (
            widget.get_active())

    # posters frame
    def on_cb_convert_toggled(self, widget):
        active = widget.get_active()
        self.settings['poster_convert'] = active
        if not active:
            self.widgets['vb_posters'].set_sensitive(False)
        else:
            self.widgets['vb_posters'].set_sensitive(True)

    # }}}

    # template tab ---------------------------------# {{{
    def on_combo_theme_changed(self, widget):
        self.settings['template']
        tpl_id = widget.get_active()
        self.settings['template'] = tpl_id
        # fill authors data
        self.widgets['l_tpl_author'].set_markup("<i>%s</i>" % self.templates[tpl_id]['author'])
        self.widgets['l_tpl_email'].set_markup("<i>%s</i>" % self.templates[tpl_id]['email'])
        self.widgets['l_tpl_email'].set_selectable(True)
        self.widgets['l_tpl_version'].set_markup("<i>%s</i>" % self.templates[tpl_id]['version'])
        self.widgets['l_tpl_desc'].set_markup("<i>%s</i>" % self.templates[tpl_id]['desc'])
        # remove old style list
        self.widgets['combo_style'].get_model().clear()
        # ... and add new
        if self.templates[tpl_id]['styles'] is not None:
            for i in self.templates[tpl_id]['styles']:
                (self.widgets['combo_style'].
                 insert_text(i, self.templates[tpl_id]['styles'][i]['name']))  # template name
            self.widgets['combo_style'].set_active(0)
        else:
            self.settings['style'] = None
            self.widgets['image_preview'].set_from_stock(Gtk.STOCK_MISSING_IMAGE, Gtk.IconSize.LARGE_TOOLBAR)

    def on_combo_style_changed(self, widget):
        self.settings['style'] = widget.get_active()
        self.widgets['cb_custom_style'].set_active(False)
        preview_file = None

        tpl_id = self.settings['template']
        template_dir = os.path.join(self.locations['share'], 'export_templates',
                                    self.templates[tpl_id]['dir'])
        if self.settings['style'] > -1:
            preview_file = self.templates[
                self.settings['template']]['styles'][self.settings['style']]['preview']
        if preview_file is not None:
            preview_file = os.path.join(template_dir, preview_file)
        if preview_file is not None and not os.path.isfile(preview_file):
            # try default preview image
            preview_file = os.path.join(template_dir, 'preview.jpg')
            if not os.path.isfile(preview_file):
                preview_file = None
        if preview_file is not None:
            self.widgets['image_preview'].set_from_file(preview_file)
        else:
            self.widgets['image_preview'].set_from_stock(
                Gtk.STOCK_MISSING_IMAGE, Gtk.IconSize.LARGE_TOOLBAR)
        self.widgets['image_preview'].show()

    def on_cb_custom_style_toggled(self, widget):
        if widget.get_active():
            self.settings['custom_style'] = True
            self.widgets['image_preview'].hide()
        else:
            self.settings['custom_style'] = False
            self.widgets['image_preview'].show()

    def on_fcb_custom_style_file_activated(self, widget):
        self.settings['custom_style_file'] = widget.get_filename()
        self.widgets['cb_custom_style'].set_active(True)

    # }}} }}}

    def make_navigation(self, pages, current):  # {{{
        if pages > 1:  # navigation needed
            tpl_id = self.settings['template']
            t = '<div class="navi">\n\t<p id="prev">'
            if current > 1:
                t += '<a href="./page_%s.%s">%s</a>' % \
                     (str(current - 1), self.templates[tpl_id]['ext'],
                      _('previous'))
            else:  # first page
                t += _('previous')
            t += "</p>\n"
            for i in range(1, pages + 1):
                if i == current:
                    t += '\t<p id="current">%s</p>\n' % str(i)
                else:
                    t += '\t<p><a href="./page_%s.%s">%s</a></p>\n' % \
                         (str(i), self.templates[tpl_id]['ext'], str(i))
            t += '\t<p id="next">'
            if pages > current:
                t += '<a href="./page_%s.%s">%s</a>' % \
                     (str(current + 1), self.templates[tpl_id]['ext'], _('next'))
            else:  # last page
                t += _('next')
            t += "</p>\n</div>"
            return t
        else:
            return ''

    # }}}

    def fill_template(self, template, field, data='', title='', remove=False):  # {{{
        start = template.find(f'<@{field}>')
        end = template.find(f'</@{field}>', start + 1)
        if start > -1 and end > -1:
            if remove:
                return template[:start] + template[end + 4 + len(field):]
            else:
                tmp = gutils.trim(template, f'<@{field}>', f'</@{field}>')
                tmp = tmp.replace("@DATA@", data)
                tmp = tmp.replace("@TITLE@", title)
                tmp = template[:start] + tmp + template[end + 4 + len(field):]
                if tmp.find(f'<@{field}>') != -1:
                    tmp = self.fill_template(tmp, field, data, title, remove)
                return tmp
        else:
            return template

    # }}}

    def select(self):  # {{{
        config = self.settings
        # sort order TODO: update self.search_conditions["sort_by"]
        tmp = config['sorting'].split('_')
        sort_column = "%s.%s" % (tmp[0], '_'.join(tmp[1:]))

        if config['sorting2'] == 'ASC':
            sort_column += ' ASC'
        else:
            sort_column += ' DESC'

        self.search_conditions["sort_by"] = (sort_column,)
        query = self.get_query()

        return self.db.session.execute(query)

    # }}}

    # ==[ main function ]============================{{{
    def export_data(self, widget):
        """Main exporting function"""

        config = self.settings
        fields = self.fields
        tid = config['template']

        # get data from widgets
        self.settings['export_dir'] = self.widgets['fcw'].get_filename()
        self.settings['title'] = self.widgets['entry_header'].get_text()
        self.settings['sorting'] = self.names[
            self.widgets['combo_sortby'].get_active_text()]
        if self.widgets['cb_reverse'].get_active():
            self.settings['sorting2'] = 'DESC'
        else:
            self.settings['sorting2'] = 'ASC'
        self.settings['split_num'] = self.widgets[
            'sb_split_num'].get_value_as_int()
        self.settings['poster_height'] = self.widgets[
            'sb_height'].get_value_as_int()
        self.settings['poster_width'] = self.widgets[
            'sb_width'].get_value_as_int()
        if self.widgets['cb_black'].get_active():
            self.settings['poster_mode'] = 'L'
        else:
            self.settings['poster_mode'] = 'RGB'
        self.settings['poster_format'] = self.widgets[
            'combo_format'].get_active_text()

        # persist config
        if self.config is not None:
            for name, value in list(config.items()):
                self.config.set(name, value, section='export-html')
            selected_fields = ''
            for name, value in list(self.fields.items()):
                if value:
                    selected_fields = selected_fields + name + ','
            self.config.set('selected_fields', selected_fields,
                            section='export-html')
            self.config.save()

        # create directories
        if not config['export_dir']:
            log.info("Error: Folder name not set!")
            return 1

        if not os.path.isdir(config['export_dir']):
            try:
                os.mkdir(config['export_dir'])
            except Exception:
                gutils.error(_("Can't create %s!") % config['export_dir'])
                return 2

        data_path = os.path.join(self.locations['share'], 'export_templates',
                                 self.templates[tid]['dir'], 'data')
        if os.path.isdir(data_path):
            try:
                gutils.copytree(data_path, config['export_dir'])
            except Exception as err:
                gutils.warning(str(err))

        if fields['movies_image']:
            # import modules needed later
            # modules are needed at least to convert griffith.png to nopic.(gif|jpeg|png)
            from PIL import Image
            # py2exe problem workaround:
            if os.name == 'nt' or os.name.startswith('win'):  # win32, win64
                Image._initialized = 2
            if not config['poster_convert']:
                config['poster_format'] = 'jpeg'  # replace 'jpeg'

            posters_dir = os.path.join(config['export_dir'], 'posters')
            if os.path.isdir(posters_dir):
                if gutils.question(
                        _(f"Directory {posters_dir} already exists.\nDo you "
                          f"want to overwrite it?"), self.widgets['window']):
                    try:
                        shutil.rmtree(posters_dir)
                    except Exception:
                        gutils.error(_(f"Can't remove {config['export_dir']}!"))
                        return 3
                else:
                    return 4
            try:
                os.mkdir(posters_dir)
            except Exception:
                gutils.error(_("Can't create %s!") % posters_dir)
                return 5

        if config['custom_style']:
            if (config['custom_style_file'] is not None
                    and os.path.isfile(config['custom_style_file'])):
                try:
                    shutil.copy(config['custom_style_file'],
                                config['export_dir'])
                except Exception:
                    gutils.warning(_(f"Can't copy "
                                     f"{config['custom_style_file']}!"))
                    config['custom_style'] = False
                style = os.path.split(self.settings['custom_style_file'])[1]
            else:
                config['custom_style'] = False

        if config['style'] is not None and config['custom_style'] is False:
            style = self.templates[tid]['styles'][config['style']]['file']
            style_path = os.path.join(
                self.locations['share'], 'export_templates',
                self.templates[tid]['dir'], style)
            try:
                shutil.copy(style_path, config['export_dir'])
            except Exception:
                gutils.warning(_(f"Can't copy {style_path}!"))

        # select exported movies
        exported_movies = self.select().fetchall()
        if self.settings['sorting'] in ('movies_title', 'movies_o_title'):
            # re-sorting movies case-insensitive and respect the current locale setting
            # if sorting by title or original title is selected
            import locale
            locale.setlocale(locale.LC_ALL, "")
            exported_movies.sort(
                key=lambda k: locale.strxfrm(
                    k._mapping[self.settings['sorting']] and
                    k._mapping[self.settings['sorting']].lower() or ''),
                reverse=self.settings['sorting2'] == 'DESC')
        number_of_exported_movies = len(exported_movies)

        if config['split_by'] == 1:  # split by number of movies per page
            self.entries_per_page = config['split_num']
        else:  # split by number of pagess
            if number_of_exported_movies < config['split_num']:
                self.entries_per_page = 1
            else:
                self.entries_per_page = int(number_of_exported_movies / config['split_num'])

        # calculate number of files to be created (pages)
        self.pages = int(math.ceil(float(number_of_exported_movies) / self.entries_per_page))

        template_dir = os.path.join(self.locations['share'], 'export_templates', self.templates[tid]['dir'])
        try:
            filename = 'page.tpl'
            tpl_header = open(os.path.join(template_dir, filename), "r").read()
        except Exception:
            gutils.error(_("Can't open %s!") % filename)
            return False

        tpl_header = self.fill_template(tpl_header, 'header', config['title'])
        try:
            tpl_header = self.fill_template(tpl_header, 'style', style)
        except Exception:
            pass
        tmp = (_('Document generated by Griffith v') + version.pversion +
               ' - Copyright (C) ' + version.pyear + ' ' + version.pauthor +
               ' - ' + _('Released Under the GNU/GPL License'))
        tmp = gutils.html_encode(tmp)
        tmp = tmp.replace('@', ' at ')  # prevent spam
        tpl_header = self.fill_template(tpl_header, 'copyright', tmp)
        tmp = None

        tpl_header = self.fill_template(tpl_header, 'pages', self.pages)

        # count exported fields
        rowspan = 0
        for i in fields:
            if fields[i] is True:
                rowspan += 1
        rowspan = str(rowspan)
        tpl_header = self.fill_template(tpl_header, 'rowspan', rowspan)

        # split template
        tpl_tail = gutils.after(tpl_header, '<!-- /ITEMS -->')
        tpl_item = gutils.trim(tpl_header, '<!-- ITEMS -->', '<!-- /ITEMS -->')
        tpl_header = gutils.before(tpl_header, '<!-- ITEMS -->')

        # fill header
        for j in self.names:
            if self.fields[self.names[j]] is True:
                tpl_header = self.fill_template(tpl_header, self.names[j], '', j)
            else:
                tpl_header = self.fill_template(tpl_header, self.names[j], remove=True)

        # check if line break needs conversion
        if tpl_header.upper().find('XHTML 1.0') > -1:
            linebreak_replacement = '<br />'
        else:
            linebreak_replacement = None

        item = 1  # item's position on page (1 - first, ...)
        i = 1
        page = 1  # page number
        for row in exported_movies:  # fill items {{{
            # check if new file has to be created
            if item == 1:
                filename = os.path.join(
                    config['export_dir'], 'page_%s.' %
                                          page + self.templates[tid]['ext'])
                try:
                    exported_file = open(filename, 'w')
                except Exception:
                    gutils.error(_("Can't create %s!") % filename)
                    return False
                tmp2 = tpl_header + ''
                exported_file.write(self.fill_template(tmp2, 'page', str(page)))
                tmp2 = None

            # ---------------------------------------------
            tmp = tpl_item + ''  # a copy (not a reference!)
            tmp = self.fill_template(tmp, 'id', str(item))
            tmp = self.fill_template(tmp, 'item', str(i))
            for j in self.names:
                if self.fields[self.names[j]] is True:
                    if self.names[j] == 'movies_image':
                        if row._mapping['movies_poster_md5']:
                            # image = row['movies_poster_md5'] + '.' + config['poster_format'].lower()
                            image = "%d.%s" % (row._mapping['movies_number'],
                                               config['poster_format'].lower())
                            tmp = self.fill_template(tmp, self.names[j], image, j)
                        else:
                            tmp = self.fill_template(
                                tmp, self.names[j],
                                'nopic.' + config['poster_format'].lower(), j)
                    elif row._mapping[self.names[j]] is None:
                        tmp = self.fill_template(tmp, self.names[j], '', j)
                    elif row._mapping[self.names[j]] is True:
                        tmp = self.fill_template(tmp, self.names[j], _('Yes'), j)
                    elif row._mapping[self.names[j]] is False:
                        tmp = self.fill_template(tmp, self.names[j], _('No'), j)
                    else:
                        try:
                            data = str(row._mapping[self.names[j]])
                            if linebreak_replacement is not None:
                                data = data.replace('\r\n', linebreak_replacement)
                                data = data.replace('\n', linebreak_replacement)
                            tmp = self.fill_template(tmp, self.names[j], data, j)
                        except UnicodeDecodeError:
                            log.info(
                                f"Unicode Decode Error occurred while decoding "
                                f"{self.names[j]} (movie number: {row['movies_number']})")
                            data = str(row._mapping[self.names[j]])
                            if linebreak_replacement is not None:
                                data = data.replace('\r\n', linebreak_replacement)
                                data = data.replace('\n', linebreak_replacement)
                            tmp = self.fill_template(tmp, self.names[j], data, j)
                        except Exception:
                            log.info(f"Error occurred while decoding "
                                     f"{self.names[j]} (movie number: "
                                     f"{row['movies_number']})")
                else:
                    tmp = self.fill_template(tmp, self.names[j], remove=True)
                tmp = gutils.convert_entities(tmp)
            exported_file.write(tmp)
            tmp = None
            # ---------------------------------------------

            # copy poster
            if fields['movies_image']:

                if row._mapping['movies_poster_md5']:
                    image_file_src = gutils.get_image_fname(
                        row._mapping['movies_poster_md5'], self.db)
                    image_file_dst = os.path.join(
                        posters_dir, f"{row._mapping['movies_number']}."
                                     f"{config['poster_format'].lower()}")
                    if not config['poster_convert']:  # copy file
                        try:
                            shutil.copy(image_file_src, image_file_dst)
                        except Exception:
                            log.info("Can't copy %s", image_file_src)
                    else:  # convert posters
                        try:
                            im = (Image.open(image_file_src, 'r').
                                  convert(config['poster_mode']))
                            im.thumbnail((config['poster_width'],
                                          config['poster_height']),
                                         Image.LANCZOS)
                            im.save(image_file_dst, config['poster_format'])
                        except Exception:
                            log.info("Can't convert %s", image_file_src)

            # close file if last item
            if (((page - 1) * self.entries_per_page) + item ==
                    number_of_exported_movies):
                tmp2 = tpl_tail + ''
                exported_file.write(
                    self.fill_template(tmp2, 'navigation',
                                       self.make_navigation(self.pages, page)))
                exported_file.close()
                tmp2 = None

            # close file if last item in page
            elif item == self.entries_per_page:
                tmp2 = tpl_tail + ''
                exported_file.write(
                    self.fill_template(tmp2, 'navigation',
                                       self.make_navigation(self.pages, page)))
                exported_file.close()
                page += 1
                item = 1
                tmp2 = None
            else:
                item += 1
            i += 1
        # }}}
        if fields['movies_image']:
            # convert/copy the griffith picture for movies without a poster
            image_file_src = os.path.join(self.locations['images'],
                                          'griffith.png')
            image_file_dst = os.path.join(posters_dir, 'nopic.'
                                          + config['poster_format'].lower())
            try:
                if config['poster_convert']:
                    im = (Image.open(image_file_src, 'r')
                          .convert(config['poster_mode']))
                    im.thumbnail((config['poster_width'],
                                  config['poster_height']), Image.LANCZOS)
                else:
                    im = Image.open(image_file_src, 'r')
                im = im.convert("RGB")
                im.save(image_file_dst, config['poster_format'])
            except Exception:
                log.info("Can't convert %s" % image_file_src)
        gutils.info(_("Document has been generated."), self.widgets['window'])
        self.on_quit()
    # }}}
