#
# bootloader_gui.py: gui bootloader configuration dialog
#
# Copyright 2001 Red Hat, Inc.
#
# This software may be freely redistributed under the terms of the GNU
# library public license.
#
# You should have received a copy of the GNU Library Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#

# must replace with explcit form so update disks will work
from iw_gui import *

from gtk import *
from gnome.ui import *
from translate import _, N_
import gdkpixbuf
import iutil
from package_gui import queryUpgradeContinue
import gui

class BootloaderWindow (InstallWindow):
    checkMark = None
    checkMark_Off = None

    windowTitle = N_("Boot Loader Configuration")
    htmlTag = "bootloader"

    def getPrev (self):
        # avoid coming back in here if the user backs past and then tries
        # to skip this screen
	pass

	# XXX
	#
        # if doing an upgrade, offer choice of aborting upgrade.
        # we can't allow them to go back in install, since we've
        # started swap and mounted the systems filesystems
        # if we've already started an upgrade, cannot back out
        #
        # if we are skipping indivual package selection, must stop it here
        # very messy.
        #
        #if self.todo.upgrade and self.todo.instClass.skipStep("indivpackage"):
            #rc = queryUpgradeContinue(self.todo.intf)
            #if not rc:
                #raise gui.StayOnScreen
            #else:
                #import sys
                #print _("Aborting upgrade")
                #sys.exit(0)

    def getNext (self):
        if self.lba.get_active() and not self.bl.forceLBA32:
            rc = self.intf.messageWindow(_("Warning"),
                    _("Forcing the use of LBA32 for your bootloader when "
                      "not supported by the BIOS can cause your machine "
                      "to be unable to boot.  We highly recommend you "
                      "create a boot disk when asked later in the "
                      "install process.\n\n"
                      "Would you like to continue and force LBA32 mode?"),
                                    type = "yesno")
            if rc != 1:
                raise gui.StayOnScreen

        if self.none_radio.get_active ():
	    self.dispatch.skipStep("instbootloader")
            self.dispatch.skipStep("bootloaderpassword")
            return
        elif self.lilo_radio.get_active ():
            self.dispatch.skipStep("bootloaderpassword")
        elif self.grub_radio.get_active ():
            self.dispatch.skipStep("bootloaderpassword", skip = 0)

        if len(self.bootDevice.keys()) > 0:
	    self.dispatch.skipStep("instbootloader", skip = 0)

	    for (widget, device) in self.bootDevice.items():
		if widget.get_active():
		    self.bl.setDevice(device)

        self.bl.setUseGrub(self.grub_radio.get_active())
        self.bl.args.set(self.appendEntry.get_text())
        
        default = None
        linuxDevice = None
        for index in range(self.numImages):
            device = self.imageList.get_text(index, 1)[5:]
            type = self.types[index]
            label = self.imageList.get_text(index, 3)

	    self.bl.images.setImageLabel(device, label, self.bl.useGrub())

            if self.default == index:
                default = device
            if type == 2:
                linuxDevice = device

        if not default:
            default = linuxDevice

        self.bl.images.setDefault(default)
        self.bl.setForceLBA(self.lba.get_active())
        

    def typeName(self, type):
        if (type == "FAT"):
            return "DOS/Windows"
        elif (type == "hpfs"):       
            return "OS/2 / Windows NT"
        else:
            return type

    def checkLiloReqs(self):
        if self.default == None:
            return 0

        defaultlabel = self.imageList.get_text(self.default, 3)
        if defaultlabel == "" or defaultlabel == None:
            return 0

        device = None
        label = None
        for i in range(self.numImages):
            device = self.imageList.get_text(i, 1)[5:]
            label  = self.imageList.get_text(i, 3)
            if device == self.rootdev:
                break

        if label == "":
            return 0

        for i in range(self.numImages):
            label1 = self.imageList.get_text(i, 3)
            j = i+1
            while j < self.numImages:
                label2 = self.imageList.get_text(j, 3)
                if label1 == label2 and label1 != "":
                    return 0
                j = j + 1


        return 1

    def toggled (self, widget, *args):
        if self.ignoreSignals:
            return
        
        if not widget.get_active ():
            state = TRUE
            if self.checkLiloReqs():
                self.ics.setNextEnabled (1)
            else:
                self.ics.setNextEnabled (0)            
        else:
            state = FALSE
            self.ics.setNextEnabled(1)

        list = self.bootDevice.keys()
        list.extend ([self.appendEntry, self.editBox, self.imageList,
                      self.liloLocationBox, self.radioBox, self.sw])
        for n in list:
            n.set_sensitive (state)

#        if state and not len(self.bootDevice.keys()) < 2:
#            self.liloLocationBox.set_sensitive(0)
#            self.grubCheck.set_sensitive(0)
#            print "here"
#            self.radio_hbox.set_sensitive(0)
#	    for n in self.bootDevice.keys():
#		n.set_sensitive(0)

    def labelInsertText(self, entry, text, len, data):
        i = 0
        while i < len:
            cur = text[i]

            # lilo did not allow ' '!, grub does
            if self.lilo_radio.get_active() and (cur == ' ' or cur == '#' or cur == '$' or cur == '='):
                entry.emit_stop_by_name("insert_text")
                return
            elif cur == '#' or cur == '$' or cur == '=':
                entry.emit_stop_by_name ("insert_text")
                return
            i = i + 1

    def labelUpdated(self, *args):
        index = self.imageList.selection[0]

        label = self.labelEntry.get_text()
        self.imageList.set_text(index, 3, label)

        # cannot allow user to select as default is zero length
        if label:
            self.defaultCheck.set_sensitive (TRUE)
        else:
            self.ignoreSignals = 1
            self.defaultCheck.set_active(0)
            self.defaultCheck.set_sensitive (FALSE)
            if self.default != None and self.default == index:
                self.imageList.set_text(self.default, 0, "")
                self.default = None
            self.ignoreSignals = 0
            
        if self.checkLiloReqs():
            self.ics.setNextEnabled (1)
        else:
            self.ics.setNextEnabled (0)


    def defaultUpdated(self, *args):
        if self.ignoreSignals: return

        index = self.imageList.selection[0]
        
        if range(self.count) > 0:
            for i in range(self.count):
                self.imageList.set_pixmap(i, 0, self.checkMark_Off)
        
        if self.defaultCheck.get_active():
            if self.default != None:
                self.imageList.set_pixmap(self.default, 0, self.checkMark_Off)

            self.imageList.set_pixmap(index, 0, self.checkMark)
            self.default = index
        else:
            self.imageList.set_pixmap(index, 0, self.checkMark_Off)
            self.default = None

        if self.checkLiloReqs():
            self.ics.setNextEnabled (1)
        else:
            self.ics.setNextEnabled (0)
        

    def labelSelected(self, *args):
        index = self.imageList.selection[0]
        device = self.imageList.get_text(index, 1)
        type = self.imageList.get_text(index, 2)
        label = self.imageList.get_text(index, 3)

        self.deviceLabel.set_text(_("Partition") + ": " + device)
        device = device[5:]

        self.typeLabel.set_text(_("Type") + ":" + type)
        self.labelEntry.set_text(label)
        
        # do not allow blank label to be default
        if not label:
            self.defaultCheck.set_active(0)
            self.defaultCheck.set_sensitive (FALSE)

        self.ignoreSignals = 1
        if index == self.default:
            self.defaultCheck.set_active(1)
        else:
            self.defaultCheck.set_active(0)
        self.ignoreSignals = 0

    def bootloaderchange(self, widget):
        if self.lilo_radio.get_active():
            selected = "lilo"
        elif self.grub_radio.get_active():
            selected = "grub"
        elif self.none_radio.get_active():
            return

        if not self.lastselected or selected == self.lastselected:
            return
        self.lastselected = selected

        # swap the label for what it was "last"...  this is conveniently
        # also the long form if we're switching back to grub or vice versa
        for index in range(self.numImages):
            tmp = self.oldLabels[index]
            self.oldLabels[index] = self.imageList.get_text(index, 3)
            self.imageList.set_text(index, 3, tmp)
        self.labelSelected()

    # LiloWindow tag="lilo"
    def getScreen(self, dispatch, bl, fsset, diskSet):
        if not BootloaderWindow.checkMark:
            BootloaderWindow.checkMark = self.ics.readPixmap("checkbox-on.png")
        if not BootloaderWindow.checkMark_Off:
            BootloaderWindow.checkMark_Off = self.ics.readPixmap("checkbox-off.png")            

	self.dispatch = dispatch
	self.bl = bl
        self.intf = dispatch.intf

	self.rootdev = fsset.getEntryByMountPoint("/").device.getDevice()

	imageList = bl.images.getImages()
	defaultDevice = bl.images.getDefault()
        self.ignoreSignals = 0

        self.radioBox = GtkTable(2, 6)
	self.bootDevice = {}
        self.radioBox.set_border_width (5)
        
        spacer = GtkLabel("")
        spacer.set_usize(10, 1)
        self.radioBox.attach(spacer, 0, 1, 2, 4, FALSE)

        label = GtkLabel(_("Install Boot Loader record on:"))
        label.set_alignment(0.0, 0.5)
        self.liloLocationBox = GtkVBox (FALSE, 0)
        self.liloLocationBox.pack_start(label)
        self.radioBox.attach(self.liloLocationBox, 0, 2, 1, 2)

	choices = fsset.bootloaderChoices(diskSet)
	if choices:
	    radio = None
	    count = 0
	    for (device, desc) in choices:
		radio = GtkRadioButton(radio,  
				("/dev/%s %s" % (device, _(desc))))
		self.radioBox.attach(radio, 1, 2, count + 2, count + 3)
		self.bootDevice[radio] = device

		if bl.getDevice() == device:
		    radio.set_active(1)

		count = count + 1

        label = GtkLabel(_("Kernel Parameters") + ":")
        label.set_alignment(0.0, 0.5)
        self.appendEntry = GtkEntry()
        if bl.args.get():
            self.appendEntry.set_text(bl.args.get())
        box = GtkHBox(FALSE, 5)
        box.pack_start(label)
        box.pack_start(self.appendEntry)
        alignment = GtkAlignment()
        alignment.set(0.0, 0.5, 0, 1.0)
        alignment.add(box)
        self.lba = GtkCheckButton(_("Force use of LBA32 (not normally required)"))
        self.lba.set_active(self.bl.forceLBA32)
        vbox = GtkVBox(FALSE, 5)
        vbox.pack_start(alignment)
        vbox.pack_end(self.lba)
        self.radioBox.attach(vbox, 0, 2, 5, 6)
        
        box = GtkVBox (FALSE, 0)
# CJS the 2.4.18-5 errata kernel breaks the installation of grub.  So I am
# changing the default to be LILO
# 
#       label = GtkLabel(_("Please select the boot loader that the computer will use.  GRUB is the default boot loader. "
#                          "However, if you do not wish to overwrite your current boot loader, "
#                          "select \"Do not install a boot loader.\"  "))
        label = GtkLabel(_("Please select the boot loader that the computer will use.  LILO is the default boot loader. "
                           "However, if you do not wish to overwrite your current boot loader, "
                           "select \"Do not install a boot loader.\"  "))
        label.set_usize(400, -1)
        label.set_line_wrap(TRUE)
        label.set_alignment(0.0, 0.0)
        self.editBox = GtkVBox ()
        self.imageList = GtkCList (4, ( _("Default"), _("Device"),
                                        _("Partition type"), _("Boot label")))
        self.sw = GtkScrolledWindow ()

                           
        self.grub_radio = GtkRadioButton(None, (_("Use GRUB as the boot loader")))
        self.lilo_radio = GtkRadioButton(self.grub_radio, (_("Use LILO as the boot loader")))
        self.none_radio = GtkRadioButton(self.grub_radio, (_("Do not install a boot loader")))


        self.lilo_radio.connect("toggled", self.bootloaderchange)
        self.grub_radio.connect("toggled", self.bootloaderchange)
        self.none_radio.connect("toggled", self.toggled)

 	if not dispatch.stepInSkipList("instbootloader"):
 	    self.none_radio.set_active (FALSE)
 	else:
             self.none_radio.set_active (TRUE)
             self.toggled (self.none_radio)

             for n in (self.appendEntry, self.editBox, 
                       self.imageList, self.liloLocationBox, self.radioBox ):
                 n.set_sensitive (FALSE)

        self.lastselected = None

        self.radio_vbox = GtkVBox(FALSE, 2)
        self.radio_vbox.set_border_width(5)
        self.radio_vbox.pack_start(label, FALSE)
# CJS just switched the order of these
#       self.radio_vbox.pack_start(self.grub_radio, FALSE)
        self.radio_vbox.pack_start(self.lilo_radio, FALSE)
        self.radio_vbox.pack_start(self.grub_radio, FALSE)
# CJS end of switch
        self.radio_vbox.pack_start(self.none_radio, FALSE)
        
        box.pack_start(self.radio_vbox, FALSE)

        box.pack_start (GtkHSeparator (), FALSE)
        box.pack_start (self.radioBox, FALSE)
        
        sortedKeys = imageList.keys()
        sortedKeys.sort()
        self.numImages = len(sortedKeys)

        if not bl.useGrub():
            self.lilo_radio.set_active(1)
            self.lastselected = "lilo"
        else:
            self.grub_radio.set_active(1)
            self.lastselected = "grub"
                
        self.default = None
        self.count = 0
        self.types = []
        self.oldLabels = []
        for n in sortedKeys:
            (label, longlabel, type) = imageList[n]
            self.types.append(type)
            if label == None:
                label = ""
            if longlabel == None:
                longlabel = ""
            if self.lastselected == "lilo":
                row = ("", "/dev/" + n, self.typeName(type), label)
                self.oldLabels.append(longlabel)
            else:
                row = ("", "/dev/" + n, self.typeName(type), longlabel)
                self.oldLabels.append(label)
            self.imageList.append(row)

            if (n == defaultDevice):
                self.default = self.count
                self.imageList.set_pixmap(self.count, 0, self.checkMark)
            else:
                self.imageList.set_pixmap(self.count, 0, self.checkMark_Off)
            self.count = self.count + 1

        self.imageList.columns_autosize ()
        self.imageList.column_title_passive (1)
        self.imageList.set_border_width (5)

        self.deviceLabel = GtkLabel(_("Partition") + ":")
        self.typeLabel = GtkLabel(_("Type") + ":")

        tempBox = GtkHBox(TRUE)
        self.deviceLabel.set_alignment(0.0, 0.0)
        self.typeLabel.set_alignment(0.0, 0.0)
        tempBox.pack_start(self.deviceLabel, FALSE)
        tempBox.pack_start(self.typeLabel, FALSE)
        self.defaultCheck = GtkCheckButton(_("Default boot image"))

        # Alliteration!
        self.labelLabel = GtkLabel(_("Boot label") + ":")
        self.labelEntry = GtkEntry(32)

        self.imageList.connect("select_row", self.labelSelected)
        self.defaultCheck.connect("toggled", self.defaultUpdated)
        self.labelEntry.connect("changed", self.labelUpdated)
        self.labelEntry.connect("insert_text", self.labelInsertText)

        tempBox2 = GtkHBox(FALSE, 5)
        self.labelLabel.set_alignment(0.0, 0.5)
        tempBox2.pack_start(self.labelLabel, FALSE)
        tempBox2.pack_start(self.labelEntry, FALSE)

        self.editBox.pack_start (tempBox, FALSE)
        self.editBox.pack_start (self.defaultCheck, FALSE)
        self.editBox.pack_start (tempBox2, FALSE)
        self.editBox.set_border_width (5)

        box.pack_start (GtkHSeparator (), FALSE)
        box.pack_start (self.editBox, FALSE)

        self.imageList.set_selection_mode (SELECTION_BROWSE)

        self.sw.set_policy (POLICY_AUTOMATIC, POLICY_AUTOMATIC)
        self.sw.add (self.imageList)
        box.pack_start (self.sw, TRUE)

	if not dispatch.stepInSkipList("instbootloader"):
            self.editBox.set_sensitive(TRUE)
            tempBox2.set_sensitive(TRUE)
            self.radioBox.set_sensitive(TRUE)
            self.sw.set_sensitive(TRUE)
        else:
            self.editBox.set_sensitive(FALSE)
            self.radioBox.set_sensitive(FALSE)
            self.sw.set_sensitive(FALSE)
            
        self.ignoreSignals = 0

        return box
