# -*- coding: UTF-8 -*-

__revision__ = '$Id$'

# Copyright © 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 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 gettext
import logging
import math
import os
import re
import sys
from glob import glob
from locale import getdefaultlocale

from gi.repository import GObject
from gi.repository import Gtk
from gi.repository import GdkPixbuf

import db
import gutils

try:
    from gi.repository import GtkSpell
    spell_support = 1
except:
    spell_support = 0

log = logging.getLogger("Griffith")


def locations(self, home_dir):
    defaultLang, defaultEnc = getdefaultlocale()
    if defaultEnc is None:
        defaultEnc = 'UTF-8'
    locations = {}
    locations['exec'] = os.path.abspath(os.path.dirname(sys.argv[0]))  # deprecated
    locations['lib'] = os.path.dirname(__file__)
    locations['home'] = home_dir

    if os.name == 'nt' or os.name.startswith('win'):  # win32, win64
        locations['movie_plugins'] = "%s\\lib\\plugins\\movie" % locations['exec']
        locations['export_plugins'] = "%s\\lib\\plugins\\export" % locations['exec']
        locations['images'] = "%s\\images" % locations['exec']
        locations['share'] = locations['images']
        locations['glade'] = "%s\\glade\\" % locations['exec']
        locations['desktop'] = ''
        locations['i18n'] = "%s\\i18n" % locations['exec']
        os.environ['PATH'] += ";lib;"

        # windows hack for locale setting
        lang = os.getenv('LANG')
        if lang is None:
            if defaultLang:
                lang = defaultLang
        if lang:
            os.environ['LANG'] = lang

    elif os.name == 'posix':
        locations['share'] = os.path.abspath(os.path.join(locations['lib'], '..'))
        locations['glade'] = os.path.join(locations['share'], 'glade')
        locations['i18n'] = os.path.abspath(os.path.join(locations['share'], '..', 'locale'))
        if not os.path.isdir(locations['i18n']):
            locations['i18n'] = os.path.join(locations['share'], 'i18n')
        #some locations
        locations['movie_plugins'] = os.path.join(locations['lib'], 'plugins', 'movie')
        locations['export_plugins'] = os.path.join(locations['lib'], 'plugins', 'export')
        locations['images'] = os.path.join(locations['share'], 'images')
        locations['desktop'] = os.path.join(os.path.expanduser('~'), 'Desktop')
    else:
        print('Operating system not supported')
        sys.exit()

    from tempfile import gettempdir
    locations['temp'] = gettempdir()

    try:
        if not os.path.exists(locations['home']):
            log.info('Creating %s', locations['home'])
            os.makedirs(locations['home'])
        else:
            log.info("Using Griffith directory: %s", locations['home'])
    except OSError:
        log.info('Unable to create griffith directory.')
        raise
        sys.exit()

    if not os.access(locations['home'], os.W_OK):
        log.info('Cannot write to griffith directory, %s', locations['home'])
        sys.exit()

    locations['posters'] = os.path.join(locations['home'], 'posters')
    if not os.path.isdir(locations['posters']):
        os.makedirs(locations['posters'])

    # includes plugins in system path for easier importing
    sys.path.append(locations['lib'])
    sys.path.append(locations['movie_plugins'])
    sys.path.append(locations['export_plugins'])

    self.locations = locations
    return locations


def gui(self):
    self._ = None

    if os.name in ('mac') or \
            (hasattr(os, 'uname') and os.uname()[0] == 'Darwin'):
        self.mac = True
    else:
        self.mac = False

    self.griffith_dir = self.locations['home']    # deprecated

    if self.windows:
        Gtk.rc_parse('%s\\gtkrc' % self.locations['exec'])

    gf = os.path.join(self.locations['glade'], 'griffith.ui')
    from widgets import define_widgets
    define_widgets(self, gf)

    self.pdf_reader = self.config.get('pdf_reader')


def i18n(self, location):
    gettext.bindtextdomain('griffith', location)
    gettext.textdomain('griffith')
    #Gtk.glade.bindtextdomain('griffith', location)
    #Gtk.glade.textdomain('griffith')
    gettext.install('griffith', location)


def toolbar(self):
    """if toolbar is hide in config lets hide the widget"""
    if not self.config.get('view_toolbar', True, section='window'):
        self.widgets['toolbar'].hide()
        self.widgets['menu']['toolbar'].set_active(False)
    else:
        self.widgets['toolbar'].show()
        self.widgets['menu']['toolbar'].set_active(True)
    if not self.config.get('view_ext_toolbar', True, section='window'):
        self.widgets['extensions']['toolbar_hb'].hide()
        self.widgets['menu']['ext_toolbar'].set_active(False)
    else:
        self.widgets['extensions']['toolbar_hb'].show()
        self.widgets['menu']['ext_toolbar'].set_active(True)


def treeview(self):
    import main_treeview
    # set up the treeview to do multiple selection
    tree = self.widgets['treeview']
    self.treemodel = Gtk.TreeStore(str, GdkPixbuf.Pixbuf, str, str, str, str, bool, str, str, int, str, str)
    tree.set_model(self.treemodel)
    tree.set_headers_visible(True)
    tree.get_selection().set_mode(Gtk.SelectionMode.MULTIPLE)
    self.widgets['treeview'].get_selection().connect("changed", main_treeview.on_tree_selection, self)

    # number column
    renderer = Gtk.CellRendererText()
    self.number_column = Gtk.TreeViewColumn(_('No.'), renderer, text=0)
    self.number_column.set_name('number')
    self.number_column.set_resizable(True)
    self.number_column.set_sort_column_id(0)
    self.number_column.set_reorderable(True)
    self.widgets['treeview'].append_column(self.number_column)
    # pic column
    renderer = Gtk.CellRendererPixbuf()
    self.image_column = Gtk.TreeViewColumn(_('Image'), renderer, pixbuf=1)
    self.image_column.set_name('image')
    self.image_column.set_resizable(False)
    self.image_column.set_reorderable(True)
    self.widgets['treeview'].append_column(self.image_column)
    # original title column
    renderer = Gtk.CellRendererText()
    self.otitle_column = Gtk.TreeViewColumn(_('Original Title'), renderer, text=2)
    self.otitle_column.set_name('otitle')
    self.otitle_column.set_resizable(True)
    self.otitle_column.set_sort_column_id(2)
    self.otitle_column.set_reorderable(True)
    self.widgets['treeview'].append_column(self.otitle_column)
    # title column
    renderer = Gtk.CellRendererText()
    self.title_column = Gtk.TreeViewColumn(_('Title'), renderer, text=3)
    self.title_column.set_name('title')
    self.title_column.set_resizable(True)
    self.title_column.set_sort_column_id(3)
    self.title_column.set_reorderable(True)
    self.widgets['treeview'].append_column(self.title_column)
    # director column
    renderer = Gtk.CellRendererText()
    self.director_column = Gtk.TreeViewColumn(_('Director'), renderer, text=4)
    self.director_column.set_name('director')
    self.director_column.set_sort_column_id(4)
    self.director_column.set_resizable(True)
    self.director_column.set_reorderable(True)
    self.widgets['treeview'].append_column(self.director_column)
    # genre column
    renderer = Gtk.CellRendererText()
    self.genre_column = Gtk.TreeViewColumn(_('Genre'), renderer, text=5)
    self.genre_column.set_name('genre')
    self.genre_column.set_sort_column_id(5)
    self.genre_column.set_resizable(True)
    self.genre_column.set_reorderable(True)
    self.widgets['treeview'].append_column(self.genre_column)
    # seen column
    renderer = Gtk.CellRendererToggle()
    self.seen_column = Gtk.TreeViewColumn(_('Seen it'), renderer, active=6)
    self.seen_column.set_name('seen')
    self.seen_column.set_sort_column_id(6)
    self.seen_column.set_resizable(True)
    self.seen_column.set_reorderable(True)
    self.widgets['treeview'].insert_column(self.seen_column, 1)
    # year column
    renderer = Gtk.CellRendererText()
    renderer.set_property('xalign', 0.5)
    self.year_column = Gtk.TreeViewColumn(_('Year'), renderer, text=7)
    self.year_column.set_name('year')
    self.year_column.set_sort_column_id(7)
    self.year_column.set_resizable(True)
    self.year_column.set_alignment(0.5)
    self.year_column.set_reorderable(True)
    self.widgets['treeview'].append_column(self.year_column)
    # runtime column
    renderer = Gtk.CellRendererText()
    renderer.set_property('xalign', 1)
    self.runtime_column = Gtk.TreeViewColumn(_('Runtime'), renderer, text=8)
    self.runtime_column.set_name('runtime')
    self.runtime_column.set_sort_column_id(8)
    self.runtime_column.set_resizable(True)
    self.runtime_column.set_alignment(1)
    self.runtime_column.set_reorderable(True)
    self.widgets['treeview'].append_column(self.runtime_column)
    # rating column
    renderer = Gtk.CellRendererText()
    renderer.set_property('xalign', 0.5)
    self.rating_column = Gtk.TreeViewColumn(_('Rating'), renderer, text=9)
    self.rating_column.set_name('rating')
    self.rating_column.set_sort_column_id(9)
    self.rating_column.set_resizable(True)
    self.rating_column.set_alignment(0.5)
    self.rating_column.set_reorderable(True)
    self.widgets['treeview'].append_column(self.rating_column)
    # created column
    renderer = Gtk.CellRendererText()
    renderer.set_property('xalign', 0.5)
    self.created_column = Gtk.TreeViewColumn(_('Created'), renderer, text=10)
    self.created_column.set_name('created')
    self.created_column.set_sort_column_id(10)
    self.created_column.set_resizable(True)
    self.created_column.set_alignment(0.5)
    self.created_column.set_reorderable(True)
    self.widgets['treeview'].append_column(self.created_column)
    # updated column
    renderer = Gtk.CellRendererText()
    renderer.set_property('xalign', 0.5)
    self.updated_column = Gtk.TreeViewColumn(_('Updated'), renderer, text=11)
    self.updated_column.set_name('updated')
    self.updated_column.set_sort_column_id(11)
    self.updated_column.set_resizable(True)
    self.updated_column.set_alignment(0.5)
    self.updated_column.set_reorderable(True)
    self.widgets['treeview'].append_column(self.updated_column)

    # reflect saved column order and column sizes
    columnorder = self.config.get('columnorder', None, section='mainlist')
    if columnorder:
        columnmapping = dict([(column.get_name(), column) for column in self.widgets['treeview'].get_columns()])
        currentcol = None
        columnordersplitted = re.split('[ \t]*,[ \t]*', columnorder)
        for col in columnordersplitted:
            if col in columnmapping:
                self.widgets['treeview'].move_column_after(columnmapping[col], currentcol)
                currentcol = columnmapping[col]
    columnsizes = self.config.get('columnsizes', None, section='mainlist')
    if columnsizes:
        columnsizessplitted = re.split('[ \t]*,[ \t]*', columnsizes)
        currentcol = 0
        for columnsize in columnsizessplitted:
            try:
                columnsize = int(columnsize)
                self.widgets['treeview'].get_column(currentcol).set_sizing(Gtk.TreeViewColumnSizing.FIXED)
                self.widgets['treeview'].get_column(currentcol).set_fixed_width(columnsize)
            except:
                pass
            currentcol = currentcol + 1
    # reflect saved column sorting
    columnsortid = self.config.get('columnsortid', None, section='mainlist')
    columnsortorder = self.config.get('columnsortorder', None, section='mainlist')
    try:
        if columnsortid:
            columnsortid = int(columnsortid)
            if columnsortorder:
                columnsortorder = Gtk.SortType(int(columnsortorder))
            else:
                columnsortorder = Gtk.SortType.ASCENDING
            self.treemodel.set_sort_column_id(columnsortid, columnsortorder)
    except:
        log.exception('')
    # add data to treeview
    self.total = self.db.session.query(db.Movie).count()
    self.widgets['treeview'].set_search_equal_func(search_func_treeview)
    self.widgets['treeview'].show()

    # adding some completion fields - TODO: move it to initialize
    self.completion = Gtk.EntryCompletion()
    self.widgets['add']['o_title'].set_completion(self.completion)
    self.completion.set_model(self.treemodel)
    self.completion.set_text_column(3)
    # ... title
    self.completion_t = Gtk.EntryCompletion()
    self.widgets['add']['title'].set_completion(self.completion_t)
    self.completion_t.set_model(self.treemodel)
    self.completion_t.set_text_column(4)


def search_func_treeview(model, column, key, iter):
    return not (str(model.get_value(iter, 0)).startswith(key) or
        str(model.get_value(iter, 2)).lower().startswith(key.lower()) or
        str(model.get_value(iter, 3)).lower().startswith(key.lower()))


def loans_treeview(self):
    self.loans_treemodel = Gtk.TreeStore(str, str, str)  # move to self.widgets
    self.widgets['movie']['loan_history'].set_model(self.loans_treemodel)
    self.widgets['movie']['loan_history'].set_headers_visible(True)
    # loan date
    renderer = Gtk.CellRendererText()
    self.date_column = Gtk.TreeViewColumn(_('Loan Date'), renderer, text=0)
    self.date_column.set_resizable(True)
    self.widgets['movie']['loan_history'].append_column(self.date_column)
    self.date_column.set_sort_column_id(0)
    # return date
    renderer = Gtk.CellRendererText()
    self.return_column = Gtk.TreeViewColumn(_('Return Date'), renderer, text=1)
    self.return_column.set_resizable(True)
    self.widgets['movie']['loan_history'].append_column(self.return_column)
    # loan to
    renderer = Gtk.CellRendererText()
    self.loaner_column = Gtk.TreeViewColumn(_('Loaned To'), renderer, text=2)
    self.loaner_column.set_resizable(True)
    self.widgets['movie']['loan_history'].append_column(self.loaner_column)


def lang_treeview(self):
    treeview = self.widgets['add']['lang_treeview']
    self.lang['model'] = Gtk.TreeStore(str, str, str, str, str)
    treeview.set_model(self.lang['model'])
    treeview.set_headers_visible(True)

    model = self.lang['lang'] = Gtk.ListStore(int, str)
    for i in self.db.session.query(db.Lang.lang_id, db.Lang.name).all():
        model.append([i.lang_id, i.name])
    combo = Gtk.CellRendererCombo()
    combo.set_property('model', model)
    combo.set_property('text-column', 1)
    combo.set_property('editable', True)
    combo.set_property('has-entry', False)
    combo.connect('edited', self.on_tv_lang_combo_edited, 0)
    column = Gtk.TreeViewColumn(_('Language'), combo, text=0)
    column.set_property('min-width', 80)
    column.set_property('resizable', True)
    column.set_sort_column_id(0)
    treeview.append_column(column)

    model = self.lang['type'] = Gtk.ListStore(int, str)
    #i = 0
    #for lang_type in self._lang_types:
    #    model.append([i, lang_type])
    #    i += 1
    model.append([0, ''])
    model.append([1, _('lector')])
    model.append([2, _('dubbing')])
    model.append([3, _('subtitles')])
    model.append([4, _("commentary")])
    combo = Gtk.CellRendererCombo()
    combo.set_property('model', model)
    combo.set_property('text-column', 1)
    combo.set_property('editable', True)
    combo.set_property('has-entry', False)
    combo.connect('edited', self.on_tv_lang_combo_edited, 1)
    column = Gtk.TreeViewColumn(_('Type'), combo, text=1)
    column.set_property('min-width', 80)
    column.set_property('resizable', True)
    column.set_sort_column_id(1)
    treeview.append_column(column)

    model = self.lang['acodec'] = Gtk.ListStore(int, str)
    for i in self.db.session.query(db.ACodec.acodec_id, db.ACodec.name).all():
        model.append([i.acodec_id, i.name])
    combo = Gtk.CellRendererCombo()
    combo.set_property('model', model)
    combo.set_property('text-column', 1)
    combo.set_property('editable', True)
    combo.set_property('has-entry', False)
    combo.connect('edited', self.on_tv_lang_combo_edited, 2)
    column = Gtk.TreeViewColumn(_('Codec'), combo, text=2)
    column.set_property('min-width', 80)
    column.set_property('resizable', True)
    column.set_sort_column_id(2)
    treeview.append_column(column)

    model = self.lang['achannel'] = Gtk.ListStore(int, str)
    for i in self.db.session.query(db.AChannel.achannel_id, db.AChannel.name).all():
        model.append([i.achannel_id, i.name])
    combo = Gtk.CellRendererCombo()
    combo.set_property('model', model)
    combo.set_property('text-column', 1)
    combo.set_property('editable', True)
    combo.set_property('has-entry', False)
    combo.connect('edited', self.on_tv_lang_combo_edited, 3)
    column = Gtk.TreeViewColumn(_('Channels'), combo, text=3)
    column.set_property('min-width', 80)
    column.set_property('resizable', True)
    column.set_sort_column_id(3)
    treeview.append_column(column)

    model = self.lang['subformat'] = Gtk.ListStore(int, str)
    for i in self.db.session.query(db.SubFormat.subformat_id, db.SubFormat.name).all():
        model.append([i.subformat_id, i.name])
    combo = Gtk.CellRendererCombo()
    combo.set_property('model', model)
    combo.set_property('text-column', 1)
    combo.set_property('editable', True)
    combo.set_property('has-entry', False)
    combo.connect('edited', self.on_tv_lang_combo_edited, 4)
    column = Gtk.TreeViewColumn(_('Subtitle format'), combo, text=4)
    column.set_property('min-width', 80)
    column.set_property('resizable', True)
    column.set_sort_column_id(4)
    treeview.append_column(column)

    treeview.show_all()


def movie_plugins(self):
    """
    dinamically finds the movie source information plugins
    and fills the plugins drop down list
    """

    tmdbsimple_installed = True
    try:
        import tmdbsimple 
    except:
        tmdbsimple_installed = False
        
    self.plugins = gutils.read_plugins('PluginMovie', \
        self.locations['movie_plugins'])
    self.plugins.sort()
    mcounter = 0
    default_plugin = self.config.get('default_movie_plugin')
    for p in self.plugins:
        plugin_module = os.path.basename(p).replace('.py', '')
        plugin_name = plugin_module.replace('PluginMovie', '')
        if plugin_name == 'TMDB' and not tmdbsimple_installed:
            log.info('tmdbsimple is not installed - disabling TMDB plugin')
            continue
        self.widgets['add']['source'].append_text(plugin_name)
        self.widgets['preferences']['default_plugin'].append_text(plugin_name)
        if plugin_name == default_plugin:
            self.widgets['preferences']['default_plugin'].set_active(mcounter)
            self.widgets['add']['source'].set_active(mcounter)
        mcounter = mcounter + 1


def export_plugins(self):
    """
    dinamically finds the available export plugins
    and fills the export menu entry
    """
    plugins = gutils.read_plugins('PluginExport', \
        self.locations['export_plugins'])
    plugins.sort()
    for p in plugins:
        plugin_module = os.path.basename(p).replace('.py', '')
        plugin_name = plugin_module.replace('PluginExport', '')
        menu_items = Gtk.MenuItem(plugin_name)
        self.widgets['menu']['export'].append(menu_items)
        menu_items.connect('activate', self.on_export_activate, plugin_name)
        menu_items.show()


def import_plugins(self):
    """
    dinamically finds the available import plugins
    and fills the import menu entry
    """

    import plugins.imp

    fields_to_import = ('number', 'title', 'o_title', 'director', 'year', 'runtime', 'country',
        'seen', 'rating', 'genre', 'studio', 'plot', 'cast', 'notes', 'classification',
        'site', 'o_site', 'trailer', 'medium_id', 'media_num', 'vcodec_id', 'color', 'cond',
        'layers', 'region', 'collection_id', 'volume_id', 'image', 'ratio_id', 'screenplay',
        'cameraman', 'barcode', 'tags', 'poster')

    # glade
    glade_file = os.path.join(self.locations['glade'], 'import.ui')
    get = lambda x: builder.get_object(x)
    builder = Gtk.Builder()
    builder.set_translation_domain("griffith")
    builder.add_from_file(glade_file)

    w = self.widgets['import'] = {
        'window': get('dialog_import'),
        'pwindow': get('dialog_progress'),
        'pabort': get('p_abortbutton'),
        'fcw': get('fcw'),
        'plugin': get('combo_plugin'),
        'author': get('l_author'),
        'email': get('l_email'),
        'version': get('l_version'),
        'description': get('l_description'),
        'box_import_1': get('box_import_1'),
        'box_import_2': get('box_import_2'),
        'box_import_3': get('box_import_3'),
        'progress': get('l_progress'),
        'progressbar': get('progressbar'),
        'fields': {},
    }
    w['window'].connect('delete_event', plugins.imp.on_delete_event, self)
    get('cancel_button').connect('clicked', plugins.imp.on_abort_button_clicked, self)
    get('import_button').connect('clicked', plugins.imp.on_import_button_clicked, self)
    w['plugin'].connect('changed', plugins.imp.on_import_plugin_changed, w)
    w['window'].set_transient_for(self.widgets['window'])
    w['pwindow'].set_transient_for(self.widgets['window'])

    for name in plugins.imp.__all__:
        w['plugin'].append_text(name)
    w['plugin'].set_active(0)

    # fields to import
    j = 0
    k = math.ceil(len(self.field_names) / float(3))
    for i in fields_to_import:
        j = j + 1
        w['fields'][i] = Gtk.CheckButton(self.field_names[i])
        w['fields'][i].set_active(True)  # TODO: get from config
        if j <= k:
            w['box_import_1'].add(w['fields'][i])
        elif j <= 2 * k:
            w['box_import_2'].add(w['fields'][i])
        else:
            w['box_import_3'].add(w['fields'][i])
    w['box_import_1'].show_all()
    w['box_import_2'].show_all()
    w['box_import_3'].show_all()


def extension(self, module, enabled):
    if enabled:
        try:
            ext = module(self)
        except (NotImplementedError, DeprecationWarning) as e:
            log.warning('extension skipped: %s', e.message)
            log.debug('extension skipped: %s', module.__file__)
            return [None, None]

        if module.toolbar_icon:
            toolbar = self.widgets['extensions']['toolbar']
            if module.toolbar_icon.endswith(('.png', '.svg')):
                icon_path = os.path.join(os.path.dirname(module.__file__), 'data', module.toolbar_icon)
                if not os.path.isfile(icon_path):
                    icon_path = os.path.join(self.locations['images'], module.toolbar_icon)
                if not os.path.isfile(icon_path):
                    log.error('icon not found: %s', module.toolbar_icon)
                else:
                    icon = Gtk.Image()
                    icon.set_from_file(icon_path)
                    icon.show()
                    toolbutton = Gtk.ToolButton.new(icon, None)
            else:
                toolbutton = Gtk.ToolButton.new_from_stock(module.toolbar_icon)

            toolbar.insert(toolbutton, -1)
            ext.toolbar_icon_widget = toolbutton
            toolbutton.show()
            toolbar.show()
            toolbutton.set_tooltip_text(module.description)
            toolbutton.connect('clicked', ext._on_toolbar_icon_clicked)
    else:
        ext = None
    return ext


def extension_preferences(self, module, enabled):
    # preferences window
    p_vbox = self.widgets['extensions']['preferences_vbox']
    configwidgets = {}

    label = "%s v%s <i>(%s &lt;%s&gt;)</i>" % (module.name, module.version, module.author, module.email)
    expander = Gtk.Expander(label=label)
    expander.get_label_widget().set_tooltip_markup(module.description)
    expander.set_use_markup(True)
    vbox = Gtk.VBox()

    # extension details
    hbox = Gtk.HBox()
    vbox.pack_start(hbox, False, True, 0)
    enabled_cb = Gtk.CheckButton(label=_('Enable this extension'))
    enabled_cb.set_active(enabled)
    configwidgets['enabled'] = enabled_cb
    vbox.pack_start(enabled_cb, False, True, 0)

    for pref_name in module.preferences:
        name = module.preferences[pref_name].get('name', pref_name)
        hint = module.preferences[pref_name].get('hint')
        value = module.preferences[pref_name].get('default')
        value = self.config.get("%s_%s" % (module.name, pref_name), value, section='extensions')
        type_ = module.preferences[pref_name].get('type', str)

        hbox = Gtk.HBox()
        hbox.pack_start(Gtk.Label(name, True, True, 0), False, True, 4)

        if type_ is str:
            w = Gtk.Entry()
            w.insert_text(value, 0)
            # TODO: min, max
        # elif type is int: # TODO
        elif type_ is bool:
            w = Gtk.CheckButton()
            w.set_active(bool(value))
        elif isinstance(type_, (list, tuple, dict)):
            model = Gtk.TreeStore(str, str)
            if isinstance(type_, dict):
                iterable = iter(type_.items())
            else:
                iterable = enumerate(type_)
            pos = None
            count = 0
            for code, codevalue in iterable:
                myiter = model.append(None, None)
                model.set_value(myiter, 0, str(code))
                model.set_value(myiter, 1, str(codevalue))
                if value and value == codevalue:
                    pos = count
                count = count + 1
            # combobox with complex binding to a model needs cell renderer
            w = Gtk.ComboBox(model=model)
            renderer = Gtk.CellRendererText()
            w.pack_start(renderer, True)
            w.add_attribute(renderer, 'text', 1)
            if pos is not None:
                w.set_active(int(pos))
        else:
            log.error('type not recognized %s', type(type_))
            continue

        if hint:
            w.set_tooltip_markup(hint)
        hbox.pack_start(w, True, True, 0)

        vbox.pack_start(hbox, False, True, 0)

        configwidgets[pref_name] = w

    expander.add(vbox)
    p_vbox.pack_start(expander, False, True, 0)
    p_vbox.show_all()

    return configwidgets


def extensions(self):
    import plugins.extensions
    user_extensions_path = os.path.join(self.locations['home'], 'lib', 'extensions')
    if os.path.isdir(user_extensions_path):
        plugins.extensions.scan_for_extensions(user_extensions_path)

    if hasattr(self, 'extensions'):
        for ext in self.extensions:
            ext.clear()
    self.extensions = []  # deletes previous instances

    for ext_name in sorted(plugins.extensions.by_name):
        ext_module = plugins.extensions.by_name[ext_name]
        enabled = self.config.get("%s_enabled" % ext_name, ext_module.enabled, section='extensions')
        if not hasattr(ext_module, 'preferenceswidgets'):
            ext_module.preferenceswidgets = extension_preferences(self, ext_module, enabled)
        ext = extension(self, ext_module, enabled)
        if ext:
            self.extensions.append(ext)


def people_treeview(self, create=True):
    row = None
    self.p_treemodel = Gtk.TreeStore(GObject.TYPE_STRING, GObject.TYPE_STRING, GObject.TYPE_STRING, GObject.TYPE_STRING)
    self.widgets['preferences']['treeview'].set_model(self.p_treemodel)
    self.widgets['preferences']['treeview'].set_headers_visible(True)

    if create is True:
        # name column
        renderer = Gtk.CellRendererText()
        column = Gtk.TreeViewColumn(_('Name'), renderer, text=0)
        column.set_resizable(True)
        column.set_sort_column_id(0)
        self.widgets['preferences']['treeview'].append_column(column)
        # email column
        renderer = Gtk.CellRendererText()
        column = Gtk.TreeViewColumn(_('E-mail'), renderer, text=1)
        column.set_resizable(True)
        column.set_sort_column_id(1)
        self.widgets['preferences']['treeview'].append_column(column)
    # add data to treeview
    self.p_treemodel.clear()
    for i in self.db.session.query(db.Person.name, db.Person.email).order_by(db.Person.name.asc()):
        myiter = self.p_treemodel.insert_before(None, None)
        self.p_treemodel.set_value(myiter, 0, i.name)
        self.p_treemodel.set_value(myiter, 1, i.email)
    self.widgets['preferences']['treeview'].show()


def combos(self):
    i = 0
    for cond in self._conditions:
        self.widgets['preferences']['condition'].insert_text(i, cond)
        self.widgets['add']['condition'].insert_text(i, cond)
        i += 1
    i = 0
    for color in self._colors:
        self.widgets['preferences']['color'].insert_text(i, color)
        self.widgets['add']['color'].insert_text(i, color)
        i += 1
    i = 0
    for region in self._regions:
        self.widgets['preferences']['region'].insert_text(i, region)
        self.widgets['add']['region'].insert_text(i, region)
        i += 1
    i = 0
    for layer in self._layers:
        self.widgets['preferences']['layers'].insert_text(i, layer)
        self.widgets['add']['layers'].insert_text(i, layer)
        i += 1
    i = 0
    pos_to_activate = 0
    selected_criteria = self.config.get('criteria', None, section='mainlist')
    self.search_criteria_sorted = sorted((self.field_names[criteria], criteria) for criteria in self.search_criteria)
    self.search_criteria_sorted.insert(0, (_('Any'), 'any'))
    for (criterianame, criteria) in self.search_criteria_sorted:
        self.widgets['filter']['criteria'].insert_text(i, criterianame)
        if selected_criteria == criterianame:
            pos_to_activate = i
        i += 1
    self.widgets['filter']['criteria'].set_active(pos_to_activate)
    i = 0
    for field in self.sort_criteria:
        if field != 'movie_id':
            self.widgets['preferences']['sortby'].insert_text(i, self.field_names[field])
        else:
            self.widgets['preferences']['sortby'].insert_text(i, _('Last added'))
        i += 1
    self.widgets['preferences']['sortby'].set_wrap_width(3)
    self.widgets['preferences']['sortby'].set_active(0)  # Number


def dictionaries(self):
    """initializes data filled dynamically by users"""
    self.am_tags = {}  # dictionary for tag CheckBoxes
    update_volume_combo_ids(self)
    update_collection_combo_ids(self)
    fill_volumes_combo(self)
    fill_collections_combo(self)
    fill_advfilter_combo(self)
    fill_preferences_tags_combo(self)
    fill_resolutions_combo(self)
    language_combos(self)
    acodec_combos(self)
    achannel_combos(self)
    subformat_combos(self)
    vcodec_combos(self)
    media_combos(self)
    create_tag_vbox(self, widget=self.widgets['add']['tag_vbox'], tab=self.am_tags)
    self.sort_criteria = [  # "[]" because of index()
        'number', 'o_title', 'title', 'director', 'year', 'runtime', 'country',
        'genre', 'studio', 'media_num', 'rating', 'classification', 'collection_id',
        'volume_id', 'cond', 'layers', 'region', 'movie_id']
    self.search_criteria = (
        'o_title', 'title', 'number', 'director', 'plot', 'cast', 'notes', 'year',
        'runtime', 'country', 'genre', 'studio', 'media_num', 'rating', 'screenplay',
        'cameraman', 'barcode')
    self.field_names = {
        'barcode': _('Barcode'),
        'cast': _('Cast'),
        'cameraman': _('Cameraman'),
        'classification': _('Classification'),
        'collection_id': _('Collection'),
        'color': _('Color'),
        'cond': _('Condition'),
        'country': _('Country'),
        'director': _('Director'),
        'genre': _('Genre'),
        'image': _('Image'),
        'layers': _('Layers'),
        'loaned': _('Loaned'),
        'media_num': _('Discs'),
        'medium_id': _('Medium'),
        'notes': _('Notes'),
        'number': _('Number'),
        'o_site': _('Official site'),
        'o_title': _('Original Title'),
        'plot': _('Plot'),
        'poster': _('Poster'),
        'ratio_id': _('Aspect ratio'),
        'rating': _('Rating'),
        'region': _('Region'),
        'runtime': _('Runtime'),
        'screenplay': _('Screenplay'),
        'seen': _('Seen it'),
        'site': _('Site'),
        'studio': _('Studio'),
        'tags': _('Tags'),
        'title': _('Title'),
        'trailer': _('Trailer'),
        'vcodec_id': _('Video codec'),
        'volume_id': _('Volume'),
        'year': _('Year')}
    self._conditions = (_('N/A'), _('Damaged'), _('Poor'), _('Fair'), _('Good'), _('Excellent'))
    self._colors = (_('N/A'), _('Color'), _('Black and White'), _('Mixed'))
    self._lang_types = ('', _('lector'), _('dubbing'), _('subtitles'), _('commentary'))
    self._layers = (_('N/A'), _('Single Side, Single Layer'), _('Single Side, Dual Layer'), _('Dual Side, Single Layer'), _('Dual Side, Dual Layer'))
    self._regions = (
        _('Region 0 (No Region Coding)'),
        _('Region 1 (United States of America, Canada)'),
        _('Region 2 (Europe, Egypt, Arabia, Japan and South Africa)'),
        _('Region 3 (Korea, Thailand, Vietnam, Borneo and Indonesia)'),
        _('Region 4 (Australia and New Zealand, Mexico and South America)'),
        _('Region 5 (India, Africa, Russia and former USSR countries)'),
        _('Region 6 (Popular Republic of China)'),
        _('Region 7 (Reserved for Unspecified Special Use)'),
        _('Region 8 (Airlines/Cruise Ships)'),
        _('Region A/1 (North and South America, Japan, Korea, Taiwan, Hong Kong, Southeast Asia)'),
        _('Region B/2 (Europe, Middle East, Africa, Australia, Oceania)'),
        _('Region C/3 (India, Nepal, China, Russia, Central and South Asia)'),
    )


def web_results(self):
    self.treemodel_results = Gtk.TreeStore(str, str)
    self.widgets['results']['treeview'].set_model(self.treemodel_results)
    self.widgets['results']['treeview'].set_headers_visible(False)
    # column ids
    renderer = Gtk.CellRendererText()
    column1 = Gtk.TreeViewColumn(None, renderer, text=0)
    column1.set_visible(False)
    self.widgets['results']['treeview'].append_column(column1)
    # column titles
    renderer = Gtk.CellRendererText()
    column2 = Gtk.TreeViewColumn(None, renderer, text=1)
    column2.set_resizable(True)
    column2.set_sort_column_id(1)
    self.widgets['results']['treeview'].append_column(column2)


def spellcheck(self):
    global spell_support
    spell_error = False
    if self.posix and spell_support:
        if self.config.get('gtkspell', False, section='spell') == True:
            if self.config.get('notes', True, section='spell') is True and self.config.get('lang', section='spell') != '':
                try:
                    self.notes_spell = GtkSpell.Checker.new()
                    self.notes_spell.set_language(self.config.get('lang', section='spell'))
                    self.notes_spell.attach(self.widgets['add']['notes'])
                except:
                    spell_error = True

            if self.config.get('plot', True, section='spell') is True and self.config.get('lang', section='spell') != '':
                try:
                    self.plot_spell = GtkSpell.Checker.new()
                    self.plot_spell.set_language(self.config.get('lang', section='spell'))
                    self.plot_spell.attach(self.widgets['add']['plot'])
                except:
                    spell_error = True
            if spell_error:
                log.info('Dictionary not available. Spell check will be disabled.')
                if not self.config.get('notified', False, section='spell'):
                    gutils.info(_("Dictionary not available. Spellcheck will be disabled. \n" + \
                        "Please install the aspell-%s package or adjust the spellchecker preferences.") % self.config.get('lang', section='spell'), \
                        self.widgets['preferences']['window'])
                    self.config.set('notified', True, section='spell')
                    self.config.save()
    else:
        log.info('Spellchecker is not available')


def preferences(self):
    self.widgets['preferences']['db_type'].insert_text(0, 'SQLite3 (internal)')
    self.widgets['preferences']['db_type'].insert_text(1, 'PostgreSQL')
    self.widgets['preferences']['db_type'].insert_text(2, 'MySQL')
    self.widgets['preferences']['db_type'].insert_text(3, 'Microsoft SQL')
    self.widgets['preferences']['db_host'].set_text(self.config.get('host', '', section='database'))
    self.widgets['preferences']['db_port'].set_value(int(self.config.get('port', 0, section='database')))
    self.widgets['preferences']['db_user'].set_text(self.config.get('user', '', section='database'))
    self.widgets['preferences']['db_passwd'].set_text(self.config.get('passwd', '', section='database'))
    self.widgets['preferences']['db_name'].set_text(self.config.get('name', '', section='database'))
    db_type = self.config.get('type', 'sqlite', section='database')
    if db_type == 'postgres':
        self.widgets['preferences']['db_type'].set_active(1)
    elif db_type == 'mysql':
        self.widgets['preferences']['db_type'].set_active(2)
    elif db_type == 'mssql':
        self.widgets['preferences']['db_type'].set_active(3)
    else:
        self.widgets['preferences']['db_type'].set_active(0)

    # add completion data
    treemodel = Gtk.TreeStore(str)
    for name in (os.path.basename(x)[:-3] for x in glob("%s/*.db" % self.locations['home'])):
        myiter = treemodel.append(None)
        treemodel.set_value(myiter, 0, name)
    completion = Gtk.EntryCompletion()
    completion.set_minimum_key_length(0)
    self.widgets['preferences']['db_name'].set_completion(completion)
    completion.set_model(treemodel)
    completion.set_text_column(0)


def update_volume_combo_ids(self):
    self.volume_combo_ids = {}
    self.volume_combo_ids[0] = 0
    for i, item in enumerate(self.db.session.query(db.Volume.volume_id).all()):
        self.volume_combo_ids[i + 1] = item.volume_id


def update_collection_combo_ids(self):
    self.collection_combo_ids = {}
    self.collection_combo_ids[0] = 0
    for i, item in enumerate(self.db.session.query(db.Collection.collection_id).order_by(db.Collection.name).all()):
        self.collection_combo_ids[i + 1] = item.collection_id


def fill_volumes_combo(self, default=0):
    _tmp = self.initialized
    self.initialized = False  # don't refresh main treeview
    self.widgets['add']['volume'].get_model().clear()
    for i in self.volume_combo_ids:
        vol_id = self.volume_combo_ids[i]
        if vol_id > 0:
            name = self.db.session.query(db.Volume.name).filter_by(volume_id=vol_id).first().name
        else:
            name = ''
        self.widgets['add']['volume'].insert_text(int(i), name)
    self.widgets['add']['volume'].show_all()
    i = gutils.findKey(default, self.volume_combo_ids)
    if i is not None:
        self.widgets['add']['volume'].set_active(int(i))
    self.widgets['add']['volume'].set_wrap_width(3)
    self.initialized = _tmp


def fill_collections_combo(self, default=0):
    _tmp = self.initialized
    self.initialized = False  # don't refresh main treeview
    self.widgets['add']['collection'].get_model().clear()
    self.widgets['filter']['collection'].get_model().clear()
    for i in self.collection_combo_ids:
        col_id = self.collection_combo_ids[i]
        if col_id > 0:
            name = self.db.session.query(db.Collection.name).filter_by(collection_id=col_id).first().name
        else:
            name = ''
        self.widgets['add']['collection'].insert_text(int(i), name)
        # add some white spaces to prevent scrollbar hides parts of the names
        self.widgets['filter']['collection'].insert_text(int(i), name + '   ')
    self.widgets['add']['collection'].show_all()
    self.widgets['filter']['collection'].show_all()
    self.widgets['filter']['collection'].set_active(0)
    i = gutils.findKey(default, self.collection_combo_ids)
    if i is not None:
        self.widgets['add']['collection'].set_active(int(i))
    self.widgets['add']['collection'].set_wrap_width(2)
    self.initialized = _tmp


def fill_advfilter_combo(self):
    _tmp = self.initialized
    self.initialized = False  # don't refresh main treeview
    self.widgets['filter']['advfilter'].get_model().clear()
    self.widgets['filter']['advfilter'].insert_text(0, '')  # empty one
    for i, item in enumerate(self.db.session.query(db.Filter.name).order_by(db.Filter.name).all()):
        # add some white spaces to prevent scrollbar hides parts of the names
        self.widgets['filter']['advfilter'].insert_text(i + 1, item.name + '   ')
    self.widgets['filter']['advfilter'].show_all()
    self.widgets['filter']['advfilter'].set_active(0)
    self.initialized = _tmp


def fill_preferences_tags_combo(self):
    _tmp = self.initialized
    self.initialized = False  # don't refresh main treeview
    self.widgets['preferences']['tag_name'].get_model().clear()
    self.tags_ids = {}
    for i, tag in enumerate(self.db.session.query(db.Tag.name, db.Tag.tag_id).all()):
        self.tags_ids[i] = tag.tag_id
        self.widgets['preferences']['tag_name'].insert_text(i, tag.name)
    self.widgets['preferences']['tag_name'].show_all()
    self.widgets['preferences']['tag_name'].set_active(0)
    self.initialized = _tmp


def fill_resolutions_combo(self, default=0):
    _tmp = self.initialized
    self.initialized = False  # don't refresh main treeview
    self.widgets['add']['resolution'].get_model().clear()
    #resolutions = [names[0] for names in db._movie.res_aliases.values()]
    resolutions = [names[0] for (res, names) in db._movie.res_aliases.items()]
    resolutions.sort()
    i = 0
    for name in resolutions:
        self.widgets['add']['resolution'].insert_text(i, name)
        i = i + 1
    self.widgets['add']['resolution'].show_all()
    self.initialized = _tmp


def language_combos(self):
    self.widgets['preferences']['lang_name'].get_model().clear()
    self.languages_ids = {}
    self.languages_ids[0] = 0    # empty one
    self.lang['lang'].clear()
    self.widgets['preferences']['lang_name'].insert_text(0, '')
    for i, lang in enumerate(self.db.session.query(db.Lang.lang_id, db.Lang.name).all()):
        self.languages_ids[i + 1] = lang.lang_id
        self.widgets['preferences']['lang_name'].insert_text(i + 1, lang.name)
        # add movie languages treeview
        self.lang['lang'].append([lang.lang_id, lang.name])
    self.widgets['preferences']['lang_name'].show_all()
    self.widgets['preferences']['lang_name'].set_active(0)


def acodec_combos(self):
    self.widgets['preferences']['acodec_name'].get_model().clear()
    self.acodecs_ids = {}
    self.acodecs_ids[0] = 0    # empty one
    self.lang['acodec'].clear()
    self.widgets['preferences']['acodec_name'].insert_text(0, '')
    for i, acodec in enumerate(self.db.session.query(db.ACodec.acodec_id, db.ACodec.name).all()):
        self.acodecs_ids[i + 1] = acodec.acodec_id
        self.widgets['preferences']['acodec_name'].insert_text(i + 1, acodec.name)
        # add movie languages treeview
        self.lang['acodec'].append([acodec.acodec_id, acodec.name])
    self.widgets['preferences']['acodec_name'].show_all()
    self.widgets['preferences']['acodec_name'].set_active(0)


def achannel_combos(self):
    self.widgets['preferences']['achannel_name'].get_model().clear()
    self.achannels_ids = {}
    self.achannels_ids[0] = 0    # empty one
    self.lang['achannel'].clear()
    self.widgets['preferences']['achannel_name'].insert_text(0, '')
    for i, achannel in enumerate(self.db.session.query(db.AChannel.achannel_id, db.AChannel.name).all()):
        self.achannels_ids[i + 1] = achannel.achannel_id
        self.widgets['preferences']['achannel_name'].insert_text(i + 1, achannel.name)
        # add movie languages treeview
        self.lang['achannel'].append([achannel.achannel_id, achannel.name])
    self.widgets['preferences']['achannel_name'].show_all()
    self.widgets['preferences']['achannel_name'].set_active(0)


def subformat_combos(self):
    self.widgets['preferences']['subformat_name'].get_model().clear()
    self.subformats_ids = {}
    self.subformats_ids[0] = 0    # empty one
    self.lang['subformat'].clear()
    self.widgets['preferences']['subformat_name'].insert_text(0, '')
    for i, subformat in enumerate(self.db.session.query(db.SubFormat.subformat_id, db.SubFormat.name).all()):
        self.subformats_ids[i + 1] = subformat.subformat_id
        self.widgets['preferences']['subformat_name'].insert_text(i + 1, subformat.name)
        # add movie languages treeview
        self.lang['subformat'].append([subformat.subformat_id, subformat.name])
    self.widgets['preferences']['subformat_name'].show_all()
    self.widgets['preferences']['subformat_name'].set_active(0)


def media_combos(self):
    # clear data
    self.widgets['preferences']['medium_name'].get_model().clear()
    self.widgets['preferences']['media'].get_model().clear()
    self.widgets['add']['media'].get_model().clear()

    self.media_ids = {}

    self.media_ids[0] = None
    self.widgets['preferences']['medium_name'].insert_text(0, '')
    self.widgets['add']['media'].insert_text(0, _('N/A'))
    self.widgets['preferences']['media'].insert_text(0, _('N/A'))
    for i, medium in enumerate(self.db.session.query(db.Medium.medium_id, db.Medium.name).all()):
        self.media_ids[i + 1] = medium.medium_id
        self.widgets['preferences']['medium_name'].insert_text(i + 1, medium.name)
        self.widgets['add']['media'].insert_text(i + 1, medium.name)
        self.widgets['preferences']['media'].insert_text(i + 1, medium.name)

    self.widgets['preferences']['medium_name'].show_all()
    self.widgets['add']['media'].show_all()
    self.widgets['preferences']['media'].show_all()
    if self.config.has_key('media', section='defaults'):
        pos = gutils.findKey(self.config.get('media', section='defaults'), self.media_ids)
        if pos is not None:
            self.widgets['preferences']['media'].set_active(int(pos))
        else:
            self.widgets['preferences']['media'].set_active(0)
    else:
        self.widgets['preferences']['media'].set_active(0)
    self.widgets['preferences']['medium_name'].set_active(0)


def vcodec_combos(self):
    # clear data
    self.widgets['preferences']['vcodec_name'].get_model().clear()
    self.widgets['preferences']['vcodec'].get_model().clear()
    self.widgets['add']['vcodec'].get_model().clear()

    self.vcodecs_ids = {}

    self.vcodecs_ids[0] = None
    self.widgets['preferences']['vcodec_name'].insert_text(0, '')
    self.widgets['add']['vcodec'].insert_text(0, _('N/A'))
    self.widgets['preferences']['vcodec'].insert_text(0, _('N/A'))
    for i, vcodec in enumerate(self.db.session.query(db.VCodec.vcodec_id, db.VCodec.name).all()):
        self.vcodecs_ids[i + 1] = vcodec.vcodec_id
        self.widgets['preferences']['vcodec_name'].insert_text(i + 1, vcodec.name)
        self.widgets['add']['vcodec'].insert_text(i + 1, vcodec.name)
        self.widgets['preferences']['vcodec'].insert_text(i + 1, vcodec.name)

    self.widgets['preferences']['vcodec_name'].show_all()
    self.widgets['add']['vcodec'].show_all()
    self.widgets['preferences']['vcodec'].show_all()

    pos = gutils.findKey(self.config.get('vcodec', 0, section='defaults'), self.vcodecs_ids)
    if pos is not None:
        self.widgets['preferences']['vcodec'].set_active(int(pos))
    else:
        self.widgets['preferences']['vcodec'].set_active(0)
    self.widgets['preferences']['vcodec_name'].set_active(0)


def create_tag_vbox(self, widget, tab):
    for i in widget.get_children():
        i.destroy()
    for i in self.tags_ids:
        tag_id = self.tags_ids[i]
        tag_name = self.db.session.query(db.Tag.name).filter_by(tag_id=tag_id).first().name
        tab[i] = Gtk.CheckButton(tag_name)
        tab[i].set_active(False)
        widget.pack_start(tab[i], True, True, 0)
    widget.show_all()


def remove_hbox(self, widget, tab):
    number = len(widget.get_children()) - 1  # last box number
    try:
        tab.pop()
        widget.remove(widget.get_children().pop())
    except:
        log.info('List is empty')
    widget.show_all()
