"""This file contains the MainGUI class."""

import gtk
import gnome
import gnome.ui
from os.path import join

import Const
from LibGladeApplication import LibGladeApplication
from GtkAttributesFacade import GtkAttributesFacade 
from ciphergui.CipherGUIList import cipherGUIList


class MainGUI(LibGladeApplication):

    """This is the main window for the application.
    
    HACK:  To do cut, copy, and paste I'm using the emit method.  I suspect
    that the PyGTK API will eventually update the TextView class to include the
    methods *_clipboard just as the C API does.
    
    The following private variables are used:

    _last_text_view - This is the last TextView that was focused.

    _cipherGUI - This is an instance of a class from the ciphergui package
    associated with the currently selected cipher.

    _cipherGUIInstances - Whenever a new ciphergui instance is created, it is
    cached here so that its key is not lost when the user switches between
    ciphers.

    """

    def __init__(self):
        """Init the GUI."""
        LibGladeApplication.__init__(self, 
            join(Const.GLADEDIR, "gcipher.glade"))
        self._last_text_view = self.decrypted_text_view
        self._cipherGUIInstances = {}
        self._initCipherMenu()

    def _initCipherMenu(self):
        """Initialize the Cipher menu.

        This menu must be dynamic since it must contain the list of ciphers, so
        it can't be created just using Glade.  Place the menu items before the 
        separator and the "Key..." menu item.

        """
        group = None
        l = cipherGUIList[:]
        l.reverse()
        for i in l:
            (className, guiName, labelName, description) = i
            menuItem = gtk.RadioMenuItem(group, labelName)
            if not group:
                group = menuItem
            menuItem.connect_object("activate", self.on_cipher_activate, 
                className)
            menuItem.show()
            self.cipher_menu.prepend(menuItem)
            setattr(self, className, menuItem)
        self.Gie.emit("activate")

    def on_decrypt_activate(self, w):
        """Decrypt encrypted_text_view and update decrypted_text_view."""
        self._transfer(self.encrypted_text_view, self.decrypted_text_view, 
            self._cipherGUI.decrypt)

    def on_encrypt_activate(self, w):
        """Encrypt decrypted_text_view and update encrypted_text_view."""
        self._transfer(self.decrypted_text_view, self.encrypted_text_view, 
            self._cipherGUI.encrypt)

    def on_cut_activate(self, w):
        """Do self._last_text_view.cut_clipboard."""
        self._last_text_view.emit("cut-clipboard")

    def on_copy_activate(self, w):
        """Do self._last_text_view.copy_clipboard."""
        self._last_text_view.emit("copy-clipboard")

    def on_paste_activate(self, w):
        """Do self._last_text_view.paste_clipboard."""
        self._last_text_view.emit("paste-clipboard")

    def on_clear_activate(self, w):
        """Delete the selected text in self._last_text_view, if appropriate."""
        buf = self._last_text_view.buffer
        if len(buf.selection_bounds):
            buf.delete(*buf.selection_bounds)

    def on_copy_up_activate(self, w):
        """Copy the encrypted text to the decrypted text."""
        self._transfer(self.encrypted_text_view, self.decrypted_text_view, 
            lambda s: s)

    def on_copy_down_activate(self, w):
        """Copy the decrypted text to the encrypted text."""
        self._transfer(self.decrypted_text_view, self.encrypted_text_view, 
            lambda s: s)

    def on_cipher_activate(self, cipherGUIClassName):
        """Update the currently selected ciphergui.

        The ciphergui instances are created and cached on an as needed basis.
        Update the key menu item and button so that they are only sensitive if
        the selected ciphergui has a key dialog.
        
        """
        if self._cipherGUIInstances.has_key(cipherGUIClassName):
            self._cipherGUI = self._cipherGUIInstances[cipherGUIClassName]
        else:
            CipherGUIModule = __import__("ciphergui." + cipherGUIClassName, 
                globals(), locals(), cipherGUIClassName)
            CipherGUIClass = getattr(CipherGUIModule, cipherGUIClassName)
            self._cipherGUI = self._cipherGUIInstances[cipherGUIClassName] = (
                CipherGUIClass())
        self.key_button.sensitive = self.key.sensitive = (
            hasattr(self._cipherGUI, "showKeyDialog"))

    def on_key_activate(self, w):
        """Show the key dialog for the currently selected cipher."""
        self._cipherGUI.showKeyDialog()

    def on_contents_activate(self, w):
        """Show the man page."""
        gnome.url_show("man:%s.1" % Const.NAME)

    def on_about_activate(self, w):
        """Show the about dialog."""
        gnome.ui.About(Const.NAME, Const.VERSION, Const.COPYRIGHT, Const.INFO, 
            Const.AUTHORS).show()

    def on_text_view_focus(self, text_view, e):
        """Set self._last_text_view."""
        self._last_text_view = GtkAttributesFacade(text_view)

    def _transfer(self, input_text_view, output_text_view, translator):
        """Basically output_text_view = translator(input_text_view)."""
        in_buf = input_text_view.buffer
        output_text_view.buffer.text = translator(
            in_buf.get_text(in_buf.start_iter, in_buf.end_iter, True))
