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

#   This file is part of emesene
#
#    Emesene 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.
#
#    emesene 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 emesene; if not, write to the Free Software
#    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

import sys

import Login
import TrayIcon
import MainMenu
import UserList
import UserPanel
import FilterEntry
import emesenelib.common

try:
    import gtk
    import gobject
    import pango
except:
    print 'you need pyGTK to run emesene'
    sys.exit(-1)

class MainWindow(gtk.Window):
    '''
    This class represent the main window of emesene,
    it inherit from gtk.Window
    and basically it is a container for other classes.
    '''

    __gsignals__ = {
        'gui-build-done' :
            (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
                (gobject.TYPE_STRING,)),
    }

    def __init__(self, controller):
        '''Constructor'''
        gtk.Window.__init__(self)

        self.controller = controller
        self.config = controller.config
        # accelerators
        accelGroup = gtk.AccelGroup()
        self.add_accel_group(accelGroup)
        self.accelGroup = accelGroup
        accelGroup.connect_group(ord('M'), gtk.gdk.CONTROL_MASK, \
            gtk.ACCEL_LOCKED, self.on_toggle_menu)

        self.set_title('emesene')
        self.set_role('main')

        self.x = self.config.glob['mainWindowX']
        self.y = self.config.glob['mainWindowY']

        self.set_geometry_hints(self, -1, -1)
        self.width = self.config.glob['mainWindowWidth']
        self.height = self.config.glob['mainWindowHeight']
        self.set_default_size(self.width , self.height)

        self.connect('size-allocate', self.on_size_alloc)

        theme = controller.theme
        gtk.window_set_default_icon_list(theme.getImage('icon16'),
                                          theme.getImage('icon32'),
                                          theme.getImage('icon48'),
                                          theme.getImage('icon96'))

        self.vbox = None
        self.login = None
        self.userList = None
        #The next generates a variable with letters and numbers to manage the searches
        self.acceptedCharacters = map(chr, range(97, 123)) + map(chr, range(65, 91)) \
            + ['0','1','2','3','4','5','6','7','8','9']

        self.disconectionMessage = None

        self.currentInterface = 'login'
        self.buildInterface('login')

        self.itemSelectedId = 0

        self.signals = []
        sap = self.signals.append
        sap(self.config.connect('change::showUserPanel',
            self.updateConfig))
        sap(self.config.connect('change::showSearchEntry',
            self.updateConfig))
        sap(self.config.connect('change::showStatusCombo',
            self.updateConfig))
        sap(self.config.connect('change::showMenu',
            self.updateConfig))
        sap(self.config.connect('change::userListAvatarSize',
            self.updateSize))
        sap(self.config.connect('change::smallIcons', self.updateSize))
        # TODO: do we need disconnecting these signals?

    def on_size_alloc(self, widget, allocation):
        self.width = allocation.width
        self.height = allocation.height

    def on_toggle_menu(self, *args):
        self.config.user['showMenu'] = not self.config.user['showMenu']

    def saveToQuit(self):
        '''Saves configuration parametes and everything needed ir order
        to safely quit'''

        if self.userList:
            try:
                self.userList.saveGroupState()
            except:
                pass

        self.controller.config.glob['mainWindowWidth'] = self.width
        self.controller.config.glob['mainWindowHeight'] = self.height

        self.controller.config.glob['mainWindowX'] = self.x
        self.controller.config.glob['mainWindowY'] = self.y

    def quit(self, status = 0):
        '''close the window, and do all the things needed...'''
        self.controller.quit(status)

    def show(self):
        '''Shows itself'''
        if not (self.x < 0 or self.y < 0):
            self.move(self.x, self.y)
        gtk.Window.show(self)

    def hide(self):
        '''Hides itself and any other window'''

        # saves position
        if self.get_property('visible'):
            self.x, self.y = self.get_position()

        if self.userList:
            self.userList.tooltips.hideTooltip()

        # ------------ let the window hide itself the last ---------
        gtk.Window.hide(self)

    def hideOrClose(self, *args):
        '''hide or close depending if we have trayicon'''

        if TrayIcon.disabled:
            self.quit(0)
        else:
            self.hide()

        return True

    def buildInterface(self , guiType = 'login'):
        '''build the interface depending on the guiType parameter, by
        default build the login window.'''

        # save old login values, we may need them in new interface
        if self.login:
            user = self.login.getUser()
            passwd = self.login.getPass()
            status = self.login.getStatus()
        else:
            user = passwd = status = ''

        if self.get_child():
            self.remove(self.vbox)

        if self.userList:
            self.userList.tooltips.hideTooltip()
            self.userList.disconnect(self.itemSelectedId)

        # if i dont add this if we disconnect then the image isnt shown
        if guiType == 'userlist' and self.login:
            try:
                self.login.remove(self.login.loginImage)
            except:
                emesenelib.common.debug('Error when removing loginImage')

        self.currentInterface = guiType

        #widgets

        self.vbox = gtk.VBox(spacing=2)
        self.scroll = gtk.ScrolledWindow()
        self.scroll.set_policy(gtk.POLICY_NEVER , gtk.POLICY_AUTOMATIC)
        self.scroll.set_shadow_type(gtk.SHADOW_IN)
        self.menu = MainMenu.MainMenu(self.controller, \
                                       guiType, self.accelGroup)

        if guiType == 'login':
            self.vbox.pack_start(self.menu, False, False)
            self.login = Login.Login(self.controller, 'login')
            if self.disconectionMessage != None:
                self.vbox.pack_start(self.getStatusBar(), False, False, 0)
                self.disconectionMessage = None
            self.vbox.pack_start(self.login)
        elif guiType == 'userlist':
            self.login = None
            self.vbox.pack_start(self.menu, False, False)
            self.userList = UserList.UserList(self.controller, \
                self.controller.theme, self.controller.config)
            self.itemSelectedId = self.userList.connect('item-selected',
                self.onItemSelected)

            self.userPanel = UserPanel.UserPanel(self.controller)
            self.vbox.pack_start(self.userPanel, False, False)
            self.statusCombo = StatusCombo(self.controller)
            self.statusVBox = gtk.VBox()
            self.statusVBox.pack_start(self.statusCombo, False, False)
            self.statusVBox.set_border_width(2)
            self.statusVBox.show_all()
            self.filterEntry = FilterEntry.FilterEntry(
                self.userList.setFilterText)
            self.scroll.add(self.userList)
            vbox2 = gtk.VBox()
            vbox2.set_border_width(2)
            vbox2.pack_start(self.scroll)

            if self.config.user['statusComboOnTop']:
                self.vbox.pack_start(self.statusVBox, False, False)
                self.vbox.pack_start(self.filterEntry, False, False)
                self.vbox.pack_start(vbox2)
            else:
                self.vbox.pack_start(self.filterEntry, False, False)
                self.vbox.pack_start(vbox2)
                self.vbox.pack_start(self.statusVBox, False, False)

            self.filterEntry.connect('filter-entry-lost-focus', self.lost_focus)
            vbox2.show_all()
            self.controller.connect('preferences-changed',
                self.updateConfig)

        elif guiType == 'loading':
            self.menu.set_sensitive(False)

            self.login = Login.Login(self.controller, 'loading')
            self.login.setFieldValues(user, passwd, status)
            self.vbox.pack_start(self.menu, False, False)
            self.vbox.pack_start(self.login)
            self.menu.show_all()

        elif guiType == 'reconnect':
            self.menu.set_sensitive(False)
            self.login = Login.Login(self.controller, 'reconnect')
            self.vbox.pack_start(self.menu, False, False)
            self.vbox.pack_start(self.login)
            self.menu.show_all()

        self.menu.show_all()
        self.add(self.vbox)
        self.vbox.show()
        self.update(self.controller)

        self.connect('delete-event' , self.hideOrClose)
        self.emit('gui-build-done', guiType)
        self.connect('key-press-event', self.on_key_press)

    def lost_focus(self, widget):
        if self.filterEntry.entry.get_text() =='' and not self.config.user['showSearchEntry']:
            self.filterEntry.hide()

    def on_key_press(self, widget, event):
        if self.currentInterface != 'userlist': 
            if gtk.keysyms.Escape == event.keyval:
                self.hideOrClose()
        else:
            from gtk.gdk import CONTROL_MASK, MOD1_MASK
            if gtk.keysyms.Escape == event.keyval:
                if self.filterEntry.entry.get_text() =='' and not self.config.user['showSearchEntry'] and self.filterEntry.entry.is_focus():
                    self.filterEntry.hide()
                    return True
                elif self.filterEntry.entry.get_text() !='':
                    self.filterEntry.entry.set_text('')
                    return True
                elif self.filterEntry.entry.get_text() =='':
                    self.hideOrClose()
                    return True
            elif  not self.userPanel.tNick.is_focus() and not self.userPanel.tPersonalMessage.is_focus(): 
                if not self.filterEntry.entry.is_focus() : 
                    if gtk.gdk.keyval_name(event.keyval)  in self.acceptedCharacters: 
                        if event.state & CONTROL_MASK or event.state & MOD1_MASK:
                            return False
                        else:
                            if self.filterEntry.entry.get_text() =='' and not self.config.user['showSearchEntry']:
                                self.filterEntry.show()
                            self.filterEntry.entry.set_text(self.filterEntry.entry.get_text() + gtk.gdk.keyval_name(event.keyval))
                            self.filterEntry.entry.grab_focus()
                            self.filterEntry.entry.set_position(self.filterEntry.entry.get_text_length())
                            return True

    def updateConfig(self, *args):
        self.update(self.controller, False)

    def updateSize(self, config, value, oldvalue):
        if value != oldvalue and self.userList:
            self.userList.fill()

    def update(self, controller, refresUserList=True):
        if not controller or self.currentInterface != 'userlist':
            return

        if not self.config.user['showUserPanel']:
            self.userPanel.hide()
        else:
            self.userPanel.show()

        if not self.config.user['showSearchEntry']:
            self.filterEntry.hide()
        else:
            self.filterEntry.show()

        if not self.config.user['showStatusCombo']:
            self.statusCombo.hide()
        else:
            self.statusCombo.show()

        if not self.config.user['showMenu']:
            self.menu.hide();
        else:
            self.menu.show();

        # update UserPanel Nick and PM
        if self.config.user['showUserPanel']:
            self.userPanel.personalMessageRefresh()
            self.userPanel.nickRefresh()

        if refresUserList:
            self.refreshUserList()

    def rebuild(self):
        '''repaint the currentinteface'''

        self.buildInterface(self.currentInterface)

    def refreshUserList(self, force=False):
        '''refresh the userlist :D
        (if we are in userlist mode)'''

        if self.currentInterface == 'userlist':
            groups = self.controller.msn.contactManager.groups
            groups[_('no group')] = \
                self.controller.msn.contactManager.noGroup
            self.userList.fill(groups, force)

    def setAvatar(self, pixbuf):
        if self.currentInterface == 'userlist':
            self.userPanel.setAvatar(pixbuf)

    def onItemSelected(self, userlist, objType, obj, path):
        if objType == 'user':
            self.controller.newConversation(self.controller.msn,
                                            obj.email, None, True)
        elif objType == 'group':
            if self.userList.row_expanded(path):
                self.userList.collapse_row(path)
            else:
                self.userList.expand_row(path, False)

    def getStatusBar(self):
        eventBox = gtk.EventBox()
        box = gtk.HBox(False, 0)
        eventBox.set_size_request(0, 30)
        eventBox.add(box)
        eventBox.modify_bg(gtk.STATE_NORMAL, self.controller.tooltipColor)
        label = gtk.Label(self.disconectionMessage)
        label.set_ellipsize(pango.ELLIPSIZE_END)
        image = gtk.Image()
        image.set_from_stock (gtk.STOCK_DIALOG_INFO, gtk.ICON_SIZE_LARGE_TOOLBAR)
        box.pack_start(image, False, False, 5)
        box.pack_start(label, True, True, 5)
        eventBox.show_all()
        return eventBox


class StatusCombo(gtk.ComboBox):
    '''this class represent the combo where you set the status'''

    def __init__(self, controller):
        '''Constructor'''

        self.statusListStore = gtk.ListStore(gtk.gdk.Pixbuf, \
                      gobject.TYPE_STRING, gobject.TYPE_STRING)

        gtk.ComboBox.__init__(self, self.statusListStore)

        self.controller = controller

        self.statusPixbufCell = gtk.CellRendererPixbuf()
        self.statusTextCell = gtk.CellRendererText()
        self.pack_start(self.statusPixbufCell, False)
        self.pack_start(self.statusTextCell, False)
        self.statusPixbufCell.set_property('xalign', 0.0)
        self.statusPixbufCell.set_property('xpad', 5)
        self.statusTextCell.set_property('xalign', 0.0)
        self.statusTextCell.set_property('xpad', 5)
        self.statusTextCell.set_property('width', 158)
        self.add_attribute(self.statusPixbufCell, 'pixbuf', 0)
        self.add_attribute(self.statusTextCell, 'text', 2)
        self.set_resize_mode(0)
        self.set_wrap_width(1)

        counter = 0
        flag = False
        j = 0
        for i in controller.status_ordered[0]:
            if i not in self.controller.bad_statuses:
                self.statusListStore.append([ \
                    self.controller.theme.statusToPixbuf(i).scale_simple(20,20,gtk.gdk.INTERP_BILINEAR), i, \
                    _(self.controller.status_ordered[2][j])]) # re-gettext-it
            j += 1

        self.set_current_status()
        # flag needed to avoid the double-changing of status when
        # user changes it from another place
        self.changeStatusFlag = True

        self.connect('scroll-event', self.on_scroll_event)
        self.connect('changed', self.on_status_changed, self.changeStatusFlag)
        self.controller.msn.connect('self-status-changed',
            self.selfStatusChanged)
    
    def set_current_status(self, status=None):
        ''' sets current status in the widget '''
        if status is None:
            i = self.controller.contacts.get_status()
            status = self.controller.status_ordered[0][i]
        
        i = 0
        for item in self.statusListStore:
            if item[1] == status:
                break
            i += 1
            
        self.set_active(i)
        
    def selfStatusChanged(self, msnp, status):
        self.changeStatusFlag = False
        self.set_current_status(status)        
        self.changeStatusFlag = True

    def on_status_changed(self , *args):
        if self.changeStatusFlag:
            asd = self.statusListStore.get(self.get_active_iter(), 1)
            self.controller.contacts.set_status(asd[0])

    def on_scroll_event(self,button, event):
        self.popup()
        return True
