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

__revision__ = '$Id$'

# Copyright (c) 2005-2011 Vasco Nunes, 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 byp
# 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
from gi.repository import Gtk
from gi.repository import GdkPixbuf
from sqlalchemy.exc import IntegrityError

import quick_filter
import initialize
import main_treeview
import importlib
import db
import gutils
from gutils import read_file
from gettext import gettext as _

log = logging.getLogger("Griffith")


# widgets ###################################################


def clear(self):
    """clears all fields in dialog"""
    set_details(self, {})
    self.widgets['add']['cb_only_empty'].set_active(False)


def add_movie(self, details=None):
    if details is None:
        details = {}
    set_details(self, details)

    self.active_plugin = ''
    self.widgets['add']['add_button'].show()
    self.widgets['add']['add_close_button'].show()
    self.widgets['add']['clear_button'].show()
    self.widgets['add']['save_button'].hide()
    self.widgets['add']['window'].set_title(_('Add a new movie'))
    self.widgets['add']['window'].show()


def edit_movie(self, details=None):
    if details is None:
        details = {}
    if 'number' not in details:
        details['number'] = gutils.find_next_available(self.db)
    self.selected_iter_edit = self.selected_iter
    set_details(self, details)
    self.widgets['add']['add_button'].hide()
    self.widgets['add']['add_close_button'].hide()
    self.widgets['add']['clear_button'].show()
    self.widgets['add']['save_button'].show()
    self.widgets['add']['window'].set_title(_('Edit movie'))
    self.widgets['add']['window'].show()


def update_movie(self):
    session = self.db.Session()

    if self._am_movie_id is not None:
        movie = (session.query(db.Movie)
                 .filter_by(movie_id=self._am_movie_id).one())
    else:
        movie = session.query(db.Movie).filter_by(movie_id=self._movie_id).one()
    if movie is None:  # movie was deleted in the meantime
        return add_movie_db(self, True)

    details = get_details(self)

    old_poster_md5 = movie.poster_md5
    new_poster_md5 = old_poster_md5
    if details['image']:
        if old_poster_md5 != details['image']:
            # details["image"] can contain MD5 or file path
            new_image_path = details['image']
            if not os.path.isfile(new_image_path):
                new_image_path = os.path.join(
                    self.locations['temp'], "poster_%s.jpg" % details['image'])
            if not os.path.isfile(new_image_path):
                log.warning("cannot read temporary file: %s", new_image_path)
            else:
                new_poster_md5 = gutils.md5sum(open(new_image_path, 'rb'))
                if session.query(db.Poster).filter_by(
                        md5sum=new_poster_md5).count() == 0:
                    try:
                        data = read_file(new_image_path, 'rb')
                    except Exception as ex:
                        log.warning(f"cannot read poster data, {ex}")
                        old_poster_md5 = new_poster_md5
                    else:
                        poster = db.Poster(md5sum=new_poster_md5, data=data)
                        del details["image"]
                        details['poster_md5'] = new_poster_md5
                        session.add(poster)
                else:
                    details['poster_md5'] = new_poster_md5
    else:
        details['poster_md5'] = None

    update_movie_instance(movie, details, session)
    session.add(movie)

    # delete old image
    if old_poster_md5 and old_poster_md5 != new_poster_md5:
        import delete
        old_poster = session.query(db.Poster).filter_by(md5sum=old_poster_md5).first()
        if old_poster and len(old_poster.movies) == 1:
            # other movies are not using the same poster
            session.delete(old_poster)
            delete.delete_poster_from_cache(old_poster_md5, self.locations['posters'])

    if commit(session):
        main_treeview.setmovie(self, movie, self.selected_iter_edit[0], self.treemodel)

        # close add window
        self.widgets['add']['window'].hide()
        # refresh
        self.treeview_clicked()
        self.update_statusbar(_('Movie information has been updated'))
    return True


def change_rating_from_slider(self):
    rating = int(self.widgets['add']['rating_slider'].get_value())
    self.widgets['add']['image_rating'].show()
    try:
        rimage = int(str(self.config.get('rating_image')))
    except Exception as ex:
        log.error(f"not value for 'rating_image available, {ex}")
        rimage = 0
    if rimage:
        prefix = ''
    else:
        prefix = "meter"
    rating_file = "%s/%s0%d.png" % (self.locations['images'], prefix, rating)
    _handler = self.widgets['add']['image_rating'].set_from_pixbuf(
        GdkPixbuf.Pixbuf.new_from_file(rating_file))


def populate_with_results(self):
    w = self.widgets['add']
    if self.found_results_id:
        m_id = self.found_results_id
    else:
        self.found_results_id = 0
        treeselection = self.widgets['results']['treeview'].get_selection()
        tmp_model, tmp_iter = treeselection.get_selected()
        if tmp_iter is None:
            return False
        m_id = tmp_model.get_value(tmp_iter, 0)

    self.treemodel_results.clear()
    self.widgets['results']['window'].hide()
    log.debug(f"self.found_results_id: {self.found_results_id}, m_id={m_id}")

    plugin_name = 'PluginMovie' + self.active_plugin
    plugin = __import__(plugin_name)
    self.movie = plugin.Plugin(m_id)
    self.movie.locations = self.locations
    self.movie.config = self.config
    fields_to_fetch = ['o_title', 'title', 'director', 'plot', 'cast',
                       'country', 'genre', 'classification', 'studio',
                       'o_site', 'site', 'trailer', 'year', 'notes', 'runtime',
                       'image', 'rating', 'screenplay', 'cameraman',
                       'resolution', 'barcode']
    # remove fields that user doesn't want to fetch: (see preferences window)
    fields_to_fetch = [i for i in fields_to_fetch if self.config.get("s_%s" % i, True, section='add')]

    if w['cb_only_empty'].get_active():  # only empty fields
        details = get_details(self)
        fields_to_fetch = [i for i in fields_to_fetch if details[i] is None or details[i] == 0.0]
    self.movie.fields_to_fetch = fields_to_fetch

    if not self.movie.get_movie(w['window']):
        return False
    self.movie.parse_movie()

    if 'year' in fields_to_fetch:
        w['year'].set_value(int(self.movie.year))
        fields_to_fetch.pop(fields_to_fetch.index('year'))
        log.debug(f"CFG: 'year': {self.movie.year}")
    if 'runtime' in fields_to_fetch:
        w['runtime'].set_value(int(self.movie.runtime))
        fields_to_fetch.pop(fields_to_fetch.index('runtime'))
        log.debug(f"CFG: 'runtime': {self.movie.runtime}")
    if 'cast' in fields_to_fetch:
        cast_buffer = w['cast'].get_buffer()
        cast_buffer.set_text(gutils.convert_entities(self.movie.cast))
        fields_to_fetch.pop(fields_to_fetch.index('cast'))
        log.debug(f"CFG: 'cast': '''{self.movie.cast}'''")
    if 'plot' in fields_to_fetch:
        plot_buffer = w['plot'].get_buffer()
        plot_buffer.set_text(gutils.convert_entities(self.movie.plot))
        fields_to_fetch.pop(fields_to_fetch.index('plot'))
        log.debug(f"CFG: 'plot': '''{self.movie.plot}'''")
    if 'notes' in fields_to_fetch:
        notes_buffer = w['notes'].get_buffer()
        notes_buffer.set_text(gutils.convert_entities(self.movie.notes))
        fields_to_fetch.pop(fields_to_fetch.index('notes'))
        log.debug(f"CFG: 'notes': '''{self.movie.notes}'''")
    if 'rating' in fields_to_fetch:
        if self.movie.rating:
            w['rating_slider'].set_value(float(self.movie.rating))
        fields_to_fetch.pop(fields_to_fetch.index('rating'))
        log.debug(f"CFG: 'rating': {self.movie.rating}")
    if 'resolution' in fields_to_fetch:
        w['resolution'].get_child().set_text(gutils.convert_entities(self.movie.resolution))
        fields_to_fetch.pop(fields_to_fetch.index('resolution'))
        log.debug(f"CFG: 'resolution': '{self.movie.resolution}'")
    # poster
    if 'image' in fields_to_fetch:
        log.debug(f"[populate_with_results]: "
                  f"self.movie.image_url: {self.movie.image_url} "
                  f"self.movie.image: {self.movie.image}")
        w['image'].set_text('')
        if self.movie.image:
            image_path = self.movie.image
            log.debug(f"image_path: {image_path} "
                      f"exists: {os.path.exists(image_path)}")
            try:
                _handler = self.Image.set_from_file(image_path)
                pixbuf = self.Image.get_pixbuf()
                width = 200  # old value: 100
                height = 280  # old value: 140
                w['picture'].set_from_pixbuf(pixbuf.scale_simple(
                    width, height, 3))
                w['image'].set_text(image_path)
                w['aremove_poster'].set_sensitive(True)
            except Exception as exc:
                log.debug(f"Exception: {exc}")
                image_path = gutils.get_defaultimage_fname(self)
                _handler = self.Image.set_from_file(image_path)
                w['picture'].set_from_pixbuf(self.Image.get_pixbuf())
                w['aremove_poster'].set_sensitive(False)
        else:
            image_path = gutils.get_defaultimage_fname(self)
            _handler = self.Image.set_from_file(image_path)
            pixbuf = self.Image.get_pixbuf()
            w['picture'].set_from_pixbuf(pixbuf)
            w['aremove_poster'].set_sensitive(False)
        fields_to_fetch.pop(fields_to_fetch.index('image'))
        log.debug(f"CFG: 'image': '{self.movie.image}'")
        log.debug(f"CFG: 'image_url': '{self.movie.image_url}'")
    # other fields
    for field in fields_to_fetch:
        w[field].set_text(str(gutils.convert_entities(self.movie[field])))
        log.debug(f"CFG: '{field}': '{self.movie[field]}'")
    return True


def show_websearch_results(self):
    total = self.found_results_id = 0
    for g in self.search_movie.ids:
        if str(g) != '':
            total += 1
    if total > 1:
        self.widgets['results']['window'].show()
        self.widgets['results']['window'].set_keep_above(True)
        key = 0
        self.treemodel_results.clear()
        for row in self.search_movie.ids:
            if str(row) != '':
                title = self.search_movie.titles[key]
                myiter = self.treemodel_results.insert_before(None, None)
                self.treemodel_results.set_value(myiter, 0, str(row))
                self.treemodel_results.set_value(myiter, 1, title)
            key += 1
        self.widgets['results']['treeview'].show()
    elif total == 1:
        self.widgets['results']['treeview'].set_cursor(total - 1)
        for row in self.search_movie.ids:
            if str(row) != '':
                self.found_results_id = str(row)
                populate_with_results(self)
    else:
        gutils.error(_("No results"), self.widgets['add']['window'])


def get_from_web(self):
    """search the movie in web using the active plugin"""
    log.debug("[get_from_web]")
    title = self.widgets['add']['title'].get_text()
    o_title = self.widgets['add']['o_title'].get_text()

    if o_title or title:
        option = gutils.on_combo_box_entry_changed_name(
            self.widgets['add']['source'])
        self.active_plugin = option
        if option is None:
            gutils.error(_("No search plugin selected."))
            log.warning("No search plugin selected.")
            return False
        plugin_name = 'PluginMovie%s' % option
        plugin = __import__(plugin_name)
        if self.debug_mode:
            log.debug('reloading %s', plugin_name)
            import sys
            importlib.reload(sys.modules[plugin_name])
        self.search_movie = plugin.SearchPlugin()
        self.search_movie.config = self.config
        self.search_movie.locations = self.locations
        if o_title:
            self.search_movie.url = self.search_movie.original_url_search
            if self.search_movie.remove_accents:
                self.search_movie.title = gutils.remove_accents(o_title, 'utf-8')
            else:
                self.search_movie.title = o_title
        elif title:
            self.search_movie.url = self.search_movie.translated_url_search
            if self.search_movie.remove_accents:
                self.search_movie.title = gutils.remove_accents(title, 'utf-8')
            else:
                self.search_movie.title = title
        # check if internet connection is available
        try:
            if self.search_movie.search_movies(self.widgets['add']['window']):
                self.search_movie.get_searches()
            log.debug(f"Search movie: {self.search_movie} self.search_movie.ids={self.search_movie.ids}")
            if len(self.search_movie.ids) == 1 and o_title and title:
                self.search_movie.url = self.search_movie.translated_url_search
                if self.search_movie.remove_accents:
                    self.search_movie.title = gutils.remove_accents(title, 'utf-8')
                else:
                    self.search_movie.title = title
                if self.search_movie.search_movies(self.widgets['add']['window']):
                    self.search_movie.get_searches()
            self.show_search_results(self.search_movie)
        except Exception as exc:
            log.exception(f"Caught too broad try-except: {exc}")
            gutils.error(_("Connection failed."))
    else:
        gutils.error(
            _("You should fill the original title\nor the movie title."))
    return True


def source_changed(self):
    option = gutils.on_combo_box_entry_changed_name(self.widgets['add']['source'])
    self.active_plugin = option
    plugin_name = 'PluginMovie' + option
    plugin = __import__(plugin_name)
    self.widgets['add']['plugin_desc'].set_text(
        plugin.plugin_name + "\n" + plugin.plugin_description + "\n"
        + _('Url: ') + plugin.plugin_url + "\n"
        + _('Language: ') + plugin.plugin_language)
    image = os.path.join(self.locations['images'], plugin_name + ".png")
    # if movie plugin logo exists lets use it
    if os.path.exists(image):
        _handler = self.widgets['add']['plugin_image'].set_from_pixbuf(
            GdkPixbuf.Pixbuf.new_from_file(str(image)))


def get_details(self):  # {{{
    w = self.widgets['add']

    cast_buffer = w['cast'].get_buffer()
    notes_buffer = w['notes'].get_buffer()
    plot_buffer = w['plot'].get_buffer()

    t_movies = {
        'cameraman': w['cameraman'].get_text(),
        'classification': w['classification'].get_text(),
        'barcode': str(gutils.digits_only(w['barcode'].get_text())),
        'color': w['color'].get_active(),
        'cond': w['condition'].get_active(),
        'country': w['country'].get_text(),
        'director': w['director'].get_text(),
        'genre': w['genre'].get_text(),
        'image': w['image'].get_text(),
        'layers': w['layers'].get_active(),
        'media_num': w['discs'].get_value(),
        'number': w['number'].get_value(),
        'o_site': w['o_site'].get_text(),
        'o_title': w['o_title'].get_text(),
        'rating': w['rating_slider'].get_value(),
        'region': w['region'].get_active(),
        'resolution': w['resolution'].get_child().get_text().strip(),
        'runtime': w['runtime'].get_text(),
        'screenplay': w['screenplay'].get_text(),
        'site': w['site'].get_text(),
        'studio': w['studio'].get_text(),
        'title': w['title'].get_text(),
        'trailer': w['trailer'].get_text(),
        'year': w['year'].get_value(),
        'collection_id': w['collection'].get_active(),
        'medium_id': w['media'].get_active(),
        'volume_id': w['volume'].get_active(),
        'vcodec_id': w['vcodec'].get_active(),
        'cast': cast_buffer.get_text(cast_buffer.get_start_iter(), cast_buffer.get_end_iter(), False),
        'notes': notes_buffer.get_text(notes_buffer.get_start_iter(), notes_buffer.get_end_iter(), False),
        'plot': plot_buffer.get_text(plot_buffer.get_start_iter(), plot_buffer.get_end_iter(), False),
        'created': None,
        'updated': None
        }
    if self._am_movie_id is not None:
        t_movies['movie_id'] = self._am_movie_id

    if t_movies['collection_id'] > 0:
        t_movies['collection_id'] = self.collection_combo_ids[t_movies['collection_id']]
    else:
        t_movies['collection_id'] = None
    if t_movies['volume_id'] > 0:
        t_movies['volume_id'] = self.volume_combo_ids[t_movies['volume_id']]
    else:
        t_movies['volume_id'] = None
    if t_movies['medium_id'] > 0:
        t_movies['medium_id'] = self.media_ids[t_movies['medium_id']]
    else:
        t_movies['medium_id'] = None
    if t_movies['vcodec_id'] > 0:
        t_movies['vcodec_id'] = self.vcodecs_ids[t_movies['vcodec_id']]
    else:
        t_movies['vcodec_id'] = None
    if t_movies['barcode'] == '0':
        t_movies['barcode'] = None

    if w['seen'].get_active():
        t_movies['seen'] = True
    else:
        t_movies['seen'] = False
    if t_movies['year'] < 1900:
        t_movies['year'] = None

    def get_id(model, text):
        for model_id in model:
            if model_id[1] == text:
                return model_id[0]
        return None

    # languages
    t_movies['languages'] = set()
    # isn't the best but it works. without it the current selection of a language field is lost
    w['lang_treeview'].child_focus(Gtk.DirectionType.TAB_FORWARD)
    for row in self.lang['model']:
        lang_id = get_id(self.lang['lang'], row[0])
        lang_type = get_id(self.lang['type'], row[1])
        acodec = get_id(self.lang['acodec'], row[2])
        achannel = get_id(self.lang['achannel'], row[3])
        subformat = get_id(self.lang['subformat'], row[4])
        t_movies['languages'].add((lang_id, lang_type, acodec, achannel, subformat))

    # tags
    t_movies['tags'] = {}
    for i in self.tags_ids:
        if self.am_tags[i].get_active():
            t_movies['tags'][self.tags_ids[i]] = 1

    validate_details(t_movies)

    return t_movies  # }}}


def set_details(self, item=None):  # {{{
    if item is None:
        item = {}
    if 'movie_id' in item and item['movie_id']:
        self._am_movie_id = item['movie_id']
    else:
        self._am_movie_id = None
    w = self.widgets['add']

    cast_buffer = w['cast'].get_buffer()
    notes_buffer = w['notes'].get_buffer()
    plot_buffer = w['plot'].get_buffer()

    if 'o_title' in item and item['o_title']:
        w['o_title'].set_text(item['o_title'])
    else:
        w['o_title'].set_text('')
    if 'title' in item and item['title']:
        w['title'].set_text(item['title'])
    else:
        w['title'].set_text('')
    if 'number' in item and item['number']:
        w['number'].set_value(int(item['number']))
    else:
        w['number'].set_value(int(gutils.find_next_available(self.db)))
    if 'title' in item and item['title']:
        w['title'].set_text(item['title'])
    if 'year' in item and item['year']:
        w['year'].set_value(gutils.digits_only(item['year'], 2100))
    else:
        w['year'].set_value(0)
    if 'resolution' in item and item['resolution']:
        if self.config.get('use_resolution_alias', True):
            w['resolution'].get_child().set_text(item['resolution'])
        elif 'height' in item and item['height'] and 'width' in item and item['width']:
            w['resolution'].get_child().set_text("%dx%d" % (item['width'], item['height']))
        else:  # fallback to 'resolution'
            w['resolution'].get_child().set_text(item['resolution'])
    else:
        w['resolution'].get_child().set_text('')
    if 'runtime' in item and item['runtime']:
        w['runtime'].set_value(gutils.digits_only(item['runtime']))
    else:
        w['runtime'].set_value(0)
    if 'barcode' in item and item['barcode']:
        w['barcode'].set_text(item['barcode'])
    else:
        w['barcode'].set_text('')
    if 'cameraman' in item and item['cameraman']:
        w['cameraman'].set_text(item['cameraman'])
    else:
        w['cameraman'].set_text('')
    if 'screenplay' in item and item['screenplay']:
        w['screenplay'].set_text(item['screenplay'])
    else:
        w['screenplay'].set_text('')
    if 'country' in item and item['country']:
        w['country'].set_text(item['country'])
    else:
        w['country'].set_text('')
    if 'classification' in item and item['classification']:
        w['classification'].set_text(item['classification'])
    else:
        w['classification'].set_text('')
    if 'studio' in item and item['studio']:
        w['studio'].set_text(item['studio'])
    else:
        w['studio'].set_text('')
    if 'o_site' in item and item['o_site']:
        w['o_site'].set_text(item['o_site'])
    else:
        w['o_site'].set_text('')
    if 'director' in item and item['director']:
        w['director'].set_text(item['director'])
    else:
        w['director'].set_text('')
    if 'site' in item and item['site']:
        w['site'].set_text(item['site'])
    else:
        w['site'].set_text('')
    if 'trailer' in item and item['trailer']:
        w['trailer'].set_text(item['trailer'])
    else:
        w['trailer'].set_text('')
    if 'genre' in item and item['genre']:
        w['genre'].set_text(item['genre'])
    else:
        w['genre'].set_text('')
    if 'color' in item and item['color']:
        w['color'].set_active(gutils.digits_only(item['color'], 3))
    else:
        w['color'].set_active(gutils.digits_only(self.config.get('color', 0, section='defaults'), 3))
    if 'layers' in item and item['layers']:
        w['layers'].set_active(gutils.digits_only(item['layers'], 4))
    else:
        w['layers'].set_active(gutils.digits_only(self.config.get('layers', 0, section='defaults'), 4))
    if 'region' in item and item['region'] >= 0:
        w['region'].set_active(gutils.digits_only(item['region'], 11))
    else:
        w['region'].set_active(gutils.digits_only(self.config.get('region', 0, section='defaults'), 11))
    if 'cond' in item and item['cond'] is not None:
        w['condition'].set_active(gutils.digits_only(item['cond'], 5))
    else:
        w['condition'].set_active(gutils.digits_only(self.config.get('condition', 0, section='defaults'), 5))
    if 'media_num' in item and item['media_num']:
        w['discs'].set_value(gutils.digits_only(item['media_num']))
    else:
        w['discs'].set_value(1)
    if 'rating' in item and item['rating']:
        w['rating_slider'].set_value(gutils.digits_only(item['rating'], 10))
    else:
        w['rating_slider'].set_value(0)
    if 'seen' in item:
        if item['seen'] is True:
            w['seen'].set_active(True)
        else:
            w['seen'].set_active(False)
    else:
        w['seen'].set_active(bool(self.config.get('seen', True, section='defaults')))
    if 'cast' in item and item['cast']:
        cast_buffer.set_text(item['cast'])
    else:
        cast_buffer.set_text('')
    if 'notes' in item and item['notes']:
        notes_buffer.set_text(item['notes'])
    else:
        notes_buffer.set_text('')
    if 'plot' in item and item['plot']:
        plot_buffer.set_text(item['plot'])
    else:
        plot_buffer.set_text('')
    # pos = 0
    if 'medium_id' in item and item['medium_id']:
        pos = gutils.find_key(item['medium_id'], self.media_ids)
    else:
        pos = gutils.find_key(int(self.config.get('media', 0, section='defaults')), self.media_ids)
    if pos is not None:
        w['media'].set_active(int(pos))
    else:
        w['media'].set_active(0)
    # pos = 0
    if 'vcodec_id' in item and item['vcodec_id']:
        pos = gutils.find_key(item['vcodec_id'], self.vcodecs_ids)
    else:
        pos = gutils.find_key(int(self.config.get('vcodec', 0, section='defaults')), self.vcodecs_ids)
    if pos is not None:
        w['vcodec'].set_active(int(pos))
    else:
        w['vcodec'].set_active(0)
    # pos = 0
    if 'volume_id' in item and item['volume_id']:
        pos = gutils.find_key(item['volume_id'], self.volume_combo_ids)
    if pos is not None:
        w['volume'].set_active(int(pos))
    else:
        w['volume'].set_active(0)
    pos = 0
    if 'collection_id' in item and item['collection_id']:
        pos = gutils.find_key(item['collection_id'], self.collection_combo_ids)
    if pos is not None:
        w['collection'].set_active(int(pos))
    else:
        w['collection'].set_active(0)
    # tags
    for tag in self.am_tags:
        self.am_tags[tag].set_active(False)
    if 'tags' in item:
        for tag in item['tags']:
            i = gutils.find_key(tag.tag_id, self.tags_ids)
            self.am_tags[i].set_active(True)
    # languages
    w['lang_treeview'].get_model().clear()
    if 'languages' in item and len(item['languages']) > 0:
        for i in item['languages']:
            self.create_language_row(i)
    # poster
    w['aremove_poster'].set_sensitive(True)
    if 'poster_md5' in item and item['poster_md5']:
        image_path = gutils.get_image_fname(item["poster_md5"], self.db, 'm')
        if not image_path:
            image_path = ''  # isfile doesn't like bool
            w['aremove_poster'].set_sensitive(False)
        w['image'].set_text(item['poster_md5'])
    elif 'image' in item and item['image']:
        if len(item['image']) == 32:  # md5
            image_path = gutils.get_image_fname(item["image"], self.db, 'm')
            if not image_path:
                image_path = ''  # isfile doesn't like bool
                w['aremove_poster'].set_sensitive(False)
            else:
                w['image'].set_text(item['image'])
        else:
            image_path = os.path.join(self.locations['posters'], "m_%s.jpg" % item['image'])
            log.warning("TODO: image=%s", item['image'])
    else:
        w['image'].set_text('')
        image_path = gutils.get_defaultimage_fname(self)
        w['aremove_poster'].set_sensitive(False)
    if not os.path.isfile(image_path):
        image_path = gutils.get_defaultimage_fname(self)
        w['aremove_poster'].set_sensitive(False)
    w['picture'].set_from_file(image_path)

    w['notebook'].set_current_page(0)
    w['o_title'].grab_focus()
    # }}}


def validate_details(t_movies, allow_only=None):
    for i in list(t_movies.keys()):
        if t_movies[i] == '':
            t_movies[i] = None
    for i in ('color', 'cond', 'layers', 'media', 'vcodec'):
        if i in t_movies and t_movies[i] < 1:
            t_movies[i] = None
    for i in ('volume_id', 'collection_id', 'runtime'):
        if i in t_movies and (t_movies[i] is None or int(t_movies[i]) == 0):
            t_movies[i] = None
    if allow_only is not None:
        # iterate over a copy of keys of the dict because removing elements of a dict
        # within a for enumeration of the same dict instance isn't supported
        for i in list(t_movies.keys()):
            if i not in allow_only:
                t_movies.pop(i)


# ## database part #############################################


def add_movie_db(self, close):
    session = self.db.Session()
    details = get_details(self)

    if not details['o_title'] and not details['title']:
        gutils.error(
            _("You should fill the original title\nor the movie title."),
            parent=self.widgets['add']['window'])
        return False

    asked = False
    if details['o_title']:
        if (session.query(db.Movie)
                .filter_by(o_title=details['o_title']).count() > 0):
            asked = True
            if not gutils.question(_('Movie with that title already exists, are'
                                     ' you sure you want to add?'),
                                   self.widgets['add']['window']):
                return False
    if not asked and details['title']:
        if session.query(db.Movie).filter_by(title=details['title']).count() > 0:
            if not gutils.question(_('Movie with that title already exists, are'
                                     ' you sure you want to add?'),
                                   self.widgets['add']['window']):
                return False
    if details['image']:
        tmp_image_path = original_image_path = details['image']
        if os.path.isfile(tmp_image_path):
            with open(tmp_image_path, 'rb') as file_object:
                new_poster_md5 = gutils.md5sum(file_object)
                if session.query(db.Poster).filter_by(
                        md5sum=new_poster_md5).count() == 0:
                    try:
                        file_object.seek(0, 0)
                        data = file_object.read()
                    except Exception as exc:
                        log.warning(f"cannot read poster data {exc}")
                    else:
                        poster = db.Poster(md5sum=new_poster_md5, data=data)
                        del details["image"]
                        details["poster_md5"] = new_poster_md5
                        session.add(poster)
                else:
                    details["poster_md5"] = new_poster_md5
            try:
                if not tmp_image_path == original_image_path:
                    os.remove(tmp_image_path)
            except Exception as exc:
                log.warning(f"cannot remove temporary file {tmp_image_path}"
                            f" {exc}")
        else:
            log.warning(f"cannot read temporary file: {tmp_image_path}")

    movie = update_movie_instance(None, details, session)
    session.add(movie)
    if not commit(session):
        return False

    # create new entry, unselect current movie and
    # select new entry in main treelist
    myiter = main_treeview.addmovie(self, movie)
    main_treeview.select(self, None)
    main_treeview.select(self, myiter)

    # update statusbar
    self.total += 1
    self.count_statusbar()

    clear(self)

    if close:
        self.hide_add_window()
    return True


def clone_movie(self) -> bool:
    session = self.db.Session()

    if self.selected_iter[0] is None:
        log.warning("cannot clone movie: no item selected")
        return False
    number = self.selected[0]
    movie = session.query(db.Movie).filter_by(number=number).first()

    if movie is None:
        log.warning("cannot clone movie: Movie(%s) not found", number)
        return False

    next_number = gutils.find_next_available(self.db)

    # integer problem workaround
    if int(movie.seen) == 1:
        seen = True
    else:
        seen = False
    new_movie = db.Movie()
    new_movie.barcode = movie.barcode
    new_movie.cameraman = movie.cameraman
    new_movie.cast = movie.cast
    new_movie.classification = movie.classification
    new_movie.collection_id = movie.collection_id
    new_movie.color = movie.color
    new_movie.cond = movie.cond
    new_movie.country = movie.country
    new_movie.director = movie.director
    new_movie.genre = movie.genre
    new_movie.languages = movie.languages
    new_movie.layers = movie.layers
    new_movie.loaned = movie.loaned
    new_movie.loans = movie.loans
    new_movie.media_num = movie.media_num
    new_movie.medium_id = movie.medium_id
    new_movie.notes = movie.notes
    new_movie.number = next_number
    new_movie.o_site = movie.o_site
    new_movie.o_title = movie.o_title
    new_movie.plot = movie.plot
    new_movie.poster_md5 = movie.poster_md5
    new_movie.rating = movie.rating
    new_movie.ratio_id = movie.ratio_id
    new_movie.region = movie.region
    new_movie.resolution = movie.resolution
    new_movie.runtime = movie.runtime
    new_movie.screenplay = movie.screenplay
    new_movie.seen = seen
    new_movie.site = movie.site
    new_movie.studio = movie.studio
    new_movie.tags = movie.tags
    new_movie.title = movie.title
    new_movie.trailer = movie.trailer
    new_movie.vcodec_id = movie.vcodec_id
    new_movie.volume_id = movie.volume_id
    new_movie.year = movie.year

    # save
    session.add(new_movie)
    if not commit(session):
        return False

    if movie.poster_md5:
        image_path = gutils.get_image_fname(movie.poster_md5, self.db)
        if not image_path or not os.path.isfile(image_path):
            image_path = gutils.get_defaultimage_fname(self)
        _handler = self.Image.set_from_file(image_path)

    # change_filter calls populate_treeview which updates the status bar
    quick_filter.change_filter(self)
    return True


def update_movie_instance(movie, details, session):
    if not movie:
        movie = db.Movie()
    if details is not None:
        t_tags = t_languages = None
        if 'tags' in details:
            t_tags = details.pop('tags')
        if 'languages' in details:
            t_languages = details.pop('languages')
        # for i in db.tables.movies.columns.keys():
        for i in details:
            if i not in ('created', 'updated') and hasattr(movie, i):
                setattr(movie, i, details[i])

        # clear previous data (in case of updates)
        if movie.languages:
            movie.languages = []
        if movie.tags:
            movie.tags = []
        # languages
        if t_languages is not None:
            for lang in t_languages:
                if lang[0] > 0:
                    ml = db.MovieLang(
                        lang_id=lang[0], movie_type=lang[1], acodec_id=lang[2],
                        achannel_id=lang[3], subformat_id=lang[4])
                    movie.languages.append(ml)
        # tags
        if t_tags is not None:
            for tag in list(t_tags.keys()):
                db_tag = session.query(db.Tag).filter_by(tag_id=tag).one()
                # movie.tags.append(db.MovieTag(tag_id=tag))
                movie.tags.append(db_tag)
        if hasattr(movie, 'image') and movie.image:  # TODO: remove it once image will be removed from movies_table
            movie.image = None  # remove MD5 or link
    return movie


def commit(session):
    try:
        session.commit()
    except IntegrityError as ex:
        session.rollback()
        log.warning("Cannot commit movie: %s", ex)
        gutils.warning(str(ex.orig))
        return False
    except Exception as e:
        log.error("Unexpected problem: %s", e)
        return False
    return True


def add_medium(self, name):
    session = self.db.Session()
    medium = db.Medium(name=name)
    session.add(medium)
    try:
        session.commit()
    except Exception as ex:
        session.rollback()
        log.warning("Cannot add medium entry: %s", ex)
    else:
        initialize.media_combos(self)
    return medium.medium_id


def add_vcodec(self, name):
    session = self.db.Session()
    vcodec = db.VCodec(name=name)
    session.add(vcodec)
    try:
        session.commit()
    except Exception as ex:
        session.rollback()
        log.warning("Cannot add video codec entry: %s", ex)
    else:
        initialize.vcodec_combos(self)
    return vcodec.vcodec_id


def add_volume(self, name):
    session = self.db.Session()
    vol = db.Volume(name=name)
    session.add(vol)
    try:
        session.commit()
    except Exception as ex:
        session.rollback()
        log.warning("Cannot add volume: %s", ex)
    else:
        initialize.update_volume_combo_ids(self)
        initialize.fill_volumes_combo(self, vol.volume_id)
    return vol.volume_id


def add_collection(self, name):
    session = self.db.Session()
    col = db.Collection(name=name)
    session.add(col)
    try:
        session.commit()
    except Exception as ex:
        session.rollback()
        log.warning("Cannot add collection: %s", ex)
    else:
        initialize.update_collection_combo_ids(self)
        initialize.fill_collections_combo(self, col.collection_id)
    return col.collection_id


def change_poster(self):
    from edit import change_poster_select_file
    if change_poster_select_file(self, -1, change_poster_new_movie):
        self.widgets['add']['aremove_poster'].set_sensitive(True)


def change_poster_new_movie(self, _number, filename):
    try:
        _handler = self.Image.set_from_file(filename)
        pixbuf = self.Image.get_pixbuf()
        handler = self.widgets['add']['picture'].set_from_pixbuf(
            # pixbuf.scale_simple(100, 140, 3))
            pixbuf.scale_simple(200, 280, 3))
        gutils.garbage(handler)
        self.widgets['add']['image'].set_text(filename)
        return True
    except Exception as exc:
        log.warning(f"Too broad exception, but handled: {exc}")
        image = gutils.get_defaultimage_fname(self)
        _handler = self.Image.set_from_file(image)
        handler = self.widgets['add']['picture'].set_from_pixbuf(
            self.Image.get_pixbuf())
        gutils.garbage(handler)
        return False


def delete_poster(self):
    w = self.widgets['add']
    w['image'].set_text('')
    image_path = gutils.get_defaultimage_fname(self)
    w['picture'].set_from_file(image_path)
    w['aremove_poster'].set_sensitive(False)
