# Copyright (C) 2008-2009 LottaNZB Development Team
# 
# 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; version 3.
# 
# 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 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
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.

import gtk
import locale
import webbrowser

import logging
log = logging.getLogger(__name__)

from gobject import idle_add
from os.path import join, isfile
from subprocess import call
from gtk import RESPONSE_OK, BUTTONS_OK_CANCEL

from kiwi.ui.dialogs import info
from kiwi.ui.delegates import Delegate

from lottanzb import __version__, resources
from lottanzb.core import App
from lottanzb.config import ConfigSection
from lottanzb.modes import standalone, remote_frontend
from lottanzb.util import gproperty, gsignal, _
from lottanzb.backend import Download
from lottanzb.gui import add_file, about, prefs, log as log_gui
from lottanzb.gui.modes import selection as mode_selection
from lottanzb.gui.download_list import DownloadList

try: import gnomevfs
except ImportError: gnomevfs = None

class Config(ConfigSection):
    width = gproperty(type=int, default=700)
    height = gproperty(type=int, default=350)
    x_pos = gproperty(type=int, default=100)
    y_pos = gproperty(type=int, default=100)
    maximized = gproperty(type=bool, default=False)

class Window(Delegate):
    gladefile = "main_window"
    
    # If True, the application is entirely shut down if the main window
    # is closed.
    quit_on_close = True
    
    gsignal("add-file-dialog-opened", object)
    
    def __init__(self, config):
        self.config = config
        self.prefs_window = None
        
        gtk.window_set_default_icon_name("lottanzb")
        
        Delegate.__init__(self)
        
        self.enable_rgba_support()
        
        self.download_list = DownloadList()
        self.download_list.connect("selection-changed", self.update_action_sensitivity)
        self.download_list.connect("file-dropped", self.handle_nzb_drop)
        self.download_list.get_treeview().connect("button-press-event", self.show_context_menu)
        self.download_list_container.add(self.download_list)
        
        self.restore_window_geometry()
        
        self.handle_mode_changed()
        
        App().mode_manager.connect_async(
            "notify::active-mode", self.handle_mode_changed)
        App().backend.connect_async(
            "updated", self.update)
    
    def enable_rgba_support(self):
        """
        Try to enable RGBA support
        """
        
        try:
            gtk_screen = self.toplevel.get_screen()
            rgba_colormap = gtk_screen.get_rgba_colormap()
            
            if rgba_colormap:
                gtk.widget_set_default_colormap(rgba_colormap)
        except AttributeError:
            log.debug(_("RGBA support not available."))
        else:
            log.debug(_("RGBA support enabled."))
    
    def restore_window_geometry(self):
        """
        Restore the size and position, as well as the maximization state of the
        window according to the values in the configuration.
        """
        
        if self.config.maximized:
            self.toplevel.maximize()
        else:
            width = self.config.width
            height = self.config.height
            x_pos = self.config.x_pos
            y_pos = self.config.y_pos
            
            self.toplevel.resize(width, height)
            self.toplevel.move(x_pos, y_pos)
    
    def show_add_dialog(self, file_name=None):
        """
        Display a dialog using which a user can add one ore more NZB files
        to the download queue.
        """
        
        dialog = add_file.Dialog(file_name)
        dialog.show(self)
        
        self.emit("add-file-dialog-opened", dialog)
    
    def remove_download(self, download):
        q = _("Are you sure you want to cancel this download?")
        
        if download and info(q, buttons=BUTTONS_OK_CANCEL) == RESPONSE_OK:
            download.dequeue()
    
    def handle_mode_changed(self, *args):
        mode = App().mode_manager.active_mode
        download_dir = True
        
        try:
            assert gnomevfs
            assert mode.hella_config
        except:
            download_dir = False
        
        self.open_download_dir.set_visible(download_dir)
        self.update_action_sensitivity()
    
    def handle_nzb_drop(self, download_list, files):
        if len(files) == 1:
            self.show_add_dialog(files[0])
        elif len(files) >= 1:
            for file in files:
                App().backend.enqueue(file)
    
    def update(self, *args):
        backend = App().backend
        downloads = backend.downloads
        active_download = downloads.get_active_download()
        
        if active_download:
            self.pause.set_active(backend.paused)
            self.speed.set_text(_("%s KB/s") % (backend.speed))
            self.remaining.set_text(_("Remaining: %s MB") % (
                active_download.remaining) + " - %s" % (
                backend.formatETA(backend.eta)))
            
            if backend.downloads.get_queued():
                self.total_remaining.show()
                self.total_remaining_icon.show()
                self.total_remaining.set_text(_("Total remaining: %s MB") % (
                    backend.downloads.get_total_size()) + " - %s" % (
                    backend.formatETA(downloads.get_total_eta())))
            else:
                self.total_remaining.hide()
                self.total_remaining_icon.hide()
        else:
            self.speed.set_text(_("None"))
            self.remaining.set_markup(_("None"))
        
        self.download_list.add_list(downloads)
        self.update_action_sensitivity()
    
    def update_action_sensitivity(self, *args):
        download = self.download_list.get_selected()
        active = bool(download and download.movable)
        
        states = {}
        
        for button in ["move_up", "move_down", "remove"]:
            states[button] = active
        
        if download:
            if download.state == Download.State.DOWNLOADING:
                states["move_up"] = False
            if App().backend.downloads[-1] is download:
                states["move_down"] = False
        
        for action, state in states.iteritems():
            getattr(self, action).set_sensitive(state)
    
    def show_context_menu(self, button, event):
        if event.button == 3:
            self.context_menu.popup(None, None, None, event.button, event.time)
    
    def on_main_window__delete_event(self, widget, event):
        """
        Quits the application if necessary.
        """
        
        if self.quit_on_close:
            App().quit()
    
    def on_main_window__configure_event(self, widget, event):
        """
        Store the window size and position in the configuration if it's
        not maximized.
        """
        
        if not self.config.maximized:
            position = widget.get_position()
            
            self.config.width = event.width
            self.config.height = event.height
            self.config.x_pos = widget.get_position()[0]
            self.config.y_pos = widget.get_position()[1]
    
    def on_main_window__window_state_event(self, widget, event):
        """
        Store the window state in the configuration if it has been maximized.
        """
        
        if event.changed_mask & gtk.gdk.WINDOW_STATE_MAXIMIZED:
            maximized = event.new_window_state & gtk.gdk.WINDOW_STATE_MAXIMIZED
            self.config.maximized = maximized
        
        return False
    
    def on_edit_preferences__activate(self, widget):
        """
        Displays the preferences window. If it has already been opened, bring
        it to the front.
        """
        
        if self.prefs_window:
            self.prefs_window.toplevel.present()
        else:
            def on_prefs_window_destroy(*args):
                self.prefs_window = None
            
            self.prefs_window = prefs.Window()
            self.prefs_window.show(self)
            
            self.prefs_window.toplevel.connect("destroy",
                on_prefs_window_destroy)
    
    def on_select_mode__activate(self, widget):
        dialog = mode_selection.Dialog()
        dialog.show(self)
    
    def on_show_help_content__activate(self, widget):
        try:
            if not resources.is_installed():
                for l in [locale.getlocale()[0][:2], "C"]:
                    help_file = resources.get_help(join(l, "lottanzb.xml"))
                    
                    if isfile(help_file):
                        call(["yelp", help_file])
                        return
            elif hasattr(gtk, "show_uri"):
                # The gtk.show_uri function was newly introduced in PyGTK 2.13,
                # released in August 2008 and is part of the effort of
                # deprecating libgnomeui (gnome module).
                gtk.show_uri(gtk.gdk.screen_get_default(), "ghelp:lottanzb",
                    gtk.get_current_event_time())
            else:
                import gnome
                gnome.help_display("lottanzb")
        except Exception, e:
            webbrowser.open_new_tab("http://www.lottanzb.org/help")
    
    def on_show_about_dialog__activate(self, widget):
        dialog = about.Dialog()
        dialog.show(self)
    
    def on_report_bug__activate(self, widget):
        webbrowser.open_new_tab("http://bugs.launchpad.net/lottanzb/+filebug")
    
    def on_show_message_log__activate(self, widget):
        window = log_gui.Window()
        window.show(self)
    
    def on_remove__activate(self, widget):
        self.remove_download(self.download_list.get_selected())
    
    def on_move_up__activate(self, widget):
        self.download_list.get_selected().move_up()
    
    def on_move_down__activate(self, widget):
        self.download_list.get_selected().move_down()
    
    def on_move_up_to_top__activate(self, widget):
        self.download_list.get_selected().move(0)
    
    def on_pause__activate(self, widget):
        if widget.get_active():
            App().backend.pause()
        else:
            App().backend.resume()
    
    def on_clear__activate(self, widget):
        App().backend.clear_finished()
    
    def on_open_download_dir__activate(self, widget):
        mode = App().mode_manager.active_mode
        
        try:
            gnomevfs.url_show("file://" + mode.hella_config.DEST_DIR)
        except:
            pass
    
    def on_add__activate(self, *args):
        self.show_add_dialog()
    
    def on_quit__activate(self, *args):
        App().quit()
