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

# Copyright (C) 2004-2007 Johan Svedberg <johan@svedberg.com>

# This file is part of ontv.

# ontv 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.

# ontv 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 General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with ontv; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA

import os
import string
import sys
from gettext import gettext as _

import gtk
import gnome
import gobject
try:
    import vte
except ImportError, ie:
    if str(ie) == "No module named vte":
        ed = ErrorDialog(_("Error while importing vte module"),
                         _("Could not find python-vte."))
        ed.run()
        sys.exit(1)

import GUI
import Utils

GRABBERS = {"Belgium": "tv_grab_be",
            "Brazil": "tv_grab_br",
            "Brazil (NET cable service)": "tv_grab_br_net",
            "Germany": "tv_grab_de_tvtoday",
            "Denmark": "tv_grab_dk",
            "Estonia": "tv_grab_ee",
            "Spain": "tv_grab_es",
            "Spain (laguiatv)": "tv_grab_es_laguiatv",
            "Finland": "tv_grab_fi",
            "France": "tv_grab_fr",
            "Hungary": "tv_grab_huro",
            "Romania": "tv_grab_huro",
            "Iceland": "tv_grab_is",
            "Italy": "tv_grab_it",
            "Japan": "tv_grab_jp",
            "North America": "tv_grab_na_dd",
            "Netherlands": "tv_grab_nl",
            "Netherlands (wolf)": "tv_grab_nl_wolf",
            "Norway": "tv_grab_no",
            "Reunion Island (France)": "tv_grab_re",
            "Sweden": "tv_grab_se_swedb",
            "United Kingdom (bleb.org)": "tv_grab_uk_bleb",
            "United Kingdom (rt)": "tv_grab_uk_rt",
            "South Africa": "tv_grab_za"}

class XMLTVAssistant(gtk.Assistant):

    __gsignals__ = {"apply": "override", "cancel": "override",
                    "close": "override", "prepare": "override"}

    def __init__(self, config, xmltvfile, country=None):
        gtk.Assistant.__init__(self)

        self.config = config
        self.xmltvfile = xmltvfile
        self.country = country

        self.props.title = _("OnTV XMLTV Configuration")

        self.__previous_page = -1

        self.__create_page_1()
        self.__create_page_2()
        self.__create_page_3()
        self.__create_page_4()
        self.__create_page_5()

        self.set_forward_page_func(self.__forward_page_func)

    def __create_page_1(self):
        page = self.__create_page()

        vbox = gtk.VBox(spacing=6)

        label = self.__create_label(_("Welcome! This assistant will help you setup the program OnTV will use to download TV listings for your country."))
        vbox.pack_start(label, expand=True)

        page.add(vbox)
        page.show_all()

        self.__add_page(page, _("OnTV XMLTV Configuration"),
                        gtk.ASSISTANT_PAGE_INTRO)
        self.set_page_complete(page, True)

    def __create_page_2(self):
        page = self.__create_page(0.1)

        vbox = gtk.VBox(spacing=6)

        installed_table = gtk.Table(1, 2, False)
        installed_table.set_row_spacings(6)
        installed_table.set_col_spacings(12)

        self.installed_button = gtk.RadioButton(None,
                                                _("Configure installed grabber"))
        self.installed_button.connect("toggled",
                                      self.__installed_button_toggled,
                                      installed_table)
        vbox.pack_start(self.installed_button, expand=False)

        installed_alignment = gtk.Alignment(0.3, 0.5, 0, 0)

        label = self.__create_label(_("Country:"))
        label.props.xalign = 1
        installed_table.attach(label, 0, 1, 0, 1, xoptions=gtk.FILL)

        self.country_combobox = gtk.combo_box_new_text()
        self.country_combobox.connect("changed",
                                      self.__country_combobox_changed, page)
        # Add grabbers which are in path
        for country in GRABBERS.keys():
            grabber = GRABBERS[country]
            if Utils.is_in_path(grabber):
                self.country_combobox.append_text(country)
        installed_table.attach(self.country_combobox, 1, 2, 0, 1,
                               xoptions=gtk.EXPAND|gtk.FILL)

        installed_alignment.add(installed_table)

        vbox.pack_start(installed_alignment, False, False, 5)

        custom_alignment = gtk.Alignment(0.3, 0.5, 0, 0)

        custom_table = gtk.Table(2, 3, False)
        custom_table.set_row_spacings(6)
        custom_table.set_col_spacings(12)

        self.custom_button = gtk.RadioButton(self.installed_button,
                                             _("Use custom grabber"))
        self.custom_button.connect("toggled",
                                   self.__custom_button_toggled, custom_table)
        vbox.pack_start(self.custom_button, expand=False)

        command_label = gtk.Label(_("Grabber command:"))
        command_label.props.xalign = 1
        custom_table.attach(command_label, 0, 1, 0, 1, xoptions=gtk.FILL)

        self.command_entry = gtk.Entry()
        self.command_entry.connect("changed", self.__custom_fields_changed,
                                   page)
        custom_table.attach(self.command_entry, 1, 3, 0, 1,
                            xoptions=gtk.EXPAND|gtk.FILL)

        output_label = gtk.Label(_("Output file:"))
        output_label.props.xalign = 1
        custom_table.attach(output_label, 0, 1, 1, 2, xoptions=gtk.FILL)

        self.output_entry = gtk.Entry()
        self.output_entry.connect("changed", self.__custom_fields_changed, page)
        custom_table.attach(self.output_entry, 1, 2, 1, 2,
                            xoptions=gtk.EXPAND|gtk.FILL)

        browse_button = gtk.Button(_("Browse..."))
        browse_button.connect("clicked", self.__browse_button_clicked)
        browse_button.props.xalign = 1
        custom_table.attach(browse_button, 2, 3, 1, 2,
                xoptions=gtk.SHRINK|gtk.EXPAND)

        custom_table.set_sensitive(False)

        custom_alignment.add(custom_table)

        vbox.pack_start(custom_alignment, False, False, 5)

        page.add(vbox)
        page.show_all()

        self.__add_page(page, _("Configure grabber"),
                        gtk.ASSISTANT_PAGE_CONTENT)

    def __installed_button_toggled(self, installed_button, installed_table):
        installed_table.set_sensitive(installed_button.get_active())

    def __custom_button_toggled(self, custom_button, custom_table):
        custom_table.set_sensitive(custom_button.get_active())

    def __country_combobox_changed(self, country_combobox, page):
        country_combobox_active = country_combobox.get_active()
        if country_combobox_active >= 0:
            self.set_page_complete(page, True)
            grabber = self.__get_grabber_from_combobox()
            xmltvfile_path = "~/.xmltv/%s.xml" % grabber
            grabber_command = "%s %s %s" % (grabber, "--output", xmltvfile_path)
            self.command_entry.set_text(grabber_command)
            self.output_entry.set_text(xmltvfile_path)
        else:
            self.set_page_complete(page, False)
            self.command_entry.set_text("")
            self.output_entry.set_text("")

    def __get_grabber_from_combobox(self):
        country_combobox_model = self.country_combobox.get_model()
        country_combobox_active = self.country_combobox.get_active()
        selected_country = country_combobox_model[country_combobox_active][0]
        grabber = GRABBERS[selected_country]
        return grabber

    def __custom_fields_changed(self, widget, page):
        complete = False
        if len(self.command_entry.get_text()) > 0 and \
           len(self.output_entry.get_text()) > 0:
            complete = True
        self.set_page_complete(page, complete)

    def __browse_button_clicked(self, button):
        xml_filter = gtk.FileFilter()
        xml_filter.set_name(_("XML files"))
        xml_filter.add_pattern("text/xml")
        filters = [xml_filter]
        fd = GUI.FileChooserDialog(_("Select XMLTV file..."), filters)
        response = fd.run()
        if response == gtk.RESPONSE_OK:
            self.output_entry.set_text(fd.get_filename())
            fd.hide()
        elif response == gtk.RESPONSE_CANCEL:
            fd.hide()

    def __create_page_3(self):
        page = self.__create_page()

        self.terminal_vbox = gtk.VBox(spacing=6)

        label = self.__create_label(_("Configure the grabber by answering the questions in the terminal below."))
        self.terminal_vbox.pack_start(label, expand=True)

        self.terminal_hbox = gtk.HBox()
        self.terminal_vbox.pack_start(self.terminal_hbox, expand=True)

        page.add(self.terminal_vbox)
        page.show_all()

        self.__add_page(page, _("Configure grabber"),
                        gtk.ASSISTANT_PAGE_CONTENT)

    def __create_page_4(self):
        page = self.__create_page()

        vbox = gtk.VBox(spacing=6)

        label = self.__create_label(_("Please wait while the TV listings are being downloaded and sorted. This may take several minutes depending on the speed of your Internet connection."))
        vbox.pack_start(label, expand=True)

        self.progressbar = gtk.ProgressBar()
        vbox.pack_start(self.progressbar, expand=True)
        self.progressbar_changed = False

        self.expander = gtk.Expander(_("Details"))
        vbox.pack_start(self.expander, expand=False)

        page.add(vbox)
        page.show_all()

        self.__add_page(page, _("Downloading and sorting TV listings"),
                        gtk.ASSISTANT_PAGE_PROGRESS)

    def __create_page_5(self):
        page = self.__create_page()

        vbox = gtk.VBox(spacing=6)

        label = self.__create_label(_("Congratulations! OnTV is now ready for use. You can select which channels to monitor in the preferences dialog."))
        vbox.pack_start(label, expand=True)

        page.add(vbox)
        page.show_all()

        self.__add_page(page, _("All done!"),
                        gtk.ASSISTANT_PAGE_SUMMARY)
        self.set_page_complete(page, True)

    def __create_page(self, xalign=0.5, yalign=0.5):
        page = gtk.Alignment(xalign=xalign, yalign=yalign, xscale=0, yscale=0)
        page.set_border_width(6)
        return page

    def __create_label(self, str):
        label = gtk.Label(str)
        label.set_justify(gtk.JUSTIFY_FILL)
        label.set_line_wrap(True)
        label.props.xalign = 0
        return label

    def __add_page(self, page, title, type):
        self.append_page(page)
        self.set_page_header_image(page, GUI.load_icon("ontv"))
        self.set_page_title(page, title)
        self.set_page_type(page, type)

    def __forward_page_func(self, current_page):
        if current_page == 1:
            if self.installed_button.get_active():
                grabber = self.__get_grabber_from_combobox()
                self.xmltvfile_path = os.path.expanduser("~/.xmltv/%s.xml" % \
                                                         grabber)
                self.grabber_command = "%s %s %s" % (grabber, "--output",
                                                     self.xmltvfile_path)
            elif self.custom_button.get_active():
                self.grabber_command = self.command_entry.get_text()
                self.xmltvfile_path = os.path.expanduser(self.output_entry.get_text())
                return 3

        return current_page + 1

    def do_apply(self):
        pass

    def do_cancel(self):
        self.destroy()

    def do_close(self):
        self.destroy()

    def do_prepare(self, page):
        """ Called when a new page is set as current page but before making it
        visible """

        page_number = self.get_current_page()
        page = self.get_nth_page(page_number)

        if self.__previous_page == page_number + 1:
            reaper = vte.reaper_get()
            if reaper.handler_is_connected(self.id):
                reaper.disconnect(self.id)

        if page_number == 1:
            if self.installed_button.get_active() and self.country:
                GUI.set_active_from_string(self.country_combobox, self.country)

        if page_number == 2:
            if self.installed_button.get_active():
                # Configure grabber

                # If Back was pressed from the downloading page
                if self.__previous_page == 3:
                    self.terminal_hbox.reparent(self.terminal_vbox)

                if not hasattr(self, "terminal"):
                    # Setup terminal widget
                    self.__setup_terminal()

                self.terminal.reset(full=True, clear_history=True)
                reaper = vte.reaper_get()
                self.id = reaper.connect("child-exited", self.__terminal_exited,
                                         page)
                grabber = self.grabber_command.split()[0]
                configure_command = [grabber, "--configure", "--quiet"]
                self.terminal.fork_command(grabber, configure_command)
                self.terminal.grab_focus()

        elif page_number == 3 and (self.__previous_page == 2 or
                                   self.__previous_page == 1):
            # Download TV listings

            if self.progressbar_changed:
                # Reset progressbar background
                self.progressbar.modify_fg(gtk.STATE_NORMAL, None)
                self.progressbar.modify_bg(gtk.STATE_NORMAL, None)

            if not hasattr(self, "terminal"):
                # Setup terminal widget
                self.__setup_terminal()

            self.terminal_hbox.reparent(self.expander)
            self.terminal.reset(full=True, clear_history=True)
            id = gobject.timeout_add(250, self.__pulse_progressbar,
                                     self.progressbar)
            reaper = vte.reaper_get()
            self.id = reaper.connect("child-exited",
                                     self.__grabber_command_exited,
                                     (self.progressbar, id, page))

            grabber_cmd_list = self.grabber_command.split()
            grabber_cmd_list = self.__expand_arg_for(grabber_cmd_list,
                                                    "--output")
            self.grabber_command = string.join(grabber_cmd_list)

            pid = self.terminal.fork_command(grabber_cmd_list[0],
                                             grabber_cmd_list)
            self.progressbar.set_text(_("Downloading TV listings..."))

        self.__previous_page = page_number

    def __setup_terminal(self):
        self.terminal = vte.Terminal()
        self.terminal.set_scrollback_lines(100)
        self.terminal.set_emulation("xterm")
        self.terminal.set_font_from_string("monospace 10")
        self.terminal.set_size(80, 25)
        self.terminal_hbox.pack_start(self.terminal)

        scrollbar = gtk.VScrollbar()
        scrollbar.set_adjustment(self.terminal.get_adjustment())
        self.terminal_hbox.pack_start(scrollbar)
        self.terminal_hbox.show_all()

    def __expand_arg_for(self, grabber_command, option):
        if option in grabber_command:
            i = grabber_command.index(option) + 1
            grabber_command[i] = os.path.expanduser(grabber_command[i])
        return grabber_command


    def __terminal_exited(self, reaper, pid, status, page):
        if reaper.handler_is_connected(self.id):
            reaper.disconnect(self.id)
        self.set_page_complete(page, True)

    def __pulse_progressbar(self, progressbar):
        progressbar.pulse()
        return True

    def __grabber_command_exited(self, reaper, pid, status, (progressbar, id,
                                                              page)):
        if reaper.handler_is_connected(self.id):
            reaper.disconnect(self.id)

        if os.WEXITSTATUS(status) != 0:
            gobject.source_remove(id)
            progressbar.modify_fg(gtk.STATE_NORMAL,
                                  gtk.gdk.color_parse("#eeeeec"))
            progressbar.modify_bg(gtk.STATE_NORMAL,
                                  gtk.gdk.color_parse("#ef2929"))

            progressbar.set_fraction(0)
            self.progressbar.set_text(_("Failed to download TV listings!"))
            self.expander.set_expanded(True)
            self.progressbar_changed = True
            self.set_page_type(page, gtk.ASSISTANT_PAGE_CONTENT)
        elif Utils.is_in_path("tv_sort"):
            arguments = self.grabber_command.split()
            sort_command = "tv_sort %s --output %s" % (self.xmltvfile_path,
                                                       self.xmltvfile_path)
            reaper = vte.reaper_get()
            self.id = reaper.connect("child-exited",
                                     self.__sort_command_exited,
                                     (self.progressbar, id, page))
            pid = self.terminal.fork_command(sort_command.split()[0],
                                             sort_command.split())
            progressbar.set_text(_("Sorting TV listings..."))
        else:
            self.__set_page_4_done(progressbar, id, page)

    def __sort_command_exited(self, reaper, pid, status, (progressbar, id,
                                                          page)):
        if reaper.handler_is_connected(self.id):
            reaper.disconnect(self.id)

        self.xmltvfile.props.path = self.xmltvfile_path
        self.xmltvfile.load()

        self.__set_page_4_done(progressbar, id, page)

    def __set_page_4_done(self, progressbar, id, page):
        gobject.source_remove(id)
        progressbar.set_fraction(1.0)
        progressbar.set_text(_("Done!"))
        self.config.grabber_command = self.grabber_command
        self.config.xmltv_file = self.xmltvfile_path
        self.set_page_complete(page, True)

# vim: set sw=4 et sts=4 tw=79 fo+=l:
