from gtk import *
from gnome.ui import *
from iw import *
from string import *
from thread import *
from examine import *
import rpm
import GdkImlib
import string
import sys
import xpms
from translate import _

class IndividualPackageSelectionWindow (InstallWindow):

    def __init__ (self, ics):
	InstallWindow.__init__ (self, ics)

        self.todo = ics.getToDo ()
        ics.setTitle (_("Individual Package Selection"))
        ics.setNextEnabled (1)
        ics.readHTML ("sel-indiv")
        ics.setHelpEnabled (FALSE)
        self.DIR = 0
        self.DIR_UP = 1
        self.RPM = 2

        self.updatingIcons = FALSE

	self.idirImage = GdkImlib.create_image_from_xpm (xpms.I_DIRECTORY_XPM)
	self.idirUpImage = GdkImlib.create_image_from_xpm (xpms.I_DIRECTORY_UP_XPM)
	self.packageImage = GdkImlib.create_image_from_xpm (xpms.PACKAGE_XPM)
	self.packageSelectedImage = GdkImlib.create_image_from_xpm (xpms.PACKAGE_SELECTED_XPM)

    def getPrev (self):
        for x in self.ics.getICW ().stateList:
            if isinstance (x, PackageSelectionWindow):
                return PackageSelectionWindow
            elif isinstance (x, UpgradeExamineWindow):
                return UpgradeExamineWindow
        return None
    

    def build_tree (self, x):
        if (x == ()): return ()
        if (len (x) == 1): return (x[0],)
        else: return (x[0], self.build_tree (x[1:]))

    def merge (self, a, b):
        if a == (): return self.build_tree (b)
        if b == (): return a
        if b[0] == a[0]:
            if len (a) > 1 and isinstance (a[1], type (())):
                return (a[0],) + (self.merge (a[1], b[1:]),) + a[2:]
            elif b[1:] == (): return a
            else: return (a[0],) + (self.build_tree (b[1:]),) + a[1:]
        else:
            return (a[0],) + self.merge (a[1:], b)

    def build_ctree (self, list, cur_parent = None, prev_node = None, path = ""):
        if (list == ()): return
        
        if (len (list) > 1 and isinstance (list[1], type (()))): leaf = FALSE
        else: leaf = TRUE
    
        if isinstance (list[0], type (())):
            self.build_ctree (list[0], prev_node, None, self.ctree.node_get_row_data (prev_node))
            self.build_ctree (list[1:], cur_parent, None, path)
        else:
            node = self.ctree.insert_node (cur_parent, None, (list[0],), 2,
                                           self.closed_p, self.closed_b, self.open_p, self.open_b, leaf)
            cur_path = path + "/" + list[0]
            self.ctree.node_set_row_data (node, cur_path)
            self.build_ctree (list[1:], cur_parent, node, path)

    def draw_root_icons (self):
        self.iconList.freeze ()
        self.iconList.clear ()
        for x in self.ctree.base_nodes ():
            dirName = self.ctree.get_node_info (x)[0]
            pos = self.iconList.append_imlib (self.idirImage, dirName)
            self.iconList.set_icon_data (pos, (self.DIR, x))
        self.iconList.thaw ()


    def get_rpm_desc (self, header):
        desc = replace (header[rpm.RPMTAG_DESCRIPTION], "\n\n", "\x00")
        desc = replace (desc, "\n", " ")
        desc = replace (desc, "\x00", "\n\n")
        return desc

    def clear_package_desc (self):
        self.currentPackage = None
        self.packageName.set_text ("")
        self.packageSize.set_text ("")                 
        self.packageDesc.freeze ()
        self.packageDesc.delete_text (0, -1)
        self.packageDesc.thaw ()
        self.cbutton.set_active (FALSE)
        self.cbutton.set_sensitive (FALSE)

    
    def select_icon (self, iconList, arg1, event, *args):
        if event and event.type != GDK._2BUTTON_PRESS and event.type != GDK.BUTTON_PRESS:
            return
        icon_data = iconList.get_icon_data (arg1)
        if not icon_data: return

        if event and iconList.icon_is_visible (arg1) != VISIBILITY_FULL:
            allocation = iconList.get_allocation ()
            if (event.y - self.iconListAdj.value) < (allocation[3]/2):
                self.iconList.moveto (arg1, 0.0)
            else:
                self.iconList.moveto (arg1, 1.0)

        if event == None or event.type == GDK.BUTTON_PRESS:
            if icon_data[0] == self.RPM:
                header = icon_data[1]
                # if we're already displaying the current package, don't redraw
                if self.packageName.get () == "%s-%s-%s" % (header[rpm.RPMTAG_NAME],
                                                            header[rpm.RPMTAG_VERSION],
                                                            header[rpm.RPMTAG_RELEASE]):
                    return
                
                self.currentPackage = header
                self.currentPackagePos = arg1
                self.cbutton.set_sensitive (TRUE)
                if header.selected:
                    self.cbutton.set_active (TRUE)
                else:
                    self.cbutton.set_active (FALSE)
                    
                self.packageName.set_text ("%s-%s-%s" % (header[rpm.RPMTAG_NAME],
                                                         header[rpm.RPMTAG_VERSION],
                                                         header[rpm.RPMTAG_RELEASE]))
                self.packageSize.set_text ("%.1f KBytes" % (header[rpm.RPMTAG_SIZE] / 1024.0))
                self.packageDesc.freeze ()
                self.packageDesc.delete_text (0, -1)
                self.packageDesc.insert_defaults (self.get_rpm_desc (header))
                self.packageDesc.thaw ()
            else:
                self.clear_package_desc ()
            return

        if icon_data[0] == self.RPM:
            active = self.cbutton.get_active ()
            if active == TRUE:
                self.cbutton.set_active (FALSE)
            else:
                self.cbutton.set_active (TRUE)

        if icon_data[0] == self.DIR_UP:
            current_node = icon_data[1].parent
            if current_node:
                self.ctree.select (current_node)
            else:
                # handle the imaginary root node
                current_node = self.ctree.base_nodes ()[0]
                self.ctree.unselect (icon_data[1])
                self.draw_root_icons ()
                
        elif icon_data[0] == self.DIR:
            current_node = icon_data[1]
            self.ctree.select (current_node)
            if (current_node.parent):
                self.ctree.expand_to_depth (current_node.parent, 1)
	else: return

        if self.ctree.node_is_visible (current_node) != VISIBILITY_FULL:
            self.ctree.node_moveto (current_node, 0, 0.5, 0.0)

    def select (self, ctree, node, *args):
        self.clear_package_desc ()
        self.iconList.freeze ()
        self.iconList.clear ()
        self.iconList.append_imlib (self.idirUpImage, _("Up"))
        self.iconList.set_icon_data (0, (self.DIR_UP, node))
        for x in node.children:
            dirName = ctree.get_node_info (x)[0]
            pos = self.iconList.append_imlib (self.idirImage, dirName)
            self.iconList.set_icon_data (pos, (self.DIR, x))

        try:
            # this code is wrapped in a generic exception handler since we dont
            # care if we access a namespace that lacks rpms
            
            # drop the leading slash off the package namespace
            for header in self.flat_groups[ctree.node_get_row_data (node)[1:]]:
                if header.selected:
                    packageIcon = self.packageSelectedImage
                    self.cbutton.set_active (TRUE)
                else:
                    packageIcon = self.packageImage
                    self.cbutton.set_active (FALSE)
                
                pos = self.iconList.append_imlib (packageIcon, header[rpm.RPMTAG_NAME])
                self.iconList.set_icon_data (pos, (self.RPM, header))
        except:
            pass

	# make sure that the iconList is reset to show the initial files in a dir,
        # unless we re rebuilding the icons because one has been selected for install
        if not self.updatingIcons:
            self.iconListSW.get_vadjustment ().set_value (0.0)
        self.iconList.thaw ()
        self.iconList.show_all ()


    def installButtonToggled (self, cbutton, *args):
        if not self.currentPackage: return
        oldSelectedStatus = self.currentPackage.selected
        
        if cbutton.get_active ():
            self.currentPackage.selected = 1
        else:
            self.currentPackage.selected = 0

        
        if oldSelectedStatus != self.currentPackage.selected:
            self.updatingIcons = TRUE
            self.ctree.select (self.ctree.selection[0])
            self.iconList.select_icon (self.currentPackagePos)
            self.updatingIcons = FALSE
            
#            self.iconList.freeze ()
#            if self.currentPackage.selected:
#                packageIcon = "/home/devel/pnfisher/gnome-package-checked.png"
#            else:
#                packageIcon = "/usr/src/gnorpm/gnome-package.xpm"

#            print self.currentPackagePos
#            self.iconList.remove (self.currentPackagePos)
#            print _("got here")
#            self.iconList.insert (self.currentPackagePos, packageIcon,
#                                  self.currentPackage[rpm.RPMTAG_NAME])
#            self.iconList.set_icon_data (self.currentPackagePos, (self.RPM, self.currentPackage))
            
#            self.iconList.thaw ()


    def getScreen (self):
        threads_leave ()
        self.todo.getHeaderList()
        threads_enter ()

        self.path_mapping = {}
        self.ctree = GtkCTree ()
        self.ctree.set_selection_mode (SELECTION_BROWSE)
        # Kludge to get around CTree s extremely broken focus behavior
        self.ctree.unset_flags (CAN_FOCUS)

        if (not self.__dict__.has_key ("open_p")):
            self.open_p, self.open_b = create_pixmap_from_xpm_d (self.ctree,
                                                                 None, xpms.DIRECTORY_OPEN_XPM)
            self.closed_p, self.closed_b = create_pixmap_from_xpm_d (self.ctree,
                                                                     None, xpms.DIRECTORY_CLOSE_XPM)

        groups = {}

        # go through all the headers and grok out the group names, placing
        # packages in lists in the groups dictionary.
        
        for key in self.todo.hdList.packages.keys():
            header = self.todo.hdList.packages[key]
            if not groups.has_key (header[rpm.RPMTAG_GROUP]):
                groups[header[rpm.RPMTAG_GROUP]] = []
            # don't display package if it is in the Base group
            if not self.todo.comps["Base"].items.has_key (header):
                groups[header[rpm.RPMTAG_GROUP]].append (header)

        keys = groups.keys ()
        keys.sort ()
        self.flat_groups = groups
        index = 0

        # now insert the groups into the list, then each group's packages
        # after sorting the list
        def cmpHdrName(first, second):
            if first[rpm.RPMTAG_NAME] < second[rpm.RPMTAG_NAME]:
                return -1
            elif first[rpm.RPMTAG_NAME] == second[rpm.RPMTAG_NAME]:
                return 0
            return 1

        groups = ()
        for key in keys:
            self.flat_groups[key].sort (cmpHdrName)
            groups = self.merge (groups, split (key, "/"))
        self.ctree.freeze ()
        self.build_ctree (groups)

        for base_node in self.ctree.base_nodes ():
            self.ctree.expand_recursive (base_node)
        self.ctree.columns_autosize ()
        for base_node in self.ctree.base_nodes ():
            self.ctree.collapse_recursive (base_node)
        self.ctree.thaw ()

        self.ctree.connect ("tree_select_row", self.select)
        sw = GtkScrolledWindow ()
        sw.set_border_width (5)
        sw.set_policy (POLICY_NEVER, POLICY_AUTOMATIC)
        sw.add (self.ctree)
        iconHBox = GtkHBox ()
        iconHBox.pack_start (sw, FALSE)

        self.iconList = GnomeIconList (90)
        self.iconList.set_selection_mode (SELECTION_MULTIPLE)
	self.iconList.connect ("select_icon", self.select_icon)
        self.draw_root_icons ()

        self.iconListSW = GtkScrolledWindow ()
        self.iconListSW.set_border_width (5)
        self.iconListSW.set_policy (POLICY_NEVER, POLICY_AUTOMATIC)
        self.iconListSW.add (self.iconList)
        self.iconListAdj = self.iconListSW.get_vadjustment ()
        iconHBox.pack_start (self.iconListSW)

        descVBox = GtkVBox ()        
        descVBox.pack_start (GtkHSeparator (), FALSE, padding=3)


        hbox = GtkHBox ()
        label = GtkLabel (_("Name: "))
        self.packageName = GtkLabel ()
        self.packageName.set_alignment (0.0, 0.0)
        hbox.pack_start (label, FALSE, padding=5)
        hbox.pack_start (self.packageName, FALSE)
        label = GtkLabel (_("Package Details"))
        label.set_alignment (1.0, 1.0)
        hbox.pack_start (label, padding=5)
        descVBox.pack_start (hbox, FALSE)

        hbox = GtkHBox ()
        label = GtkLabel (_("Size: "))
        self.packageSize = GtkLabel ()
        self.packageSize.set_alignment (0.0, 0.5)
        hbox.pack_start (label, FALSE, padding=5)
        hbox.pack_start (self.packageSize, FALSE)
        align = GtkAlignment (1.0, 0.0)
        self.cbutton = GtkCheckButton (_("Select Package For Installation"))
        self.cbutton.set_sensitive (FALSE)
        self.cbutton.connect ("toggled", self.installButtonToggled)
        self.cbutton.children()[0].set_alignment (1.0, 0.5)
        align.add (self.cbutton)
        hbox.pack_start (align, padding=5)
        descVBox.pack_start (hbox, FALSE)

        descSW = GtkScrolledWindow ()
        descSW.set_border_width (5)
        descSW.set_policy (POLICY_AUTOMATIC, POLICY_AUTOMATIC)

        self.packageDesc = GtkText ()
        self.packageDesc.set_word_wrap (TRUE)
        self.packageDesc.set_line_wrap (TRUE)
        self.packageDesc.set_editable (FALSE)
        descSW.add (self.packageDesc)
        descSW.set_usize (-1, 100)

        descVBox.pack_start (descSW)

#        descFrame = GtkFrame (_("Package Details"))
#        descFrame.set_border_width (5)
#        descFrame.add (descVBox)
        
        vbox = GtkVBox ()
        vbox.pack_start (iconHBox)
        vbox.pack_start (descVBox, FALSE)

        return vbox

class PackageSelectionWindow (InstallWindow):
    def __init__ (self, ics):
	InstallWindow.__init__ (self, ics)

        ics.setTitle (_("Package Group Selection"))
        ics.setNextEnabled (1)
        ics.readHTML ("sel-group")
        self.selectIndividualPackages = FALSE

    def getNext (self):
	if not self.__dict__.has_key ("individualPackages"):
	    return None

        # turn off all the comps
        for comp in self.todo.comps:
            if not comp.hidden:
                comp.unselect(0)

        # turn on each package group in order (msw's code requires this)
        for (button, comp) in self.checkButtons:
            if button.get_active ():
                comp.select (1)

        del self.checkButtons

        gotoIndividualPackages = self.individualPackages.get_active ()
        del self.individualPackages
        
        if gotoIndividualPackages:
            self.selectIndividualPackages = TRUE
            return IndividualPackageSelectionWindow
        else:
            self.selectIndividualPackages = FALSE
          
        return None

    def getScreen (self):
        threads_leave ()
        self.todo.getHeaderList ()
        self.todo.getCompsList()
        threads_enter ()

        sw = GtkScrolledWindow ()
        sw.set_border_width (5)
        sw.set_policy (POLICY_AUTOMATIC, POLICY_AUTOMATIC)

        box = GtkVBox (FALSE, 0)

	self.checkButtons = []        
        for comp in self.todo.comps:
            if not comp.hidden:
                pixname = string.replace (comp.name, ' ', '-')
                pixname = string.replace (pixname, '/', '-')
                pixname = string.replace (pixname, '.', '-')
                pixname = string.replace (pixname, '(', '-')
                pixname = string.replace (pixname, ')', '-')
                pixname = string.lower (pixname) + ".png"
                picture = None
                checkButton = None
                im = self.ics.readPixmap (pixname)
                if im:
                    im.render ()
                    pix = im.make_pixmap ()
                    hbox = GtkHBox (FALSE, 5)
                    hbox.pack_start (pix, FALSE, FALSE, 0)
                    label = GtkLabel (comp.name)
                    label.set_alignment (0.0, 0.5)
                    hbox.pack_start (label, TRUE, TRUE, 0)
                    checkButton = GtkCheckButton ()
                    checkButton.add (hbox)
                else:
                    checkButton = GtkCheckButton (comp.name)

                checkButton.set_active (comp.selected)
                self.checkButtons.append ((checkButton, comp))
                box.pack_start (checkButton)

        sw.add_with_viewport (box)
        box.set_focus_hadjustment(sw.get_hadjustment ())
        box.set_focus_vadjustment(sw.get_vadjustment ())

        vbox = GtkVBox (FALSE, 5)
        self.individualPackages = GtkCheckButton (_("Select individual packages"))
        self.individualPackages.set_active (self.selectIndividualPackages)
        align = GtkAlignment (0.5, 0.5)
        align.add (self.individualPackages)

        vbox.pack_start (sw, TRUE)
        vbox.pack_start (align, FALSE)
        
        return vbox

