#!/usr/bin/python3
# vim:et:sta:sts=4:sw=4:ts=8:tw=79:

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
from gi.repository import GLib
import os
import sys
import subprocess
import errno
import chardet
import hashlib
import threading
import gzip
import urllib.request, urllib.error, urllib.parse
import urlgrabber
import urlgrabber.progress as urlp
from textconfig import TextConfig

# Internationalization
import locale
import gettext
locale.setlocale(locale.LC_ALL, '')
locale.bindtextdomain("salix-codecs-installer", "/usr/share/locale")
gettext.bindtextdomain("salix-codecs-installer", "/usr/share/locale")
gettext.textdomain("salix-codecs-installer")
_ = gettext.gettext

spkg = '/sbin/spkg'
package_dir = '/var/lib/pkgtools/packages/'

installed_pkgs = []
for i in os.listdir(package_dir):
    installed_pkgs.append(i.rpartition('-')[0].rpartition('-')[0]
            .rpartition('-')[0])

canceltask = False


def threaded(f):
    def wrapper(*args):
        t = threading.Thread(target=f, args=args)
        t.start()
    return wrapper

def pkg_is_installed(pkg):
    if '|' in pkg:
        alternatives = pkg.split('|')
        for alt in alternatives:
            if alt in installed_pkgs:
                return True, None
        return False, alternatives[0]
    if pkg in installed_pkgs:
        return True, None
    return False, pkg



class DownloadMeter(urlp.BaseMeter):

    def __init__(self, fo=sys.stderr):
        urlp.BaseMeter.__init__(self)
        self.fo = fo

    def _do_update(self, amount_read, now=None):
        if not canceltask:
            rate = urlp.format_number(self.re.average_rate())
            frac = self.re.fraction_read()
            app.progressbar_repo.set_fraction(frac)
            app.label_repo_rate.set_text(
                _('Download rate:') + ' ' + rate + 'B/s')
        else:
            raise KeyboardInterrupt


class SalixCodecsInstaller:
    c = TextConfig('/etc/slapt-get/slapt-getrc')
    working_dir = c.get('WORKINGDIR')
    sources = c.get_all('SOURCE')

    def __get_head(self, url):
        u = urllib.request.urlopen(url)
        head = u.headers['last-modified']
        return 'Last-Modified: ' + head

    def __local_head(self, working_dir, url):
        fname = self.__mangled_url(url)
        try:
            f = open(working_dir + '/' + fname + '.head')
            return f.read().replace('\n', '')
        except IOError:
            return None

    def __store_head(self, working_dir, filename, head):
        with open(working_dir + '/' + filename, 'w') as f:
            f.write(head)

    def __mangled_url(self, url):
        mangled = '.' + url.replace('/', '#')
        return mangled

    def __unmangled_url(self, repo):
        working_dir = self.working_dir
        if not working_dir.endswith('/'):
            working_dir = working_dir + '/'
        unmangled = repo.replace('#', '/').partition(working_dir + '.')[2]
        return unmangled

    def create_dir(self, dir):
        try:
            os.makedirs(dir)
        except OSError as exc:
            if exc.errno == errno.EEXIST:
                pass
            else:
                raise

    def download_repofile(self, working_dir, url):
        new = self.__get_head(url)
        local = self.__local_head(working_dir, url)
        murl = self.__mangled_url(url)
        if new == local:
            # file is already there
            self.progressbar_repo.set_fraction(1)
        else:
            urlgrabber.urlgrab(url, filename=working_dir +
                               '/' + murl, progress_obj=meter)
            self.__store_head(working_dir, murl + '.head', new)

    def get_sources(self):
        sources = []
        for i in self.sources:
            if i.rstrip(' ').upper().endswith(':DEFAULT'):
                priority = 0
                url = i.rpartition(':')[0]
            elif i.rstrip(' ').upper().endswith(':OFFICIAL'):
                priority = 2
                url = i.rpartition(':')[0]
            elif i.rstrip(' ').upper().endswith(':PREFERRED'):
                priority = 4
                url = i.rpartition(':')[0]
            elif i.rstrip(' ').upper().endswith(':CUSTOM'):
                priority = 6
                url = i.rpartition(':')[0]
            else:
                priority = 0
                url = i
            sources.append([url, priority])
        return sources

    def url_exists(self, url):
        try:
            u = urllib.request.urlopen(url)
            return True
        except urllib.error.HTTPError as xxx_todo_changeme:
            urllib.error.URLError = xxx_todo_changeme
            return False

    def verify_checksum(self, working_dir, file):
        cmd = 'gpg --verify ' + working_dir + '/' + \
            file + '.asc ' + working_dir + '/' + file
        retval = subprocess.call(cmd, shell=True)
        if retval == 0:
            # successful verification
            return True
        elif retval == 2:
            # no gpg key found
            return True
        elif retval == 512:
            # no gpg key found (different error code?)
            return True
        else:
            return False

    def write_package_data_file(self, pkgtxt_file, mirror, priority,
                                checksums_list):
        working_dir = self.working_dir
        with open(working_dir + '/package_data', 'a') as f:
            has_mirror_line = False
            is_extra = False
            pkgname = ''
            for line in pkgtxt_file:
                try:
                    line_str = line.decode()
                except UnicodeDecodeError:
                    # sometimes weird characters end up in the package description
                    # and throw an exception with decode(). In that case, we try to
                    # guess the encoding and go with that. If it still doesn't
                    # work, just drop it, it's just a description line, nothing too
                    # important
                    encoding = chardet.detect(line)['encoding']
                    try:
                        line_str = line.decode(encoding)
                    except UnicodeDecodeError:
                        continue
                if line_str.startswith('PACKAGE NAME'):
                    pkgname = line_str.partition('PACKAGE NAME:')[2].strip()
                    has_mirror_line = False
                    is_extra = False
                    f.write(line_str)
                elif line_str.startswith('PACKAGE MIRROR'):
                    has_mirror_line = True
                    if line_str.rpartition('\n')[0].rstrip('/').endswith('extra'):
                        is_extra = True
                    f.write(line_str)
                elif line_str.startswith('PACKAGE LOCATION'):
                    if not has_mirror_line:
                        f.write('PACKAGE MIRROR:  ' + mirror + '\n')
                    f.write('PACKAGE PRIORITY:  ' + str(priority) + '\n')
                    if is_extra:
                        location = './' + \
                            line_str.partition('PACKAGE LOCATION:')[2].lstrip(
                                ' ').partition('/extra/')[2]
                        f.write('PACKAGE LOCATION:  ' + location)
                    else:
                        f.write(line_str)
                elif line_str.startswith('PACKAGE SUGGESTS'):
                    f.write(line_str)
                    for sum in checksums_list:
                        if sum[1] == pkgname:
                            f.write('PACKAGE MD5SUM:  ' + sum[0] + '\n')
                            break
                else:
                    f.write(line_str)

    def create_package_data(self, repos):
        working_dir = self.working_dir
        # Make sure the package_data file is empty
        with open(working_dir + '/package_data', 'w') as f:
            pass
        for i in repos:
            pkgtxtpath = i[0]
            priority = i[1]
            patchespath = i[2]
            checksumspath = i[3]
            # Read all checksums in a list
            checksums_list = []
            if checksumspath.endswith('.gz'):
                with gzip.open(checksumspath, 'rb') as f:
                    checksums_file = f.readlines()
            else:
                with open(checksumspath) as f:
                    checksums_file = f.readlines()
            for line in checksums_file:
                try:
                    line_str = line.decode()
                except AttributeError:
                    # so, line usually comes out as bytes, so decode() is
                    # needed, but sometimes it comes out as a string, so we
                    # get an
                    # AttributeError: 'str' object has no attribute 'decode'
                    # exception instead.
                    line_str = line
                line_str_last = line_str.rpartition('\n')[0]
                checksum = line_str_last.partition('  ')[0]
                pkgname = line_str_last.partition('  ')[2].rpartition('/')[2]
                checksums_list.append([checksum, pkgname])
            mirror = self.__unmangled_url(pkgtxtpath).rpartition('/')[0] + '/'
            # Read PACKAGES.TXT files and add the info to the package_data file
            if pkgtxtpath.endswith('.gz'):
                with gzip.open(pkgtxtpath, 'rb') as f:
                    pkgtxt_file = f.readlines()
            else:
                with open(pkgtxtpath) as f:
                    pkgtxt_file = f.readlines()
            self.write_package_data_file(
                pkgtxt_file, mirror, priority, checksums_list)
            # Read PACKAGES.TXT from patches dir
            if patchespath is not None:
                if patchespath.endswith('.gz'):
                    with gzip.open(patchespath, 'rb') as f:
                        pkgtxt_file = f.readlines()
                else:
                    with open(patchespath) as f:
                        pkgtxt_file = f.readlines()
                self.write_package_data_file(
                    pkgtxt_file, mirror, priority + 1, checksums_list)
        self.progressbar_repo_total.set_fraction(1)
        self.label_repo_desc.set_text(_('Reading package lists...'))

    def download_repo_info(self):
        global canceltask
        sources = self.get_sources()
        working_dir = self.working_dir
        allrepos = []
        # There are 6 different files to (try to) download for every
        # repo + one final step for reading the package lists into the
        # package_data file
        steps = len(sources) * 6.0 + 1
        step = 0

        for repo in sources:
            if not canceltask:
                repo_files = []
                self.label_repo_rate.set_text('')
                repo_url = repo[0]
                if not repo_url.endswith('/'):
                    repo_url = repo_url + '/'
                repo_priority = repo[1]
                self.label_repo_name.set_text(repo_url)
                # Retrieve package data
                if self.url_exists(repo_url + 'PACKAGES.TXT.gz'):
                    url = repo_url + 'PACKAGES.TXT.gz'
                elif self.url_exists(repo_url + 'PACKAGES.TXT'):
                    url = repo_url + 'PACKAGES.TXT'
                else:
                    self.dialog_update.hide()
                    self.messagedialog_sources_error.show()
                self.label_repo_desc.set_text(_('Retrieving package data...'))
                self.download_repofile(working_dir, url)
                fullpath = working_dir + '/' + self.__mangled_url(url)
                repo_files.append(fullpath)
                repo_files.append(repo_priority)
                step += 1
                self.progressbar_repo_total.set_fraction(step / steps)
                self.progressbar_repo.set_fraction(1)
            if not canceltask:
                # Retrieve patch list
                patches = False
                if self.url_exists(repo_url + 'patches/PACKAGES.TXT.gz'):
                    url = repo_url + 'patches/PACKAGES.TXT.gz'
                    patches = True
                elif self.url_exists(repo_url + 'patches/PACKAGES.TXT'):
                    url = repo_url + 'patches/PACKAGES.TXT'
                    patches = True
                if patches:
                    self.label_repo_desc.set_text(
                        _('Retrieving patch list...'))
                    self.download_repofile(working_dir, url)
                    fullpath = working_dir + '/' + self.__mangled_url(url)
                    repo_files.append(fullpath)
                    self.progressbar_repo.set_fraction(1)
                else:
                    repo_files.append(None)
                step += 1
                self.progressbar_repo_total.set_fraction(step / steps)
            if not canceltask:
                # Retrieve checksum list
                if self.url_exists(repo_url + 'CHECKSUMS.md5.gz'):
                    url = repo_url + 'CHECKSUMS.md5.gz'
                elif self.url_exists(repo_url + 'CHECKSUMS.md5'):
                    url = repo_url + 'CHECKSUMS.md5'
                else:
                    self.dialog_update.hide()
                    self.messagedialog_sources_error.show()
                self.label_repo_desc.set_text(_('Retrieving checksum list...'))
                self.download_repofile(working_dir, url)
                fullpath = working_dir + '/' + self.__mangled_url(url)
                repo_files.append(fullpath)
                step += 1
                self.progressbar_repo_total.set_fraction(step / steps)
                self.progressbar_repo.set_fraction(1)
            if not canceltask:
                # Retrieve checksum signature
                checksumsig = False
                if self.url_exists(repo_url + 'CHECKSUMS.md5.gz.asc'):
                    url = repo_url + 'CHECKSUMS.md5.gz.asc'
                    checksumsig = True
                elif self.url_exists(repo_url + 'CHECKSUMS.md5.asc'):
                    url = repo_url + 'CHECKSUMS.md5.asc'
                    checksumsig = True
                if checksumsig:
                    self.label_repo_desc.set_text(
                        _('Retrieving checksum signature...'))
                    self.download_repofile(working_dir, url)
                    self.progressbar_repo.set_fraction(1)
                step += 1
                self.progressbar_repo_total.set_fraction(step / steps)
            if not canceltask:
                # Verify checksum
                if checksumsig:
                    checksum = self.__mangled_url(url.rpartition('.asc')[0])
                    self.label_repo_desc.set_text(
                        _('Verifying checksum signature...'))
                    if not self.verify_checksum(working_dir, checksum):
                        self.dialog_update.hide()
                        self.messagedialog_repo_checksum.show()
                step += 1
                self.progressbar_repo_total.set_fraction(step / steps)
            if not canceltask:
                # Retrieve ChangeLog.txt
                if self.url_exists(repo_url + 'ChangeLog.txt'):
                    url = repo_url + 'ChangeLog.txt'
                    self.label_repo_desc.set_text(
                        _('Retrieving ChangeLog.txt...'))
                    self.download_repofile(working_dir, url)
                    self.progressbar_repo.set_fraction(1)
                step += 1
            if not canceltask:
                self.progressbar_repo_total.set_fraction(step / steps)
                allrepos.append(repo_files)
        return allrepos

    def pkg_deps_and_sugs(self, pkgname):
        cmd = ['LANG=C /usr/sbin/slapt-get --show ' + pkgname +
               '|grep "^Package Required:\|^Package Suggests:"']
        process = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
        output = process.communicate()[0].decode()
        pkgs = []
        for line in output.split('\n'):
            if line.startswith('Package'):
                for i in line.rpartition('Package Required:')[2]\
                                        .rpartition('Package Suggests:')[2]\
                                        .strip(' ')\
                                        .replace(' ', ',')\
                                        .split(','):
                    if i != '':
                        pkgs.append(i)
        return pkgs

    def pkglist(self):
        with open('/usr/share/salix-codecs-installer/codecs-list.txt', 'r') as f:
            pkgs = f.readlines()
        pkgs[:] = [x.rstrip() for x in pkgs]
        deps = []
        for pkg in pkgs:
            for i in self.pkg_deps_and_sugs(pkg):
                deps.append(i)
        for i in pkgs:
            deps.append(i)

        to_be_installed = []
        for i in set(deps):
            installed, name = pkg_is_installed(i)
            if not installed:
                to_be_installed.append(name)
        return set(to_be_installed)

    def pkg_uris(self, pkglist):
        pkgstr = ' '.join(pkglist)
        cmd = [ 'LANG=C /usr/sbin/slapt-get --print-uris -s -i ' + pkgstr ]
        process = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
        output = process.communicate()[0].decode().split('\n')
        uris = []
        for line in output:
            line = line.strip()
            if line.startswith('https:') or line.startswith('http:') or line.startswith('ftp:'):
                uris.append(line)
        return uris

    def pkg_detailed_list(self, uris):
        working_dir = self.working_dir
        with open(working_dir + '/package_data') as f:
            package_data = f.readlines()
        uri_list = []
        for i in uris:
            pkgname = i.rpartition('/')[2]
            uri_list.append([pkgname, i])
        pkgfilename = ''
        pkgname = ''
        pkgver = ''
        pkgname_match = False
        location = ''
        location_found = False
        md5sum = ''
        md5sum_found = False
        description = ''
        description_found = False
        detailed_list = []
        for line in package_data:
            try:
                line_str = line.decode()
            except AttributeError:
                # well, this comes out as a string sometimes...
                line_str = line
            except UnicodeDecodeError:
                # sometimes weird characters end up in the package description
                # and throw an exception with decode(). In that case, we try to
                # guess the encoding and go with that. If it still doesn't
                # work, just drop it, it's just a description line, nothing too
                # important
                encoding = chardet.detect(line)['encoding']
                try:
                    line_str = line.decode(encoding)
                except UnicodeDecodeError:
                    continue
            if line_str.startswith('PACKAGE NAME'):
                pkgfilename = line_str.partition('PACKAGE NAME:')[2].strip()
                for i in uri_list:
                    if pkgfilename == i[0]:
                        pkgname = pkgfilename.rpartition(
                            '-')[0].rpartition('-')[0].rpartition('-')[0]
                        pkgver = pkgfilename.partition(
                            pkgname)[2].lstrip('-').rpartition('.')[0]
                        uri = i[1]
                        pkgname_match = True
                        location_found = False
            elif line_str.startswith('PACKAGE LOCATION'):
                location = line_str.partition('PACKAGE LOCATION:')[2].strip()
                location_found = True
            elif line_str.startswith('PACKAGE MD5SUM'):
                md5sum = line_str.partition('PACKAGE MD5SUM:')[2].strip()
                md5sum_found = True
            elif line_str.startswith(pkgname + ':'):
                if description_found is False:
                    description = line_str.partition(
                        pkgname + ': ')[2].rstrip('\n')
                    description_found = True
            if pkgname_match and location_found and md5sum_found and \
                    description_found:
                detailed_list.append([pkgname, pkgver, pkgfilename, uri,
                                      location, md5sum, description])
                pkgname = ''
                pkgver = ''
                pkgname_match = False
                location = ''
                location_found = False
                md5sum = ''
                md5sum_found = False
                description = ''
                description_found = False
        return sorted(detailed_list)

    @threaded
    def on_button_infowindow_yes_clicked(self, widget):
        try:
            GLib.idle_add(self.infowindow.hide)
            GLib.idle_add(self.dialog_update.show)
            GLib.idle_add(self.dialog_update.set_title, _('Updating local package cache'))
            repos = self.download_repo_info()
            self.create_package_data(repos)
            pkglist = self.pkglist()
            uris = self.pkg_uris(pkglist)
            to_be_installed = self.pkg_detailed_list(uris)
            if len(to_be_installed) == 0:
                GLib.idle_add(self.dialog_update.hide)
                GLib.idle_add(self.messagedialog_nopkgs.show)
            else:
                GLib.idle_add(self.dialog_update.hide)
                GLib.idle_add(self.dialog_pkglist.show)
                for i in to_be_installed:
                    # Passing checkbox state (True), changed state (False),
                    # pkgname, pkgver, pkgfilename,
                    # uri, location, md5sum, descrption
                    self.liststore_pkglist.append(
                        [True, False,
                         i[0], i[1], i[2], i[3], i[4], i[5], i[6]])
        except KeyboardInterrupt:
            GLib.idle_add(self.dialog_update.hide)
        except IOError:
            GLib.idle_add(self.dialog_update.hide)
            GLib.idle_add(self.messagedialog_dir_error.show)

    def on_button_infowindow_no_clicked(self, widget):
        Gtk.main_quit()

    @threaded
    def on_button_update_cancel_clicked(self, widget):
        global canceltask
        canceltask = True
        GLib.idle_add(self.dialog_update.hide)
        Gtk.main_quit()

    @threaded
    def on_dialog_update_delete_event(self, widget, event):
        global canceltask
        canceltask = True
        GLib.idle_add(self.dialog_update.hide)
        Gtk.main_quit()

    def md5sum_check(self, filename, md5sum):
        md5 = hashlib.md5()
        with open(filename, 'rb') as f:
            while True:
                data = f.read(8192)
                if not data:
                    break
                md5.update(data)
            local_md5 = md5.hexdigest()
            return local_md5 == md5sum

    @threaded
    def on_button_dlg_pkglist_exec_clicked(self, widget):
        try:
            working_dir = self.working_dir
            GLib.idle_add(self.dialog_pkglist.hide)
            GLib.idle_add(self.dialog_update.show)
            GLib.idle_add(self.progressbar_repo_total.set_fraction, 0)
            GLib.idle_add(self.progressbar_repo.set_fraction, 0)
            GLib.idle_add(self.dialog_update.set_title, _('Downloading packages'))
            steps = 0
            step = 0.0
            # count how many packages are to be downloaded/installed
            for i in self.liststore_pkglist:
                enabled = i[0]
                if enabled:
                    steps += 1
            # *2 because we download the md5sum too
            steps = steps * 2
            # download packages
            for i in self.liststore_pkglist:
                if not canceltask:
                    enabled = i[0]
                    pkgname = i[2]
                    pkgver = i[3]
                    pkgfilename = i[4]
                    uri = i[5]
                    location = i[6]
                    md5sum = i[7]
                    pkgdesc = i[8]
                    if enabled:
                        destdir = working_dir + '/' + location
                        dest = destdir + '/' + pkgfilename
                        self.create_dir(destdir)
                        if os.path.isfile(dest):
                            if self.md5sum_check(dest, md5sum):
                                download = False
                            else:
                                download = True
                        else:
                            download = True
                        GLib.idle_add(self.label_repo_desc.set_text, pkgfilename)
                        GLib.idle_add(self.label_repo_name.set_text, pkgdesc)
                        GLib.idle_add(self.progressbar_repo_total.set_fraction, step / steps)
                        GLib.idle_add(self.progressbar_repo.set_fraction, 0)
                        if download:
                            urlgrabber.urlgrab(
                                uri, filename=dest, progress_obj=meter)
                            if not self.md5sum_check(dest, md5sum):
                                # FIXME
                                # check if this actually works right
                                # I'll need to make a temp repo with a bad pkg
                                # md5sum
                                GLib.idle_add(self.dialog_update.hide)
                                GLib.idle_add(self.messagedialog_pkg_checksum.show)
                        step += 1
            GLib.idle_add(self.progressbar_repo_total.set_fraction, 1)
            # install packages
            GLib.idle_add(self.progressbar_repo_total.set_fraction, 0)
            GLib.idle_add(self.progressbar_repo.hide)
            GLib.idle_add(self.dialog_update.set_title, _('Installing packages'))
            success = True
            for i in self.liststore_pkglist:
                if not canceltask:
                    enabled = i[0]
                    pkgname = i[2]
                    pkgver = i[3]
                    pkgfilename = i[4]
                    location = i[6]
                    pkgdesc = i[8]
                    if enabled:
                        GLib.idle_add(self.label_repo_desc.set_text, pkgfilename)
                        GLib.idle_add(self.label_repo_name.set_text, pkgdesc)
                        GLib.idle_add(self.progressbar_repo_total.set_fraction, step / steps)
                        pkg = working_dir + '/' + location + '/' + pkgfilename
                        retval = subprocess.call(
                            [spkg, '-u', '--install-new', pkg])
                        if retval != 0:
                            success = False
                            GLib.idle_add(self.dialog_update.hide)
                            GLib.idle_add(self.messagedialog_pkginstall_error.show)
                            break
                    step += 1
            if success:
                GLib.idle_add(self.dialog_update.hide)
                GLib.idle_add(self.messagedialog_uninstall.show)
            else:
                # FIXME
                # check if this actually pops up as it's supposed to, after
                # a package has been downloaded succesfully, but spkg can't
                # install it for some reason
                GLib.idle_add(self.dialog_update.hide)
                GLib.idle_add(self.messagedialog_pkginstall_error.show)
        except KeyboardInterrupt:
            GLib.idle_add(self.dialog_update.hide)
        except OSError:
            GLib.idle_add(self.dialog_update.hide)
            GLib.idle_add(self.messagedialog_dir_error.show)
        except IOError:
            GLib.idle_add(self.dialog_update.hide)
            GLib.idle_add(self.messagedialog_dir_error.show)

    def on_button_dlg_pkglist_cancel_clicked(self, widget):
        Gtk.main_quit()

    def on_dialog_pkglist_delete_event(self, widget, event):
        Gtk.main_quit()

    def on_checkbox_toggled(self, widget, data=None):
        selectedpkg = self.treeview_pkglist.get_selection()
        self.liststore_pkglist, iter = selectedpkg.get_selected()
        selectedpkgname = self.liststore_pkglist.get_value(iter, 2)
        for i in self.liststore_pkglist:
            if i[2] == selectedpkgname:
                i[1] = True
                if i[0] == True:
                    i[0] = False
                else:
                    i[0] = True

    @threaded
    def on_button_uninstall_clicked(self, widget):
        GLib.idle_add(self.messagedialog_uninstall.hide)
        cmd = ['/sbin/spkg', '-d', 'salix-codecs-installer']
        process = subprocess.Popen(cmd)
        process.wait()
        Gtk.main_quit()

    def on_messagedialog_delete_event(self, widget, event):
        Gtk.main_quit()

    def on_messagedialog_response(self, widget, event):
        Gtk.main_quit()

    def on_messagedialog_dir_error_response(self, widget, event):
        Gtk.main_quit()

    def gtk_main_quit(self, widget, data=None):
        Gtk.main_quit()

    def __init__(self):
        builder = Gtk.Builder()
        builder.set_translation_domain("salix-codecs-installer")
        if os.path.exists('salix-codecs-installer.ui'):
            builder.add_from_file('salix-codecs-installer.ui')
        elif os.path.exists('/usr/share/salix-codecs-installer/salix-codecs-installer.ui'):
            builder.add_from_file('/usr/share/salix-codecs-installer/salix-codecs-installer.ui')
        self.window = builder.get_object('salix-codecs-installer')

        #
        # Info window
        #
        self.infowindow = builder.get_object('infowindow')
        self.button_infowindow_yes = builder.get_object(
            'button_infowindow_yes')
        self.button_infowindow_no = builder.get_object('button_infowindow_no')
        self.info_message = builder.get_object('label_info_message')
        line1=_('Some multimedia codecs are patent encumbered and pose distribution problems in certain countries. Therefore, support for all codecs is not included by default in Salix.')
        line2=_('You will be able to play files encoded with free codecs, but you will not be able to play commercial DVDs or use some proprietary formats without these codecs.')
        line3=_('Please check the legislation in your country and select to install the codecs only if it is legal for you to do so.')
        line4=_('Click Next to update the package cache and receive a list of packages about to be installed.')
        self.info_message.set_text(line1 + '\n\n' + line2 + '\n\n' + line3 + '\n\n' + line4)

        #
        # Update package cache dialog
        #
        self.dialog_update = builder.get_object('dialog_update')
        self.button_update_cancel = builder.get_object('button_update_cancel')
        self.progressbar_repo_total = builder.get_object(
            'progressbar_repo_total')
        self.progressbar_repo = builder.get_object('progressbar_repo')
        self.label_repo_rate = builder.get_object('label_repo_rate')
        self.label_repo_desc = builder.get_object('label_repo_desc')
        self.label_repo_name = builder.get_object('label_repo_name')

        # Error dialogs
        self.messagedialog_sources_error = builder.get_object(
            'messagedialog_sources_error')
        self.messagedialog_pkginstall_error = builder.get_object(
            'messagedialog_pkginstall_error')
        self.messagedialog_dir_error = builder.get_object(
            'messagedialog_dir_error')
        self.messagedialog_repo_checksum = builder.get_object(
            'messagedialog_repo_checksum')
        self.messagedialog_pkg_checksum = builder.get_object(
            'messagedialog_pkg_checksum')

        #
        # Package list dialog
        #
        self.dialog_pkglist = builder.get_object('dialog_pkglist')
        self.treeview_pkglist = builder.get_object('treeview_pkglist')
        self.liststore_pkglist = builder.get_object('liststore_pkglist')
        self.button_dlg_pkglist_exec = builder.get_object(
            'button_dlg_pkglist_cancel')
        self.button_dlg_pkglist_cancel = builder.get_object(
            'button_dlg_pkglist_cancel')
        self.treeviewcolumn_checkbox = builder.get_object(
            'treeviewcolumn_checkbox')
        self.treeviewcolumn_checkbox.set_title(_('Install'))
        self.treeviewcolumn_pkgname = builder.get_object(
            'treeviewcolumn_pkgname')
        self.treeviewcolumn_pkgname.set_title(_('Name'))
        self.treeviewcolumn_pkgver = builder.get_object(
            'treeviewcolumn_pkgver')
        self.treeviewcolumn_pkgver.set_title(_('Version'))
        self.treeviewcolumn_pkgdesc = builder.get_object(
            'treeviewcolumn_pkgdesc')
        self.treeviewcolumn_pkgdesc.set_title(_('Description'))

        #
        # Remove package dialog
        #
        self.messagedialog_uninstall = builder.get_object(
            'messagedialog_uninstall')

        #
        # All packages are already installed dialog
        #
        self.messagedialog_nopkgs = builder.get_object('messagedialog_nopkgs')

        builder.connect_signals(self)

        self.create_dir(self.working_dir)


if __name__ == "__main__":
    app = SalixCodecsInstaller()
    meter = DownloadMeter()
    app.infowindow.show()
    Gtk.main()

