#! /usr/bin/python3
# -*- coding:utf-8 -*-
#
# Copyright 2012-2013 "Korora Project" <dev@kororaproject.org>
# Copyright 2013 "Manjaro Linux" <support@manjaro.org>
# Copyright 2014 Antergos
# Copyright 2015 Martin Wimpress <code@flexion.org>
#
# Ubuntu MATE Welcome is free software: you can redistribute it and/or modify
# it under the temms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ubuntu MATE Welcome 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 Ubuntu MATE Welcome. If not, see <http://www.gnu.org/licenses/>.
#

""" Welcome screen for Ubuntu MATE """

import apt
import gettext
import inspect
import json
import logging
import os
import platform
import signal
import subprocess
import sys
import tempfile
import urllib.error
import urllib.parse
import urllib.request
import webbrowser
from gi.repository import GLib, GObject, Gdk, Gtk, Notify, WebKit
from aptdaemon.client import AptClient
from aptdaemon.gtk3widgets import AptErrorDialog, AptConfirmDialog, AptProgressDialog
import aptdaemon.errors
from aptdaemon.enums import *

# i18n
gettext.install("ubuntu-mate-welcome", "/usr/share/locale")

class SimpleApt(object):
    def __init__(self, packages, action):
        self._timeout=100
        self.packages = packages
        self.action = action
        self.source_to_update = None
        self.update_cache = False
        self.loop = GLib.MainLoop()
        self.client = AptClient()
        print('Processing: ' + ', '.join(self.packages))

    def on_error(self, error):
        if isinstance(error, aptdaemon.errors.NotAuthorizedError):
            # Silently ignore auth failures
            return
        elif not isinstance(error, aptdaemon.errors.TransactionFailed):
            # Catch internal errors of the client
            error = aptdaemon.errors.TransactionFailed(ERROR_UNKNOWN,str(error))
        error_dialog = AptErrorDialog(error)
        error_dialog.run()
        error_dialog.hide()

    def on_finished_update(self, transaction, status):
        if status != 'exit-success':
            self.do_notify(status)
            self.loop.quit()
            return False
        GLib.timeout_add(self._timeout,self.do_install)
        return True

    def on_finished_install(self, transaction, status):
        self.loop.quit()
        if status != 'exit-success':
            return False
        else:
            self.do_notify(status)

    def on_finished_remove(self, transaction, status):
        self.loop.quit()
        if status != 'exit-success':
            return False
        else:
            self.do_notify(status)

    def do_notify(self, status):
        print('Status: ' + status)
        if self.action == 'install':
            title = _('Install')
            noun = _('Installation of ')
            action = _('installed.')
        else:
            title = _('Remove')
            noun = _('Removal of ')
            action = _('removed.')

        if status == 'exit-success':
            Notify.init(title + ' ' + _('complete'))
            apt_notify=Notify.Notification.new(title + ' ' + _('complete'), ', '.join(self.packages) + ' ' + _('has been successfully ') +action, 'dialog-information')
        elif status == 'exit-cancelled':
            Notify.init(title + ' ' + _('cancelled'))
            apt_notify=Notify.Notification.new(title + ' ' + _('cancelled'), noun + ', '.join(self.packages) + ' ' + _('was cancelled.'), 'dialog-information')
        else:
            Notify.init(title + ' ' + _('failed'))
            apt_notify=Notify.Notification.new(title + ' ' + _('failed'), noun + ', '.join(self.packages) + ' ' + _('failed.'), 'dialog-error')

        apt_notify.show()

    def do_update(self):
        if self.source_to_update:
            apt_update = self.client.update_cache(self.source_to_update)
        else:
            apt_update = self.client.update_cache()
        apt_update.connect("finished",self.on_finished_update)

        update_dialog = AptProgressDialog(apt_update)
        update_dialog.run(close_on_finished=True, show_error=True,
                reply_handler=lambda: True,
                error_handler=self.on_error,
                )
        return False

    def do_install(self):
        apt_install = self.client.install_packages(self.packages)
        apt_install.connect("finished", self.on_finished_install)

        install_dialog = AptProgressDialog(apt_install)
        install_dialog.run(close_on_finished=True, show_error=True,
                        reply_handler=lambda: True,
                        error_handler=self.on_error,
                        )
        return False

    def do_remove(self):
        apt_remove = self.client.remove_packages(self.packages)
        apt_remove.connect("finished", self.on_finished_remove)

        remove_dialog = AptProgressDialog(apt_remove)
        remove_dialog.run(close_on_finished=True, show_error=True,
                        reply_handler=lambda: True,
                        error_handler=self.on_error,
                        )
        return False

    def install_packages(self):
        if self.update_cache:
            GLib.timeout_add(self._timeout,self.do_update)
        else:
            GLib.timeout_add(self._timeout,self.do_install)
        self.loop.run()

    def remove_packages(self):
        GLib.timeout_add(self._timeout,self.do_remove)
        self.loop.run()

class SimpleDeb(object):
    def __init__(self, debfile):
        self._timeout=100
        self.debfile = debfile
        self.loop = GLib.MainLoop()
        self.client = AptClient()
        print('Processing: ' + self.debfile)

    def on_error(self, error):
        if isinstance(error, aptdaemon.errors.NotAuthorizedError):
            # Silently ignore auth failures
            return
        elif not isinstance(error, aptdaemon.errors.TransactionFailed):
            # Catch internal errors of the client
            error = aptdaemon.errors.TransactionFailed(ERROR_UNKNOWN,str(error))
        error_dialog = AptErrorDialog(error)
        error_dialog.run()
        error_dialog.hide()

    def on_finished_install(self, transaction, status):
        self.loop.quit()
        if status != 'exit-success':
            return False
        else:
            self.do_notify(status)

    def do_notify(self, status):
        title = _('Install')
        noun = _('Installation of ')
        action = _('installed.')

        if status == 'exit-success':
            Notify.init(title + ' ' + _('complete'))
            deb_notify=Notify.Notification.new(title + ' ' + _('complete'), os.path.basename(self.debfile) + ' ' + _('has been successfully ') +action, 'dialog-information')
        elif status == 'exit-cancelled':
            Notify.init(title + ' ' + _('cancelled'))
            deb_notify=Notify.Notification.new(title + ' ' + _('cancelled'), noun + os.path.basename(self.debfile) + ' ' + _('was cancelled.'), 'dialog-information')
        else:
            Notify.init(title + ' ' + _('failed'))
            deb_notify=Notify.Notification.new(title + ' ' + _('failed'), noun + os.path.basename(self.debfile) + ' ' + _('failed.'), 'dialog-error')

        deb_notify.show()

    def do_install(self):
        deb_install = self.client.install_file(self.debfile)
        deb_install.connect("finished", self.on_finished_install)

        install_dialog = AptProgressDialog(deb_install)
        install_dialog.run(close_on_finished=True, show_error=True,
                        reply_handler=lambda: True,
                        error_handler=self.on_error,
                        )
        return False

    def install_file(self):
        GLib.timeout_add(self._timeout,self.do_install)
        self.loop.run()

def process_packages(packages, action):
    if len(packages) and len(action):
        packages = packages.split(',')
    else:
        print('No package(s) supplied')
        return

    codename = platform.dist()[2]
    transaction = SimpleApt(packages, action)

    # Perform any pre-install configuration. Basically enabling repositories or
    # adding PPAs.
    if 'appgrid' in packages:
        subprocess.call(['pkexec', '/usr/lib/ubuntu-mate/ubuntu-mate-welcome-repository-installer', 'appgrid', action])
        transaction.update_cache = True
        transaction.source_to_update = 'appgrid-ubuntu-stable-'+codename+'.list'
    elif 'dropbox' in packages:
        subprocess.call(['pkexec', '/usr/lib/ubuntu-mate/ubuntu-mate-welcome-repository-installer', 'dropbox', action])
        transaction.update_cache = True
        transaction.source_to_update = 'dropbox.list'
    elif 'eviacam' in packages:
        subprocess.call(['pkexec', '/usr/lib/ubuntu-mate/ubuntu-mate-welcome-repository-installer', 'eviacam', action])
        transaction.update_cache = True
        transaction.source_to_update = 'cesar-crea-si-ubuntu-eviacam-'+codename+'.list'
    elif 'adobe-flashplugin' in packages:
        subprocess.call(['pkexec', '/usr/lib/ubuntu-mate/ubuntu-mate-welcome-repository-installer', 'adobe-flashplugin', action])
        transaction.update_cache = True
    elif 'google-earth' in packages:
        subprocess.call(['pkexec', '/usr/lib/ubuntu-mate/ubuntu-mate-welcome-repository-installer', 'google-earth', action])
        transaction.update_cache = True
        transaction.source_to_update = 'google-earth.list'
    elif 'google-chrome-stable' in packages:
        subprocess.call(['pkexec', '/usr/lib/ubuntu-mate/ubuntu-mate-welcome-repository-installer', 'google-chrome', action])
        transaction.update_cache = True
        transaction.source_to_update = 'google-chrome.list'
    elif 'google-musicmanager-beta' in packages:
        subprocess.call(['pkexec', '/usr/lib/ubuntu-mate/ubuntu-mate-welcome-repository-installer', 'google-musicmanager', action])
        transaction.update_cache = True
        transaction.source_to_update = 'google-musicmanager.list'
    elif 'google-talkplugin' in packages:
        subprocess.call(['pkexec', '/usr/lib/ubuntu-mate/ubuntu-mate-welcome-repository-installer', 'google-talkplugin', action])
        transaction.update_cache = True
        transaction.source_to_update = 'google-talkplugin.list'
    elif 'handbrake' in packages:
        # Handbrake is not in the PPA yet. Also in the PPA it is known
        # as 'hanbrake-gtk' while in the archive it is known as
        # 'handbrake'
        subprocess.call(['pkexec', '/usr/lib/ubuntu-mate/ubuntu-mate-welcome-repository-installer', 'libdvdcss2', action])
        transaction.update_cache = True
        transaction.source_to_update = 'libdvdcss2.list'
    elif 'insync' in packages:
        subprocess.call(['pkexec', '/usr/lib/ubuntu-mate/ubuntu-mate-welcome-repository-installer', 'insync', action])
        transaction.update_cache = True
        transaction.source_to_update = 'insync.list'
    elif 'libdvdcss2' in packages:
        subprocess.call(['pkexec', '/usr/lib/ubuntu-mate/ubuntu-mate-welcome-repository-installer', 'libdvdcss2', action])
        transaction.update_cache = True
        transaction.source_to_update = 'libdvdcss2.list'
    elif 'makemkv-bin' in packages:
        subprocess.call(['pkexec', '/usr/lib/ubuntu-mate/ubuntu-mate-welcome-repository-installer', 'makemkv', action])
        transaction.update_cache = True
        transaction.source_to_update = 'heyarje-ubuntu-makemkv-beta-'+codename+'.list'
    elif 'minecraft-installer' in packages:
        subprocess.call(['pkexec', '/usr/lib/ubuntu-mate/ubuntu-mate-welcome-repository-installer', 'minecraft', action])
        transaction.update_cache = True
        transaction.source_to_update = 'minecraft-installer-peeps-ubuntu-minecraft-installer-'+codename+'.list'
    elif 'mumble' in packages:
        subprocess.call(['pkexec', '/usr/lib/ubuntu-mate/ubuntu-mate-welcome-repository-installer', 'mumble', action])
        if codename == 'precise' or codename == 'trusty':
            transaction.update_cache = True
            transaction.source_to_update = 'mumble-ubuntu-release-'+codename+'.list'
    elif 'pithos' in packages:
        subprocess.call(['pkexec', '/usr/lib/ubuntu-mate/ubuntu-mate-welcome-repository-installer', 'pithos', action])
        if codename == 'precise' or codename == 'trusty':
            transaction.update_cache = True
            transaction.source_to_update = 'pithos-ubuntu-ppa-'+codename+'.list'
    elif 'simplescreenrecorder' in packages:
        subprocess.call(['pkexec', '/usr/lib/ubuntu-mate/ubuntu-mate-welcome-repository-installer', 'simplescreenrecorder', action])
        transaction.update_cache = True
        transaction.source_to_update = 'maarten-baert-ubuntu-simplescreenrecorder-'+codename+'.list'
    elif 'skype' in packages:
        subprocess.call(['pkexec', '/usr/lib/ubuntu-mate/ubuntu-mate-welcome-repository-installer', 'skype', action])
        transaction.update_cache = True
    elif 'spideroakone' in packages:
        subprocess.call(['pkexec', '/usr/lib/ubuntu-mate/ubuntu-mate-welcome-repository-installer', 'spideroakone', action])
        transaction.update_cache = True
        transaction.source_to_update = 'spideroakone.list'
    elif 'spotify-client' in packages:
        subprocess.call(['pkexec', '/usr/lib/ubuntu-mate/ubuntu-mate-welcome-repository-installer', 'spotify', action])
        transaction.update_cache = True
        transaction.source_to_update = 'spotify.list'
    elif 'steam-launcher' in packages:
        subprocess.call(['pkexec', '/usr/lib/ubuntu-mate/ubuntu-mate-welcome-repository-installer', 'steam', action])
        transaction.update_cache = True
        transaction.source_to_update = 'steam.list'
    elif 'synapse' in packages:
        subprocess.call(['pkexec', '/usr/lib/ubuntu-mate/ubuntu-mate-welcome-repository-installer', 'synapse', action])
        transaction.update_cache = True
        transaction.source_to_update = 'synapse-core-ubuntu-testing-'+codename+'.list'
    elif 'syncthing' in packages:
        subprocess.call(['pkexec', '/usr/lib/ubuntu-mate/ubuntu-mate-welcome-repository-installer', 'syncthing', action])
        transaction.update_cache = True
        transaction.source_to_update = 'syncthing.list'
    elif 'telegram' in packages:
        subprocess.call(['pkexec', '/usr/lib/ubuntu-mate/ubuntu-mate-welcome-repository-installer', 'telegram', action])
        transaction.update_cache = True
        transaction.source_to_update = 'atareao-ubuntu-telegram-'+codename+'.list'
    elif 'ubuntu-sdk' in packages:
        subprocess.call(['pkexec', '/usr/lib/ubuntu-mate/ubuntu-mate-welcome-repository-installer', 'ubuntu-sdk', action])
        transaction.update_cache = True
        transaction.source_to_update = 'ubuntu-sdk-team-ubuntu-ppa-'+codename+'.list'
    elif 'uget' in packages:
        subprocess.call(['pkexec', '/usr/lib/ubuntu-mate/ubuntu-mate-welcome-repository-installer', 'uget', action])
        transaction.update_cache = True
        transaction.source_to_update = 'plushuang-tw-ubuntu-uget-stable-'+codename+'.list'
    elif 'veracrypt' in packages:
        subprocess.call(['pkexec', '/usr/lib/ubuntu-mate/ubuntu-mate-welcome-repository-installer', 'veracrypt', action])
        transaction.update_cache = True
        transaction.source_to_update = 'unit193-ubuntu-encryption-'+codename+'.list'
    elif 'virtualbox-5.0' in packages:
        subprocess.call(['pkexec', '/usr/lib/ubuntu-mate/ubuntu-mate-welcome-repository-installer', 'virtualbox', action])
        transaction.update_cache = True
        transaction.source_to_update = 'virtualbox.list'
    elif 'x2goclient' in packages:
        subprocess.call(['pkexec', '/usr/lib/ubuntu-mate/ubuntu-mate-welcome-repository-installer', 'x2go', action])
        transaction.update_cache = True
        transaction.source_to_update = 'x2go-ubuntu-stable-'+codename+'.list'
    elif 'x2goserver' in packages:
        subprocess.call(['pkexec', '/usr/lib/ubuntu-mate/ubuntu-mate-welcome-repository-installer', 'x2go', action])
        transaction.update_cache = True
        transaction.source_to_update = 'x2go-ubuntu-stable-'+codename+'.list'

    if transaction.action == 'install':
        transaction.install_packages()
    elif transaction.action == 'remove':
        transaction.remove_packages()
    else:
        print('The requested action is unknown')

def download_file(url):
    #http://stackoverflow.com/questions/22676/how-do-i-download-a-file-over-http-using-python/22776#22776
    u = urllib.request.urlopen(url)

    scheme, netloc, path, query, fragment = urllib.parse.urlsplit(url)
    filename = os.path.join('/','tmp',os.path.basename(path))

    with open(filename, 'wb') as f:
        meta = u.info()
        meta_func = meta.getheaders if hasattr(meta, 'getheaders') else meta.get_all
        meta_length = meta_func("Content-Length")
        file_size = None
        if meta_length:
            file_size = int(meta_length[0])
        print("Downloading: {0} Bytes: {1}".format(url, file_size))

        file_size_dl = 0
        block_sz = 8192
        while True:
            buffer = u.read(block_sz)
            if not buffer:
                break

            file_size_dl += len(buffer)
            f.write(buffer)

            status = "{0:16}".format(file_size_dl)
            if file_size:
                status += "   [{0:6.2f}%]".format(file_size_dl * 100 / file_size)
                fraction = file_size_dl / file_size
            status += chr(13)
            print(status, end="")
        print()

    return filename

# Look a good example - https://gist.github.com/hrasdt/8206777
# Somewhat useful - http://python-gtk-3-tutorial.readthedocs.org/en/latest/progressbar.html

def process_deburl(deburl):
    debfile = download_file(deburl)
    transaction = SimpleDeb(debfile)
    transaction.install_file()

class WelcomeConfig(object):
    """ Manages Welcome configuration """
    def __init__(self):
        # store our base architecture
        self.os_version = platform.dist()[1]
        self.os_codename = platform.dist()[2]
        self.os_title = 'Ubuntu MATE ' + self.os_version
        self._arch = os.uname()[4]

        # store we are a live CD session
        self._live = os.path.exists('/usr/share/glib-2.0/schemas/zubuntu-mate-live.gschema.override')

        # store full path to our binary
        self._welcome_bin_path = os.path.abspath(inspect.getfile(inspect.currentframe()))

        # directory for the configuration
        self._config_dir = os.path.expanduser('~/.config/ubuntu-mate/welcome/')

        # autostart directory
        self._autostart_dir = os.path.expanduser('~/.config/autostart/')

        # full path to the autostart symlink
        self._autostart_path = os.path.expanduser(os.path.join(self._autostart_dir, 'ubuntu-mate-welcome.desktop'))

        # ensure our config and autostart directories exists
        for _dir in [self._config_dir, self._autostart_dir]:
            if not os.path.exists(_dir):
                try:
                    os.makedirs(_dir)
                except OSError as err:
                    print(err)
                    pass

        # does autostart symlink exist
        self._autostart = os.path.exists(self._autostart_path)

    @property
    def arch(self):
        return self._arch

    @property
    def autostart(self):
        return self._autostart

    @autostart.setter
    def autostart(self, state):
        if state and not os.path.exists(self._autostart_path):
            # create the autostart symlink
            try:
                os.symlink('/usr/share/applications/ubuntu-mate-welcome.desktop', self._autostart_path)
            except OSError as err:
                print(err)
                pass
        elif not state and os.path.exists(self._autostart_path):
            # remove the autostart symlink
            try:
                os.unlink(self._autostart_path)
            except OSError as err:
                print(err)
                pass

        # determine autostart state based on absence of the disable file
        self._autostart = os.path.exists(self._autostart_path)

    @property
    def live(self):
        return self._live

class AppView(WebKit.WebView):
    def __init__(self):
        WebKit.WebView.__init__(self)

        self._config = WelcomeConfig()
        self._apt_cache = apt.Cache()
        self.connect('load-finished', self._load_finished_cb)
        self.connect('navigation-policy-decision-requested', self._nav_request_policy_decision_cb)
        self.l_uri = None

    def _push_config(self):
        self.execute_script("$('#os_title').html('%s')" % self._config.os_title)
        self.execute_script("$('#autostart').toggleClass('fa-check-square', %s).toggleClass('fa-square', %s)" % (json.dumps(self._config.autostart), json.dumps(not self._config.autostart)))

        # If this is a Live session (booted from ISO) show the
        # 'Install OS' button, if runningon an installed system show the
        # 'Install Software' button.
        if self._config.live:
            self.execute_script("$('#install').show();")
            self.execute_script("$('#software').hide();")
            self.execute_script("$('.live-session').hide();")
        else:
            self.execute_script("$('#install').hide();")
            self.execute_script("$('#software').show();")
            self.execute_script("$('.live-session').show();")

        # Hide applications that are not supported on some architectures.
        if self._config.arch == 'i686':
            self.execute_script("$('.i686-only').show();")
            self.execute_script("$('.x86_64-only').hide();")
            self.execute_script("$('.pc-only').show();")
        elif self._config.arch == 'x86_64':
            self.execute_script("$('.i686-only').hide();")
            self.execute_script("$('.x86_64-only').show();")
            self.execute_script("$('.pc-only').show();")
        else:
            self.execute_script("$('.i686-only').hide();")
            self.execute_script("$('.x86_64-only').hide();")
            self.execute_script("$('.pc-only').hide();")

        if self._apt_cache['hexchat'].is_installed:
            self.execute_script("$('.hexchat').show();")
            self.execute_script("$('.webchat').hide();")
        else:
            self.execute_script("$('.hexchat').hide();")
            self.execute_script("$('.webchat').show();")

        # Change button states for Software.html
        # TODO - Read this from YAML or JSON
        for package in ['adobe-flashplugin', 'appgrid', 'asunder',
        'audacity', 'bleachbit', 'blender', 'calibre',
        'chromium-browser', 'darktable', 'dropbox', 'eviacam',
        'filezilla', 'firefox', 'geany', 'gimp', 'glabels',
        'gnome-disk-utility', 'gnucash', 'gramps',
        'google-chrome-stable', 'google-earth-stable',
        'google-musicmanager-beta', 'google-talkplugin', 'handbrake',
        'hardinfo', 'icedtea-7-plugin', 'inkscape', 'insync',
        'libavcodec-extra', 'libdvdcss2', 'makemkv-bin', 'meld',
        'minecraft-installer', 'mumble', 'ocenaudio', 'pavucontrol',
        'pithos', 'pitivi', 'pysolfc', 'rapid-photo-downloader',
        'remmina', 'scribus', 'simplescreenrecorder', 'skype',
        'software-center', 'spideroakone', 'spotify-client',
        'steam-launcher', 'supertuxkart', 'sweethome3d', 'synapse',
        'synaptic', 'syncthing', 'telegram', 'terminator',
        'ubuntu-sdk', 'uget', 'veracrypt', 'virtualbox',
        'workrave', 'x2goclient', 'x2goserver', 'zim']:
            if package == 'virtualbox-5.0':
                css_class = 'virtualbox'
            elif package == 'libavcodec-extra':
                css_class = 'codecs'
            else:
                css_class = package

            try:
                if self._apt_cache[package].is_installed:
                    self.execute_script("$('."+css_class+"-install').hide();")
                    self.execute_script("$('."+css_class+"-reinstall').show();")
                    self.execute_script("$('."+css_class+"-remove').show();")
                else:
                    self.execute_script("$('."+css_class+"-install').show();")
                    self.execute_script("$('."+css_class+"-reinstall').hide();")
                    self.execute_script("$('."+css_class+"-remove').hide();")
            except:
                self.execute_script("$('."+css_class+"-install').show();")
                self.execute_script("$('."+css_class+"-reinstall').hide();")
                self.execute_script("$('."+css_class+"-remove').hide();")

    def _load_finished_cb(self, view, frame):
        self._push_config()

    def _nav_request_policy_decision_cb(self, view, frame, net_req, nav_act, pol_dec):
        uri = net_req.get_uri()

        try:
            if uri.index('#') > 0:
                uri = uri[:uri.index('#')]
        except ValueError:
            pass

        if uri == self.l_uri:
            pol_dec.use()
            return True

        if uri.startswith('cmd://'):
            self._do_command(uri)
            return True

        self.l_uri = uri

        page = urllib.request.urlopen(uri)
        frame.load_string(page.read().decode(), "text/html", "iso-8859-15", page.geturl())
        pol_dec.ignore()
        return True

    def _do_command(self, uri):
        if uri.startswith('cmd://'):
            uri = uri[6:]

        if uri.startswith('apt-install?'):
            process_packages(uri[12:], 'install')
            self._apt_cache.close()
            self._apt_cache = apt.Cache()
            self._push_config()
        elif uri.startswith('apt-remove?'):
            process_packages(uri[11:], 'remove')
            self._apt_cache.close()
            self._apt_cache = apt.Cache()
            self._push_config()
        elif uri.startswith('deb-install?'):
            process_deburl(uri[12:])
            self._apt_cache.close()
            self._apt_cache = apt.Cache()
            self._push_config()
        elif uri == 'autostart':
            self._config.autostart ^= True
            self._push_config()
        elif uri == 'install':
            subprocess.Popen(['ubiquity','gtk_ui'])
        elif uri == 'backup':
            subprocess.Popen(['deja-dup-preferences'])
        elif uri == 'chatroom':
            subprocess.Popen(['hexchat','IRC://irc.freenode.net/ubuntu-mate'])
        elif uri == 'control':
            subprocess.Popen(['mate-control-center'])
        elif uri == 'drivers':
            subprocess.Popen(['software-properties-gtk','--open-tab=4'])
        elif uri == 'firewall':
            subprocess.Popen(['gufw'])
        elif uri == 'language':
            subprocess.Popen(['gnome-language-selector'])
        elif uri == 'users':
            subprocess.Popen(['users-admin'])
        elif uri == 'quit':
            Gtk.main_quit()
        elif uri == 'tweak':
            subprocess.Popen(['mate-tweak'])
        elif uri == 'update':
            subprocess.Popen(['update-manager'])
        elif uri.startswith('run?'):
            subprocess.Popen([uri[4:]])
        elif uri.startswith('link?'):
            webbrowser.open_new_tab(uri[5:])
        else:
            print('Unknown command: %s' % uri)

class WelcomeApp(object):
    def __init__(self):
        # establish our location
        self._location = os.path.dirname( os.path.abspath(inspect.getfile(inspect.currentframe())) )

        # check for relative path
        if( os.path.exists( os.path.join(self._location, 'data/' ) ) ):
            print('Using relative path for data source. Non-production testing.')
            self._data_path = os.path.join(self._location, 'data/')
        elif( os.path.exists('/usr/share/ubuntu-mate-welcome/') ):
            print('Using /usr/share/ubuntu-mate-welcome/ path.')
            self._data_path = '/usr/share/ubuntu-mate-welcome/'
        else:
            print('Unable to source the ubuntu-mate-welcome data directory.')
            sys.exit(1)

        self._build_app()

    def _build_app(self):

        # build window
        w = Gtk.Window()
        w.set_position(Gtk.WindowPosition.CENTER)
        w.set_wmclass('Ubuntu MATE Welcome', 'Ubuntu MATE Welcome')
        w.set_title('Welcome to Ubuntu MATE')

        # http://askubuntu.com/questions/153549/how-to-detect-a-computers-physical-screen-size-in-gtk
        s = Gdk.Screen.get_default()
        if s.get_height() <= 600:
            w.set_size_request(768, 528)
        else:
            w.set_size_request(768, 552)

        icon_dir = os.path.join(self._data_path, 'img', 'welcome', 'ubuntu-mate-icon.png')
        w.set_icon_from_file(icon_dir)

        # build webkit container
        mv = AppView()

        # load our index file
        file = os.path.abspath(os.path.join(self._data_path, 'splash.html'))
        uri = 'file://' + urllib.request.pathname2url(file)
        mv.open(uri)

        # build scrolled window widget and add our appview container
        sw = Gtk.ScrolledWindow()
        sw.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
        sw.add(mv)

        # build a an autoexpanding box and add our scrolled window
        b = Gtk.VBox(homogeneous=False, spacing=0)
        b.pack_start(sw, expand=True, fill=True, padding=0)

        # add the box to the parent window and show
        w.add(b)
        w.connect('delete-event', self.close)
        w.show_all()

        self._window = w
        self._appView = mv

    def run(self):
        signal.signal(signal.SIGINT, signal.SIG_DFL)
        Gtk.main()

    def close(self, p1, p2):
        Gtk.main_quit(p1, p2);

if __name__ == "__main__":
    app = WelcomeApp()
    app.run()
