#!/usr/bin/python -tt
#
# Copyright 2005-2006  Red Hat, Inc.
#
# Jeremy Katz <katzj@redhat.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 2 only
#
# This program 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 Library General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

import os, sys, fcntl
import time
import logging

try:
    import gtk
    import gtk.glade
    import gobject
except Exception, e:
    print >> sys.stderr, "Unable to import modules.  Maybe you're not running under X?"
    sys.exit(1)

from rhpl.exception import installExceptionHandler
from rhpl.translate import _, N_, textdomain

from rpmUtils.miscutils import compareEVR
from yum.packages import YumLocalPackage

from pirut import *
from pirut.Errors import *

if os.path.exists("data/single.glade"):
    gladefn = "data/single.glade"
else:
    gladefn = "/usr/share/pirut/ui/single.glade"
I18N_DOMAIN="pirut"

class SinglePackageInstaller(GraphicalYumBase):
    def __init__(self):
        self.xml = gtk.glade.XML(gladefn, domain=I18N_DOMAIN)
        self.mainwin = self.xml.get_widget("InstallerWindow")
        self.mainwin.set_icon_from_file("/usr/share/pirut/pixmaps/installpkg.png")
        self._connectSignals()
        self._createPackageStore()
        self.mainwin.connect("delete_event", self.quit)

        # note that nothing which takes "time" should be called here!
        GraphicalYumBase.__init__(self, False)
        self.unsignedok = True
        self.doRpmDBSetup()        

    def _connectSignals(self):
        sigs = { "on_InstallerWindow_destroy": self.quit,
                 "on_quitButton_clicked": self.quit,
                 "on_applyButton_clicked": self._apply }
        self.xml.signal_autoconnect(sigs)

    def _createPackageStore(self):
        self.store = gtk.ListStore(gobject.TYPE_PYOBJECT)
        
        tree = self.xml.get_widget("packageList")
        tree.set_model(self.store)

        column = gtk.TreeViewColumn(None, None)
        column.set_clickable(True)
        txtr = gtk.CellRendererText()
        column.pack_start(txtr, True)
        column.set_cell_data_func(txtr, self.get_pkg_info)
        tree.append_column(column)

    def get_pkg_info(self, col, cell, model, i):
        pkg = model.get_value(i, 0)
        nevra = "%s" %(pkg,)
        desc = pkg.returnSimple('summary')
        text = "<span weight=\"bold\">%s</span>\n%s" %(nevra, desc)
        text.strip()
        cell.set_property("markup", text)

    def doRefresh(self, *args):
        self._busyCursor()
        self.populatePackages()
        self._normalCursor()

    def logDialog(self, msg):
        print msg
        d = gtk.MessageDialog(self.mainwin, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO,
                              gtk.BUTTONS_OK, msg)
        d.show_all()
        d.run()
        d.destroy()           

    def populatePackages(self):
        self.store.clear()

        updates = []
        installs = []
        for pkg in sys.argv[1:]:
            try:
                po = YumLocalPackage(ts=self.rpmdb.readOnlyTS(), filename=pkg)
            except yum.Errors.MiscError, e:
                log = logging.getLogger("yum")
                log.warn("Cannot open file: %s. Skipping." %(pkg,))
                continue

            if po.hdr[rpm.RPMTAG_SOURCEPACKAGE] == 1: # ugh.
                self.logDialog(_("Cannot install source packages."))
                continue

            inst = self.rpmdb.searchNevra(name=po.name)
            for instpo in inst:
                (n,a,e,v,r) = po.pkgtup
                (inn,ia,ie,iv,ir) = instpo.pkgtup
                rc = compareEVR((ie,iv,ir), (e,v,r))
                if rc < 0: # update
                    if n not in self.conf.exactarchlist or a == ia:
                        updates.append((po, instpo))
                    else:
                        self.logDialog(_("Can't install a different arch of %s than already installed.") %(pkg,))
                        continue
                elif rc == 0: # same, ignore
                    self.logDialog("%s is already installed" %(pkg,))
                elif rc > 0:
                    self.logDialog("A newer version than %s is already installed" %(pkg,))
            if len(inst) == 0:
                installs.append(po)

        for po in installs:
            self.localPackages.append(po)
            self.tsInfo.addInstall(po = po)
            self.store.append([po])
        for (po, oldpo) in updates:
            self.localPackages.append(po)
            self.tsInfo.addUpdate(po, oldpo)
            self.store.append([po])

        if len(self.tsInfo) <= 0:
            d = gtk.MessageDialog(self.mainwin, gtk.DIALOG_MODAL,
                                  gtk.MESSAGE_ERROR, gtk.BUTTONS_OK,
                                  _("No packages were given for installation."))
            d.show_all()
            d.run()
            d.destroy()
            self.quit()

    def _busyCursor(self):
        self.mainwin.window.set_cursor(gdk.Cursor(gdk.WATCH))
        self.mainwin.set_sensitive(False)

    def _normalCursor(self):
        self.mainwin.window.set_cursor(None)
        self.mainwin.set_sensitive(True)        

    def _apply(self, *args):
        # do a depsolve to see if we need to grab any other stuff... this is
        # kind of a hack knowing what resolveDeps does
        self.populateTs(test=1)
        deps = self.ts.check()
        if deps:
            pbar = PirutProgressCallback(_("Retrieving software information"),
                                         self.mainwin)
            pbar.show()
            self._busyCursor()
            try:
                self.reposSetup(pbar)
            except yum.Errors.LockError:
                pbar.destroy()
                self._normalCursor()
                d = gtk.MessageDialog(self.mainwin, gtk.DIALOG_MODAL,
                                      gtk.MESSAGE_ERROR, gtk.BUTTONS_OK,
                                      _("Another application is running which "
                                        "is accessing software information."))
                d.show_all()
                d.run()
                d.destroy()
                sys.exit(1)
            except PirutDownloadError, e:
                pbar.destroy()
                self._normalCursor()
                d = gtk.MessageDialog(self.mainwin, gtk.DIALOG_MODAL,
                                      gtk.MESSAGE_ERROR, gtk.BUTTONS_OK,
                                      _("Unable to retrieve software information"))
                d.format_secondary_text(_("Unable to retrieve software "
                                          "information.  This could be caused by "
                                          "not having a network connection "
                                          "available."))
                d.show_all()
                d.run()
                d.destroy()
                sys.exit(1)
                
            self._normalCursor()
            pbar.destroy()

        try:
            self.applyChanges(self.mainwin)
        except PirutError:
            self.quit()
        except OSError:
            d = gtk.MessageDialog(self.mainwin, gtk.DIALOG_MODAL,
                                  gtk.BUTTONS_OK,
                                  _("Unable to install software.  Error "
                                    "opening files."))
            d.show_all()
            d.run()
            d.destroy()
            self.quit()

        d = gtk.MessageDialog(self.mainwin, gtk.DIALOG_MODAL,
                              gtk.MESSAGE_INFO, gtk.BUTTONS_OK,
                              _("Software installed successfully."))
        d.show_all()
        d.run()
        d.destroy()
        self.quit()
            

    def run(self):
        self.mainwin.show_all()
        while gtk.events_pending(): gtk.main_iteration()
        self.doRefresh()
        gtk.main()

def main():
    textdomain(I18N_DOMAIN)
    gtk.glade.bindtextdomain(I18N_DOMAIN, "/usr/share/locale")
    try:
        pkginst = SinglePackageInstaller()
    except PirutError, e:
        startupError(e)
    pkginst.run()

if __name__ == "__main__":
    installExceptionHandler("Software Installer", "")
    main()
