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

__revision__ = '$Id: $'

# Copyright (c) 2011, 2012

# 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 logging
import os
import zipfile
from gettext import gettext as _
from shutil import rmtree
from tempfile import mkdtemp
from xml.dom import minidom, Node

import gutils
from plugins.imp import ImportPlugin as IP

log = logging.getLogger("Griffith")


class ImportPlugin(IP):
    description  = 'Tellico'
    author       = 'Elan Ruusamäe'
    email        = 'glen@delfi.ee'
    version      = '1.1'
    file_filters = '*.[tT][cC]'
    mime_types   = None

    fileversion  = None
    filedom      = None
    items        = None
    itemindex    = 0
    zipdir       = None

    def initialize(self):
        if not IP.initialize(self):
            return False
        self.edit = False
        return True

    def set_source(self, name):
        IP.set_source(self, name)
        self.filename = name
        self.fileversion = self.read_fileversion()
        if self.fileversion == None:
            gutils.error(_('The format of the file is not supported.'))
            return False
        return True

    def count_movies(self):
        """Returns number of movies in file which is about to be imported"""
        count = 0
        if self.filedom:
            try:
                collectionElement = self.filedom.getElementsByTagName('collection')[0]
                for element in collectionElement.childNodes:
                    if element.nodeType == Node.ELEMENT_NODE and element.nodeName == 'entry':
                        count = count + 1
                log.info('Tellico Import: %s movies for import' % count)
            except:
                log.exception('')
        else:
            log.error('Tellico Import: No filedom object.')
        return count

    def get_movie_details(self):
        """Returns dictionary with movie details"""
        if not self.filedom:
            log.error('Tellico Import: filedom not open')
            return None

        if not self.items:
            collectionElement = self.filedom.getElementsByTagName('collection')[0]
            self.items = collectionElement.childNodes
            self.itemindex = 0
        if not self.items or len(self.items) < 1:
            return None
        if len(self.items) <= self.itemindex:
            return None
        item = self.items[self.itemindex]
        while not (item.nodeType == Node.ELEMENT_NODE and item.nodeName == 'entry') and len(self.items) > self.itemindex + 1:
            self.itemindex = self.itemindex + 1
            item = self.items[self.itemindex]
        if len(self.items) <= self.itemindex:
            return None
        if not len(item.childNodes):
            return None

        details = {}
        try:
            details['number'] = item.getAttribute('id')
            for node in item.childNodes:
                if node.nodeType == Node.ELEMENT_NODE and len(node.childNodes) > 0:
                    if node.nodeName == 'color':
                        value = node.childNodes[0].data.strip()
                        if value == 'Color':
                            details['color'] = 1
                        elif value == 'Black & White':
                            details['color'] = 2
                    elif node.nodeName == 'region':
                        details['region'] = node.childNodes[0].data.strip()
                    elif node.nodeName == 'running-time':
                        details['runtime'] = node.childNodes[0].data.strip()
                        try:
                            details['runtime'] = int(details['runtime'])
                        except:
                            details['runtime'] = 0
                    elif node.nodeName == 'year':
                        details['year'] = node.childNodes[0].data.strip()
                    elif node.nodeName == 'orig-title':
                        details['o_title'] = node.childNodes[0].data.strip()
                    elif node.nodeName == 'title':
                        details['title'] = node.childNodes[0].data.strip()
                    elif node.nodeName == 'directors':
                        details['director'] = self._joinXmlNodes(node.getElementsByTagName('director'))
                    elif node.nodeName == 'writers':
                        details['screenplay'] = self._joinXmlNodes(node.getElementsByTagName('writer'))
                    elif node.nodeName == 'o_site':
                        details['o_site'] = node.childNodes[0].data.strip()
                    elif node.nodeName == 'url':
                        details['site'] = node.childNodes[0].data.strip()
                    elif node.nodeName == 'nationalitys':
                        details['country'] = self._joinXmlNodes(node.getElementsByTagName('nationality'))
                    elif node.nodeName == 'genres':
                        details['genre'] = self._joinXmlNodes(node.getElementsByTagName('genre'))
                    elif node.nodeName == 'certification':
                        details['classification'] = node.childNodes[0].data.strip()
                    elif node.nodeName == 'casts':
                        details['cast'] = self._joinCastNodes(node.getElementsByTagName('cast'), separator = "\n")
                    elif node.nodeName == 'plot':
                        details['plot'] = node.childNodes[0].data.strip()
                    elif node.nodeName == 'comments':
                        details['notes'] = node.childNodes[0].data.strip()
                    elif node.nodeName == 'cover':
                        imgfile = node.childNodes[0].data.strip()
                        # use 'image' field, 'poster' field is buggy, bug #913283
                        # https://bugs.launchpad.net/griffith/+bug/913283
                        details['image'] = os.path.join(self.zipdir, 'images', imgfile)
        except EOFError:
            details = None
        except Exception as e:
            log.exception('')
            details = None

        self.itemindex = self.itemindex + 1
        return details

    def clear(self):
        """clear plugin before next source file"""
        IP.clear(self)
        if self.filedom:
            rmtree(self.zipdir)
            self.zipdir = None
            self.filedom.unlink()
            self.filedom = None
            self.fileversion = None
            self.items = None
            self.itemindex = 0

    def destroy(self):
        """close all resources"""
        IP.destroy(self)

    def read_fileversion(self):
        version = None
        try:
            self.zipdir = self._extractZip(self.filename)
            self.filedom = minidom.parse(os.path.join(self.zipdir, 'tellico.xml'))
            rootElement = self.filedom.getElementsByTagName('tellico')[0]
            version = rootElement.getAttribute('syntaxVersion')
        except Exception as e:
            log.error(str(e))
            if self.filedom:
                self.filedom.unlink()
                self.filedom = None
        log.info('Tellico: Found file version %s' % version)
        return version

    def _extractZip(self, filename):
        zf = zipfile.ZipFile(filename, 'r')
        tmpdir = mkdtemp(prefix = 'griffit2tellico')
        zf.extractall(path = tmpdir)
        return tmpdir

    def _joinXmlNodes(self, elements, separator = ', '):
        ret = ''
        for element in elements:
            if len(element.childNodes) > 0:
                ret = ret + element.childNodes[0].data.strip() + separator

        # chop off last separator
        if len(elements) > 0:
            ret = ret[:-len(separator)]
        return ret

    # join nodes for cast
    def _joinCastNodes(self, elements, separator = ', '):
        """
        we assume that this format:
            <cast>
            <column>Actor/Actress</column>
            <column>Role</column>
            </cast>

        ideally the columns likely came from header, which may differ:
            <field flags="3" title="Cast" category="Cast" format="2" type="8" name="cast" description="...">
                <prop name="column1" >Actor/Actress</prop>
                <prop name="column2" >Role</prop>
                <prop name="columns" >2</prop>
            </field>
        """

        ret = ''
        for element in elements:
            actor = None
            columns = element.getElementsByTagName('column')
            actor = columns[0].childNodes[0].data.strip()
            if len(columns) > 1 and len(columns[1].childNodes) > 0:
                actor = actor + _(' as ') + columns[1].childNodes[0].data.strip()

            if actor:
                ret = ret + actor + separator

        # chop off last separator
        if len(elements) > 0:
            ret = ret[:-len(separator)]

        return ret
