import os
import gtk

import Plugin

class EmoticonContextMenu(gtk.Menu):
    def __init__(self, callback):
        gtk.Menu.__init__(self)
        # append two MenuItem's to this menu and set callbacks
        self.oneCharMenuItem = gtk.MenuItem(_('One char emoticons'));
        self.oneCharMenuItem.set_name('one')
        self.oneCharCallback = self.oneCharMenuItem.connect('activate', callback);
        self.append(self.oneCharMenuItem)
        
        self.anyCharMenuItem = gtk.MenuItem(_('Any emoticon'));
        self.anyCharMenuItem.set_name('any')
        self.anyCharCallback = self.anyCharMenuItem.connect('activate', callback);
        self.append(self.anyCharMenuItem)
        
        self.show_all()
    
    def clean(self):
        self.oneCharMenuItem.disconnect(self.oneCharCallback)
        self.anyCharMenuItem.disconnect(self.anyCharCallback)
        

class EmoticonButton(gtk.ToggleToolButton):
    def __init__(self, conversation, EmoticonPlugin):
        gtk.ToggleToolButton.__init__(self, gtk.STOCK_CANCEL)
        self.set_label(_('No more emoticons, please!'))
        self.conversation = conversation
        self.connect('clicked', self.onClick)
        
        self.plugin = EmoticonPlugin
        self.blocked = []
        self.blockedType = {} 
        
        # create context menu for this button
        self.menu = EmoticonContextMenu(self.onChooseMenu)
        
        # stop emoticons from blocked users in config
        for user in self.conversation.getMembers():
            configValue = self.plugin.config.getPluginValue(self.plugin.name, user, "no")
            if configValue != 'no':
                self.block(user, configValue)
                self.set_active(True)
                
        # connect signal handlers
        self.emoTransferedCallback = self.conversation.switchboard.msn.connect('custom-emoticon-transfered', self.onEmoticonTransfered)
        self.emoReceivedCallback = self.conversation.switchboard.connect('custom-emoticon-received', self.onEmoticonReceived)
        
    # two methods to do the same thing.. not very pythonic but they could be changed/improved in some way
    # so i decided to keep them separated for clarity. They both delete temporary emoticons from blocked
    # users
    def onEmoticonReceived(self, switchboard, shortcut, msnobj):
        user = msnobj.creator
        
        if not self.conversation.customEmoticons.emoticons.has_key(user):
            return False
        
        if user in self.blocked:
            if self.blockedType[user] == 'one':
                if len(shortcut) == 1 and self.conversation.customEmoticons.emoticons[user].has_key(shortcut): 
                    del self.conversation.customEmoticons.emoticons[user][shortcut]
            else:
                self.conversation.customEmoticons.emoticons[user].clear()
        else:
            return False
                
        return True
        
    def onEmoticonTransfered(self, switchboard, to, msnobj, path):
        user = msnobj.creator
        
        if not self.conversation.customEmoticons.emoticons.has_key(user):
            return False
        
        if user in self.blocked:
            if self.blockedType[user] == 'one':
                shortcut = False
                # search for the right key in the emoticons' dictionary, that's the shortcut we're looking for
                # avoid RuntimeError due to a dictionary change during iteration
                try:
                    for key, value in self.conversation.customEmoticons.emoticons[user].iteritems():
                        if value == msnobj.sha1d:
                            shortcut = key
                except RuntimeError:
                    pass
                        
                if shortcut and len(shortcut) == 1 and self.conversation.customEmoticons.emoticons[user].has_key(shortcut):
                    del self.conversation.customEmoticons.emoticons[user][shortcut]
            else:
                self.conversation.customEmoticons.emoticons[user].clear()
        else:
            return False
                
        return True

    def onChooseMenu(self, menuitem):
        # get current switchboard's users, blacklist them in the config and block them
        for user in self.conversation.getMembers():
            self.block(user, menuitem.get_name())
            # distinguish between users blacklisted for one character or any character emoticons
            self.plugin.config.setPluginValue(self.plugin.name, user, menuitem.get_name());

    def block(self, user, type):
        if self.conversation.customEmoticons.emoticons.has_key(user):
            # delete temporary emoticons coming from this user, depending on the choosen type of blacklisting (one or any char)
            if type == 'one':
                # avoid RuntimeError due to a dictionary change during iteration
                try:
                    for key, value in self.conversation.customEmoticons.emoticons[user].iteritems():
                        if len(key) == 1:
                            del self.conversation.customEmoticons.emoticons[user][key]
                except RuntimeError:
                    pass
                
            # this else assures backward compatibility with older configs
            else:
                self.conversation.customEmoticons.emoticons[user].clear()
            
        self.blocked.append(user)
        self.blockedType[user] = type
        
    def unblock(self, user):
        if user in self.blocked:
            self.blocked.remove(user)
            del self.blockedType[user]
        
    def onClick(self, window=None):
        if self.get_active():
            # show popup menu and wait for user's choice
            self.menu.popup(None, None, None, 1, 0)
            return True
        else:
            # get current users out of the blacklist and unblock them
            for user in self.conversation.getMembers():
                self.unblock(user)
                self.plugin.config.setPluginValue(self.plugin.name, user, "no");
            return True
                
        return False
        
    def clean(self):
        for user in self.blocked:
            self.unblock()

        # disconnect handlers
        self.conversation.switchboard.msn.disconnect(self.emoTransferedCallback)
        self.conversation.switchboard.disconnect(self.emoReceivedCallback)

        self.menu.clean()
        self.destroy()


class MainClass(Plugin.Plugin):
    description = _('This plugin adds a button in a conversation window that, if checked, makes you not see the other contact\'s emoticons.')
    authors = {'Lorenzo Rovigatti': 'lorenzo dot rovigatti at gmail dot com'}
    displayName = _('Emoticon Plugin')
    
    def __init__(self, controller, msn):
        Plugin.Plugin.__init__(self, controller, msn)

        self.description = _('This plugin adds a button in a conversation window that, if checked, makes you not to see the other contact\'s emoticons.')
        self.authors = {'Lorenzo Rovigatti': 'lorenzo dot rovigatti at gmail dot com'}
        self.website = ''
        self.displayName = _('Emoticon Plugin')
        self.name = 'EmoticonPlugin'
        
        # load the plugin's config
        self.config = controller.config
        self.config.readPluginConfig(self.name)

    def addButtonToConv(self, conversationManager=None, conversation=None, window=None):
        # initialize a button for emoticon stopping
        button = EmoticonButton(conversation, self)
        if self.controller.theme.getImage('noicons'):
                imagenoicons = gtk.Image()
                imagenoicons.set_from_pixbuf(self.controller.theme.getImage('noicons'))
                imagenoicons.show()
                button.set_icon_widget(imagenoicons)
        button.show()
        # add the button to the toolbar
        conversation.ui.input.toolbar.add(button)
        
    def removeButtonFromConv(self, conversationManager=None, conversation=None, window=None):
        # remove the button from the toolbar
        for button in conversation.ui.input.toolbar.get_children():
            if type(button) == EmoticonButton:
                conversation.ui.input.toolbar.remove(button)
                button.destroy()

    def start(self):
        # tell the controller to call the function addButtonToConv to add the stopEmoticon button
        # every time a new conversation is created, and append it to all the active conversations
        for conversation in self.getOpenConversations():
            self.addButtonToConv(conversation=conversation)
        
        self.convOpen = self.controller.conversationManager.connect_after('new-conversation-ui',
                                                                         self.addButtonToConv)
        
        self.convClose = self.controller.conversationManager.connect('close-conversation-ui',
                                                                         self.removeButtonFromConv)
        
        self.enabled = True

    def stop(self):
        # clean up everything
        self.controller.conversationManager.disconnect(self.convOpen)
        self.controller.conversationManager.disconnect(self.convClose)
        
        for conversation in self.getOpenConversations():
            self.removeButtonFromConv(conversation=conversation)

        self.enabled = False

    def check(self):
        # this plugin really needs nothing to work :)
        return (True, 'Ok')
