#!/usr/bin/python
# -*- coding: utf-8 -*-
### BEGIN LICENSE
# Copyright (C) 2009 Jono Bacon <jono@ubuntu.com>
# Copyright (C) 2010 Michael Budde <mbudde@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 gtk
import gobject
import logging
import re
import webbrowser

from lernid.widgets.Widget import Widget
from lernid.LernidOptions import Options
from urlparse import urlparse
from lernid.lernidconfig import get_data_path, VERSION
from lernid.LernidPreferences import Preferences
try:
    import webkit
    HAVE_WEBKIT = True
except ImportError:
    HAVE_WEBKIT = False

class Browser(Widget):

    __gtype_name__ = 'LernidBrowser'

    __gsignals__ = {
        'page-loading': (
            gobject.SIGNAL_RUN_LAST, None, (str,)
        ),
        'page-loaded': (
            gobject.SIGNAL_RUN_LAST, None, (str,)
        ),
        'page-changed': (
            gobject.SIGNAL_RUN_LAST, None, (str,)
        ),
    }

    embedded = HAVE_WEBKIT

    def _parse_urls(self, message):
        """Parse a message for URLs and return a tuple with the first
        item begin a URL to load or None and the second item being a
        (possibly empty) list of URLs to add to the combo box.
        """
        load = None
        ignore = []
        def cleanurl(url):
            if url.startswith('['):
                url = url[1:]
            if any([url.endswith(c) for c in '.;:]']):
                url = url[:-1]
            return url
        if re.search("slidefile", message, re.IGNORECASE): return (load, ignore)
        urls = re.findall("(\[?https?://[^\s\)]*)[\s\)\.\]]?", message, re.IGNORECASE)
        for url in urls:
            if (url.startswith('[') and url.endswith(']')) or load:
                ignore.append(cleanurl(url))
            else:
                load = cleanurl(url)
        return (load, ignore)

    if not HAVE_WEBKIT:

        def __init__(self):
            self.location = ""
            Widget.__init__(self, 'browser')

        def do_event_connect(self, eventman, event):
            classroom = eventman.get_widget_by_name('classroom')
            self.event_connect_signal(classroom, 'message-received', self._classroom_msg_received)
            #  Ideally the homepage should be opened inside Lernid itself
            self.set_location(event.homepage, False)
            schedule = eventman.get_widget_by_name('schedule')
            self._on_faculty = schedule.on_faculty # retrieve method

        def do_event_disconnect(self, eventman, event):
            self.event_disconnect_signals()

        def set_location(self, url, in_default_browser = True):
            if urlparse(url).scheme == '':
                url = 'http://' + url
            self.location = url
            logging.debug("url sent to browser " + url)
            webbrowser.open_new_tab(url)

        def get_location(self):
            return(self.location)

        def _classroom_msg_received(self, classroom, chan, sender, text):
            if not Options.get('unsafe-override') and not self._on_faculty(sender):
                return
            load, ignore = self._parse_urls(text)
            if load:
                self.set_location(load)

    else:

        def __init__(self):
            Widget.__init__(self, 'browser')

            builder = self.builder_with_file('BrowserWidget.ui')
            self.add(builder.get_object('browser_vbox'))
            self._browser = webkit.WebView()

            def sse2():
                try:
                    info_file = open("/proc/cpuinfo")
                except:
                    return False
                flag_lines = [l for l in info_file if l.startswith("flags")]
                if len(flag_lines) == 0: return False
                return "sse2" in flag_lines[0]
            
            browser_settings=webkit.WebSettings()
            useragent=browser_settings.get_property('user-agent')
            parts=useragent.split(' ')
            parts[-1]='lernid/'+VERSION
            browser_settings.set_property('user-agent', ' '.join(parts))
            if not sse2():
                browser_settings.set_property('enable-plugins', False)
            else:
                browser_settings.set_property('enable-plugins', True)
            self._browser.set_settings(browser_settings)
            
            scroll = builder.get_object('browser_scroll')
            scroll.add(self._browser)

            self._toolbar = builder.get_object('toolbar_hbox')
            self._refresh_button = builder.get_object('browser_refresh')
            self._stop_button = builder.get_object('browser_stop')

            # set up browser combo box
            self._url_combo = builder.get_object('browser_combo')
            self._url_store = gtk.ListStore(str, str, bool) # Title string, URL, delete
            self._url_combo.set_model(self._url_store)
            title_cell = gtk.CellRendererText()
            self._url_combo.pack_start(title_cell, True)
            self._url_combo.add_attribute(title_cell, 'text', 0)

            self._back_button = builder.get_object('browser_back')

            # Connect the signals
            builder.connect_signals(self)
            self._browser.connect("show", self._set_toolbar_state, True)
            self._browser.connect("hide", self._set_toolbar_state, False)
            self._browser.connect("load-started", self._set_button_state, True)
            self._browser.connect("load-finished", self._set_button_state, False)
            self._browser.connect("load-finished", self._update_url_combo)
            self._browser.set_property('can_focus', True)

            self._paused = False
            self._pause_button = builder.get_object('browser_pause')
            def toggle_paused(button):
                self._paused = not self._paused
            self._pause_button.connect('toggled', toggle_paused)

            self._toolbar.set_sensitive(False)

            self._browser_settings = self._browser.get_settings()
            self._browser_settings.set_property('user-stylesheet-uri', 'file://'+get_data_path()+'/stylesheet')

        def do_event_connect(self, eventman, event):
            classroom = eventman.get_widget_by_name('classroom')
            self.event_connect_signal(classroom, 'message-received', self._classroom_msg_received)
            self._toolbar.set_sensitive(True)
            self._browser.show()
            # FIXME: why does the button not follow sensitive state of the toolbar?
            self._pause_button.set_sensitive(True)
            #  Ideally the homepage should be opened inside Lernid itself
            self.set_location(event.homepage, False)
            schedule = eventman.get_widget_by_name('schedule')
            self._on_faculty = schedule.on_faculty # retrieve method

        def do_event_disconnect(self, eventman, event):
            self._url_combo.handler_block_by_func(self._change_page)
            self._browser.handler_block_by_func(self._update_url_combo)
            self._browser.open('about:blank')
            self._url_store.clear()
            self._browser.handler_unblock_by_func(self._update_url_combo)
            self._url_combo.handler_unblock_by_func(self._change_page)
            self._history = []
            self._current = None
            self._back_button.set_sensitive(False)
            self._pause_button.set_sensitive(False)
            self._toolbar.set_sensitive(False)
            self.event_disconnect_signals()

        def get_location(self):
            return self._browser.get_property('uri')

        def set_location(self, url, in_default_browser = True):
            if urlparse(url).scheme == '':
                    url = 'http://' + url
            logging.debug('opening url: '+url)
            # check if prefernce is set and the link was inside chat
            if Preferences.get('links_in_default_browser') and in_default_browser:
                webbrowser.open_new_tab(url)
                logging.debug('opening url in tab in default browser: '+url)
            else:
                self._browser.open(url)
                self.emit('page-changed', url)

        def _back(self, button):
            self._browser.go_back()

        def _refresh(self, button):
            self._browser.reload()

        def _stop(self, button):
            self._browser.stop_loading()

        def _set_toolbar_state(self, browser, state):
            """Make all buttons on the brower's toolbar insensitive"""
            # We make the toolbar insensitive, and thereby its children as well
            self._toolbar.set_sensitive(state)

        def _set_button_state(self, browser, frame, loading):
            """Change the stop and reload button states"""
            self._refresh_button.set_sensitive(not loading)
            self._stop_button.set_sensitive(loading)
            if loading:
                self.emit('page-loading', browser.get_property('uri'))
            if not self._browser.can_go_back():
                self._back_button.set_sensitive(False)

        def _update_url_combo(self, browser, *args):
            """Update the browser url combo box with the new title."""
            url = browser.get_property('uri')
            if url == None: 
                url = ''
            logging.debug('update url combo: {0}'.format(url))
            if url == 'about:blank':
                return
            if self._browser.can_go_back():
                self._back_button.set_sensitive(True)
            match = False
            storeiter = self._url_store.get_iter_first()
            while storeiter:
                if self._url_store.get_value(storeiter, 1) == url:
                    match = True
                    self._url_store.move_before(storeiter, self._url_store.get_iter_first())
                    self._url_combo.set_active_iter(storeiter)
                    break
                storeiter = self._url_store.iter_next(storeiter)
            if not match:
                title = browser.get_property('title')
                if title is None: title = ''
                urllen = 150 - len(title)
                shorturl = url
                if len(url) > urllen:
                    shorturl = url[:urllen] + '...'
                item = "{0} ({1})".format(title, shorturl)
                self._url_store.prepend([item, url, False])
                self._url_combo.set_active(0)
            self.emit('page-loaded', url)

        def _change_page(self, combo):
            logging.debug('change page: {0}'.format(combo.get_active()))
            if len(self._url_store) == 0:
                return
            url = self._url_store[self._url_combo.get_active()][1]
            delete = self._url_store[self._url_combo.get_active()][2]
            if delete:
                del self._url_store[self._url_combo.get_active()]
            if url != self._browser.get_property('uri'):
                logging.debug('{0} != {1}'.format(url, self._browser.get_property('uri')))
                self.set_location(url)

        def _classroom_msg_received(self, classroom, chan, sender, text):
            if not Options.get('unsafe-override') and not self._on_faculty(sender):
                return
            load, ignore = self._parse_urls(text)
            if load and not self._paused:
                self.set_location(load)
            elif load:
                ignore.insert(0, load)
            for url in ignore:
                self._url_store.prepend([url, url, True])

