#!/usr/bin/python
# -*- coding: utf-8 -*-
### BEGIN LICENSE
# Copyright (C) 2009 Jono Bacon <jono@ubuntu.com>
# Copyright (C) 2010 Michael Budde <mbudde@gmail.com>
# Copyright (c) 2011 John S Gruber <johnsgruber@gmail.com>
#
#This program is free software: you can redistribute it and/or modify it
#under the terms of the GNU General Public License version 3, as published
#by the Free Software Foundation.
#
#This program is distributed in the hope that it will be useful, but
#WITHOUT ANY WARRANTY; without even the implied warranties of
#MERCHANTABILITY, SATISFACTORY QUALITY, 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, see <http://www.gnu.org/licenses/>.
### END LICENSE

import sys
import os
import gtk
import xdg.BaseDirectory
import gettext
import glib
import locale
import pynotify

try:
    import appindicator
    HAVE_APPINDICATOR = True
except ImportError:
    HAVE_APPINDICATOR = False

try:
    import gwibber.lib
    HAVE_GWIBBER = True
except ImportError:
    HAVE_GWIBBER = False

# Set up translations
locale.setlocale(locale.LC_ALL, '')
gettext.install('lernid', unicode=True, names=['ngettext'])

# Check if we are working in the source tree or from the installed
# package and mangle the python path accordingly
if os.path.dirname(sys.argv[0]) != ".":
    if sys.argv[0][0] == "/":
        fullPath = os.path.dirname(sys.argv[0])
    else:
        fullPath = os.getcwd() + "/" + os.path.dirname(sys.argv[0])
else:
    fullPath = os.getcwd()
sys.path.insert(0, os.path.dirname(fullPath))

from lernid.LernidPreferences import Preferences
from lernid.LernidOptions import Options
from lernid import AboutLernidDialog, PreferencesLernidDialog
from lernid.lernidconfig import get_data_path, save_cache_path
from lernid.EventManager import EventManager
from lernid.Statusbar import Statusbar
from lernid.widgets import *

class LernidWindow(gtk.Window):
    __gtype_name__ = "LernidWindow"

    def __init__(self):
        """__init__ - This function is typically not called directly.
        Creation a LernidWindow requires rereading the associated ui
        file and parsing the ui definition externally,
        and then calling LernidWindow.finish_initializing().

        Use the convenience function NewLernidWindow to create
        LernidWindow object.

        """
        gtk.Window.__init__(self)

    def finish_initializing(self, builder):
        """finish_initalizing should be called after parsing the ui definition
        and creating a LernidWindow object with it in order to finish
        initializing the start of the new LernidWindow instance.

        """
        # Get a reference to the builder and set up the signals
        self.builder = builder
        self.builder.connect_signals(self)

        # Set up Application Indicator and notifications
        if  HAVE_APPINDICATOR and Preferences.get('show_appindicator'):
            self.setup_appindicator()
        self.setup_notifications()

        # Set up views

        self._main_window = self.builder.get_object("lernid_window")
        # Restore size and maximize state
        self.main_window_size = Preferences.get('main_window_size')
        if self.main_window_size:
            self._main_window.resize(self.main_window_size['width'], self.main_window_size['height'])
        else:
            size=self._main_window.get_size()
            self.main_window_size = {'width': size[0], 'height' : size[1]}
        if Preferences.get('main_window_maximize'):
            self._main_window.maximize()
        def save_maximize_state(win, event):
            state = bool(event.new_window_state & gtk.gdk.WINDOW_STATE_MAXIMIZED)
            Preferences.set('main_window_maximize', state)
        self._main_window.connect('window-state-event', save_maximize_state)

        self._open_url_dialog = builder.get_object('open_url_dialog')
        self._open_url_dialog.set_transient_for(self)
        self._url_entry = builder.get_object('url_entry')

        # Set up widgets
        self._eventman = EventManager.get_instance()
        self._browser = Browser.Browser()
        self._slide = Slide.Slide(Preferences.get('vertical'))
        self._schedule = Schedule.Schedule()
        self._classroom = Classroom.Classroom()
        if Options.get('web-chat'):
            self._chatroom = WebChatroom.Chatroom()
        else:
            self._chatroom = NativeChatroom.Chatroom()
        if Terminal.VTE_SUPPORT:
            self._terminal = Terminal.Terminal()

        def update_title(schedule, session):
            self.set_title('{0} - {1}'.format('Lernid', session.title))
        def reset_title(schedule):
            self.set_title('Lernid')
        self._schedule.connect('session-changed', update_title)
        self._schedule.connect('session-ended', reset_title)

        # Set tab page numbers
        self.TAB_SESSION = 0
        self.TAB_SCHEDULE = 1
        self.TAB_TERMINAL = 2
        self.ignore_initial_tab_change = True

        def highlight_session_tab(w, url=None):
            if self.ignore_initial_tab_change:
                self.ignore_initial_tab_change = False
                return
            if self._tabs.get_current_page() != self.TAB_SESSION:
                 eye_catcher = u"<span color='red'>●</span><span color='yellow'>●</span><span color='blue'>●</span>"
                 self._session_label.set_label(eye_catcher + ' %s' % _('_Session'))
                 Statusbar.push_message(_('Select the Session tab to see classroom learning material'), duration=20)
        def unhighlight_session_tab(w, p, page_num):
            if page_num == self.TAB_SESSION:
                self._session_label.set_label(_('_Session'))

        def configure_event_mainwindow(self, event):
            self.main_window_size['width'] = event.width
            self.main_window_size['height'] = event.height

        def event_interrupted(self, event):
            logging.error("event interrupted")
            n=pynotify.Notification(_('Event Connection Interrupted'), _('Please reestablish your Internet connection\nand reconnect to the event'), 'lernid')
            try:
                n.show()
            except:
                logging.error("Notification failed to show for Interrupted Event Message")
            Statusbar.push_message(_('Event Connection Interrupted -- '
            'Please reestablish your Internet connection and reconnect to the event'), 'interrupt_message')
            self.emit('event-disconnect', event)

        self._browser.connect('page-changed', highlight_session_tab)
        self._slide.connect('slide-changed', highlight_session_tab)
        self._main_window.connect('configure-event', configure_event_mainwindow)

        # Add widgets to the interface
        self.pack_widgets(Preferences.get('vertical'))

        self._tabs.connect('switch-page', unhighlight_session_tab)

        self._main_window.show_all()

        self.builder.get_object('menu_statusbar').set_active(Preferences.get('statusbar'))

        # Restore pane positions
        prefix = 'v' if Preferences.get('vertical') else 'h'
        self._mainpane = self.builder.get_object(prefix+'mainpaned')
        self._subpane = self.builder.get_object(prefix+'subpaned')
        pos = Preferences.get(prefix+'panes')
        if pos:
            if prefix == 'h':
                if pos['main'] > self.main_window_size['height']-160:
                    pos['main'] = self.main_window_size['height']-160
                if pos['sub'] > self.main_window_size['width']-160:
                    pos['sub'] = self.main_window_size['width']-160
            else:
                if pos['main'] > self.main_window_size['width']-160:
                    pos['main'] = self.main_window_size['width']-160
                if pos['sub'] > self.main_window_size['height']-160:
                    pos['sub'] = self.main_window_size['height']-160

            def setpos(pos):
                self._mainpane.set_position(pos['main'])
                self._subpane.set_position(pos['sub'])
                return False
            # Wait for window resize to complete before we
            # set the pane positions
            glib.timeout_add_seconds(2, setpos,pos)

        menu_tweet = builder.get_object('menu_tweet')
        if HAVE_GWIBBER:
            menu_tweet.show()
            self._schedule.connect('session-changed', lambda s, w: menu_tweet.set_sensitive(True))
            self._schedule.connect('session-ended', lambda s: menu_tweet.set_sensitive(False))
            self._eventman.connect('event-disconnect', lambda em, e: menu_tweet.set_sensitive(False))

        self._eventman.connect('event-interrupted', event_interrupted)
        def event_connected(self, event):
            Statusbar.pop_message('interrupt_message')
            glib.timeout_add_seconds( 12, event_message, self)
            return False

        def event_message(event_man):
            schedule = event_man.get_widget_by_name('schedule')
            qt = schedule.get_question_token()
            message1 = _('You can interact with classes held in the classroom')
#TRANSLATORS: %s will be a token from the locale of the target classroom session rather than the student's locale
            message2 = _(
                     'Add "%s" to the beginning of your query  '
                     'to direct it to the classroom instructor.' % qt)
            notification = pynotify.Notification(message1, message2, 'lernid')
            try:
                notification.show()
            except:
                logging.error("Notification failed for Interaction Message")

        self._eventman.connect('event-connect', event_connected)

        conn_menu_item = builder.get_object('menu_connect')
        disconn_menu_item = builder.get_object('menu_disconnect')
        open_url_menu_item = builder.get_object('menu_open_url')
        def toggle_menu_items(eventman, event, connecting):
            conn_menu_item.set_sensitive(not connecting)
            disconn_menu_item.set_sensitive(connecting)
            open_url_menu_item.set_sensitive(connecting)
            if hasattr(self, 'ind'):
                self.indmenu['menu_connect'].set_sensitive(not connecting)
                self.indmenu['menu_disconnect'].set_sensitive(connecting)
        self._eventman.connect('event-connect', toggle_menu_items, True)
        self._eventman.connect('event-disconnect', toggle_menu_items, False)
        self._eventman.connect('event-connect', 
                    lambda x,y,z: self._tabs.set_current_page(z), self.TAB_SESSION)

        self.connect_dialog(None)

    def pack_widgets(self, vert=True):
        prefix = 'v' if vert else 'h'

        self._tabs = self.builder.get_object(prefix+'tabs')

        # Setup session tab
        paned = vert and gtk.VPaned() or gtk.HPaned()
        self._session_label = gtk.Label()
        self._session_label.set_use_underline(True)
        self._session_label.set_use_markup(True)
        self._session_label.set_label(_('_Session'))
        self._tabs.insert_page(paned, self._session_label, self.TAB_SESSION)

        paned.pack1(self._browser, resize=True)
        paned.pack2(self._slide, resize=False)

        # Setup schedule tab
        schedule_label = gtk.Label()
        schedule_label.set_use_underline(True)
        schedule_label.set_label(_('Sche_dule'))
        self._tabs.insert_page(self._schedule, schedule_label, self.TAB_SCHEDULE)

        # Setup terminal tab
        if Terminal.VTE_SUPPORT:
            label = gtk.Label()
            label.set_use_underline(True)
            label.set_label(_('_Terminal'))
            self._tabs.insert_page(self._terminal, label, self.TAB_TERMINAL)

        self.builder.get_object(prefix+'chatroom_vbox').pack_end(self._chatroom)
        self.builder.get_object(prefix+'chatroom_label').set_mnemonic_widget(self._chatroom.get_input_widget())
        self.builder.get_object(prefix+'classroom_vbox').pack_end(self._classroom)

        # Setup chatroom user count
        mcount_label = self.builder.get_object(prefix+'chatroom_mcount')
        def update_user_count(chat, members):
            n = len(members)
            mcount_label.set_label(ngettext('({0} user)', '({0} users)', n).format(n))
        self._chatroom.connect('members-changed', update_user_count)
        def clear_user_count(em, event):
            mcount_label.set_label('')
        self._eventman.connect('event-disconnect', clear_user_count)

        align = self.builder.get_object(prefix+'alignment')
        main_vbox = self.builder.get_object('main_vbox')
        main_vbox.pack_start(align)
        statusbar = Statusbar.get_instance()
        main_vbox.pack_start(statusbar, expand=False)

        classroom_label = self.builder.get_object(prefix+'classroom_label')
        chatroom_label  = self.builder.get_object(prefix+'chatroom_label')
        def set_room_label(em, event): 
            classroom_name = Options.get('classroom', event.classroom)
            if (not (len(classroom_name) == 0)) and classroom_name[0] not in '#&!+':
                classroom_name = '#' + classroom_name
            chatroom_name = Options.get('chatroom', event.chat)
            if (not (len(chatroom_name) == 0)) and chatroom_name[0] not in '#&!+':
                chatroom_name = '#' + chatroom_name
            classroom_label.set_use_markup(True)
            chatroom_label.set_use_markup(True)
            
            classroom_label.set_markup_with_mnemonic('<b>' + _('Classroom')+'  </b>'+ classroom_name)
#TRANSLATORS: The underscore marks this as a mnemonic accelerator
            chatroom_label.set_markup_with_mnemonic('<b>'+_('_Chatroom')+'  </b>'+ chatroom_name)
        def clear_room_label(em, event):
            classroom_label.set_markup_with_mnemonic('<b>' + _('Classroom')+'</b>')
            chatroom_label.set_markup_with_mnemonic('<b>' + _('_Chatroom')+'</b>')
        self._eventman.connect('event-connect' , set_room_label)
        self._eventman.connect('event-disconnect', clear_room_label)

    def connect_dialog(self, widget):
        self._eventman.connect_dialog(parent=self._main_window)

    def setup_notifications(self):
        """Set up notification settings."""

        capabilities = {'actions':             False,
		'body':                False,
		'body-hyperlinks':     False,
		'body-images':         False,
		'body-markup':         False,
		'icon-multi':          False,
		'icon-static':         False,
		'sound':               False,
		'image/svg+xml':       False,
		'private-synchronous': False,
		'append':              False,
		'private-icon-only':   False}

        if not pynotify.init("lernid"):
            sys.exit (1)

        caps = pynotify.get_server_caps ()
        if caps is None:
            logging.debug("Failed to receive server caps.")
            sys.exit (1)

        for cap in caps:
            capabilities[cap] = True

    def setup_appindicator(self):
        # Create an Application Indicator
        self.ind = appindicator.Indicator ("lernid", "lernid",
                                           appindicator.CATEGORY_COMMUNICATIONS)
        self.ind.set_status (appindicator.STATUS_ACTIVE)
        self.ind.set_attention_icon ("lernid-attention")

        # Create a GtkMenu
        menu = gtk.Menu()

        # Empty dictionary for storing the GtkMenuItems for later reference
        self.indmenu = {}

        # Create GtkMenuItems
        self.indmenu['menu_connect'] = gtk.ImageMenuItem('gtk-connect')
        self.indmenu['menu_connect'].connect('activate', self.connect_dialog)

        self.indmenu['menu_disconnect'] = gtk.ImageMenuItem('gtk-disconnect')
        self.indmenu['menu_disconnect'].connect('activate', self.disconnect_from_event)

        self.indmenu['menu_separator'] = gtk.SeparatorMenuItem()

        self.indmenu['menu_show'] = gtk.CheckMenuItem(_("_Show Lernid"))
        self.indmenu['menu_show'].connect('activate', self.minimize_to_tray)
        self.indmenu['menu_show'].set_active(True)

        self.indmenu['menu_quit'] = gtk.ImageMenuItem('gtk-quit')
        self.indmenu['menu_quit'].connect('activate', self.quit)

        for item in self.indmenu.itervalues():
            item.show()

        # Add the GtkMenuItems to the GtkMenu
        menu.append(self.indmenu['menu_connect'])
        menu.append(self.indmenu['menu_disconnect'])
        menu.append(self.indmenu['menu_separator'])
        menu.append(self.indmenu['menu_show'])
        menu.append(self.indmenu['menu_quit'])

        self.ind.set_menu(menu)

        self.indmenu['menu_disconnect'].set_sensitive(False)

    def disconnect_from_event(self, widget):
        """Disconnect from the currently selected event."""
        self._eventman.disconnect()

    def about(self, widget, data=None):
        """about - display the about box for lernid """

        about = AboutLernidDialog.NewAboutLernidDialog()
        about.set_transient_for(self)
        response = about.run()
        about.destroy()

    def open_url(self, widget):
        self._url_entry.set_text(self._browser.get_location())
        self._url_entry.grab_focus()
        response = self._open_url_dialog.run()
        if response == gtk.RESPONSE_OK:
            self._browser.set_location(self._url_entry.get_text(), False)
        self._open_url_dialog.hide()

    def tweet_session(self, widget):
        session = self._schedule.get_current_session()
        message = _('The session "{0}" has started in #ubuntu-classroom on freenode.'.format(session.title))
        gw = gwibber.lib.GwibberPublic()
        gw.SendMessage(message)

    def preferences(self, widget, data=None):
        """preferences - display the preferences window for lernid """
        prefs = PreferencesLernidDialog.NewPreferencesLernidDialog()
        prefs.set_transient_for(self)
        response = prefs.run()
        if response == gtk.RESPONSE_OK:
            if HAVE_APPINDICATOR:
                # See LP#510169
                #if Preferences.get('show-appindicator', True):
                #    self.ind.set_status(appindicator.STATUS_ACTIVE)
                #else:
                #    self.ind = None
                pass
        prefs.destroy()

    def run(self):
        try:
            self.show()
            gtk.main()
        except:
            self._eventman.disconnect()
            raise

    def quit(self, widget, data=None):
        """quit - signal handler for closing the LernidWindow"""

        prefs = {}
        if not Preferences.get('main_window_maximize'):
            width = self.main_window_size['width']; height = self.main_window_size['height']
            prefs['main_window_size'] = {'width': width, 'height': height}
        prefix = 'v' if Preferences.get('vertical') else 'h'
        if (not Preferences.get(prefix+'panes') or
            (Preferences.get(prefix+'panes')['main'] != self._mainpane.get_position() ) or
            (Preferences.get(prefix+'panes')['sub'] != self._subpane.get_position() ) ):
            prefs[prefix+'panes'] = {
                'main': self._mainpane.get_position(),
                'sub': self._subpane.get_position()
            }
        Preferences.set(prefs)

        self._eventman.disconnect()
        while gtk.events_pending():
            gtk.main_iteration()
        Preferences.flush()
        gtk.main_quit()

    def toggle_fullscreen(self, menuitem):
        if menuitem.get_active():
            self.fullscreen()
        else:
            self.unfullscreen()

    def toggle_statusbar(self, menuitem):
        if menuitem.get_active():
            Statusbar.get_instance().show()
        else:
            Statusbar.get_instance().hide()
        Preferences.set('statusbar', menuitem.get_active())

    def minimize_to_tray(self, menuitem):
        """either hide or show the window"""
        if not menuitem.get_active():
            # Window is visble, now hide it
            self.hide()
        else:
            # Window is hidden, now show it
            self.show()


def NewLernidWindow():
    """NewLernidWindow - returns a fully instantiated
    LernidWindow object. Use this function rather than
    creating a LernidWindow directly.
    """
    # Workaround for https://bugzilla.gnome.org/show_bug.cgi?id=574520
    locale.textdomain("lernid")

    ui_filename = get_data_path('ui', 'LernidWindow.ui')
    builder = gtk.Builder()
    builder.add_from_file(ui_filename)
    window = builder.get_object("lernid_window")
    window.finish_initializing(builder)
    return window

if __name__ == "__main__":
    # Support for command line options
    import logging, optparse
    Options.add_option('-v', '--verbose', action='store_true', dest='verbose', help=_('Show debug messages'))
    Options.add_option('-d', '--debug', action='store_true', dest='more_verbose', help=_('Show debug and classroom management messages'))
    Options.add_option('--classroom', action='store', dest='classroom',
                       help=_('Override classroom channel'))
    Options.add_option('--chatroom',  action='store', dest='chatroom',
                       help=_('Override chatroom channel'))
    Options.add_option('--config', action='store', default=None,
                       help=_('Filename or URL to Lernid config file'))
    Options.add_option('--no-update', action='store_true', default=False,
                       help=_("Don't automatically reload the schedule"))
    Options.add_option('--web-chat', action='store_true', default=False,
                       help=_('Use web chat widget instead of the native one'))
    Options.add_option('--unsafe-override', action='store_true', default=False,
                       help=_('Unsafe testing option'))
    Options.add_option('--avoid-desktopcouch', action='store_true', default=False,
                       help=_('Unused debugging option to avoid desktopcouch'),
                       dest = 'avoid_desktopcouch')
    Options.add_option('--calendar', action='store', default=None,
                       help=_('Override calendar location'))
    Options.parse_args()

    # Set the logging level to show debug messages
    if Options.get('verbose') or Options.get('more_verbose'):
        logging.basicConfig(level=logging.DEBUG)
        logging.debug('logging enabled')

    # Run the application
    window = NewLernidWindow()
    window.run()
