from Tkinter import *
import Tkinter
from parttable import *
from listbox import *
from rhtkinter import *
from buttonbar import *
from rhutil import *
import rhdialog

class LiloWhereWindow(RHFrame):

    def createWidgets(self, rootPart):
	self.message = Message(self, 
		{ 'text' : 'Where do you want to install LILO?', 
		  'aspect' : '10000' })
	self.message.pack()

	self.where = StringVar()

	devfile = open("/proc/devices")
	line = devfile.readline()
	inblocks = 0
	default = None
	while (line):
	    if (inblocks):
		if (line[0:2] == " 3"): 
		    r = Radiobutton(self, { 'value' : '/dev/hda', 
			    'variable' : self.where,
			    'text' : 'On the MBR if /dev/hda ' + 
				     '(the first IDE hard drive)' } )
		    r.pack({ 'anchor' : 'w' })
		    default = '/dev/hda'
		if (line[0:2] == " 8"): 
		    if (not default):
			r = Radiobutton(self, { 'value' : '/dev/sda', 
				'variable' : self.where,
				'text' : 'On the MBR if /dev/sda ' + 
					 '(the first SCSI hard drive)' } )
			r.pack({ 'anchor' : 'w' })
		        default = '/dev/sda'
		
	    if (line[0:13] == "Block devices"):
		inblocks = 1
	    line = devfile.readline()
	devfile.close()

	if (default):
	    self.where.set(default)
	else:
	    self.where.set("/dev/fd0")

	r = Radiobutton(self, { 'value' : '/dev/fd0', 'variable' : self.where,
		'text' : 'On a floppy in /dev/fd0 (Drive A:)' } )
	r.pack({ 'anchor' : 'w' })
	r = Radiobutton(self, { 'value' : rootPart, 'variable' : self.where,
		'text' : 'On the superblock of ' + rootPart + 
			', your root Linux partition' })
	r.pack({ 'anchor' : 'w' })

	buttons = ButtonBar(self)
	buttons.addButton( 'Ok', self.okay)
	buttons.addButton( 'Cancel', self.cancel)
	buttons.pack({ 'fill' : 'x'})

    def okay(self):
	self.final = self.where.get()
	self.quit()
 
    def cancel(self):
	self.quit()

    def __init__(self, rootPart, Master = None):
	RHFrame.__init__(self, Master)
	self.createWidgets(rootPart)
	self.pack({ 'expand' : '1', 'fill' : 'both' })
	self.final = None
	if (Master):
	    Master.title("Lilo Installation")

class LiloGetAppendWindow(RHFrame):

    def createWidgets(self):
	self.message = Message(self, {
		  'text' : 
			"Enter the parameters below (ex: hd=64,32,202). "
			"This will be added as an append line to your "
			"LILO configuration.", 'aspect' : '600' })
	self.message.pack()

	self.entry = RHEntry(self, { 'relief' : 'sunken' } )
	self.entry.pack({ 'fill' : 'x' })
	self.entry.focus_set()
	self.entry.bind('<Return>', self.okay)

	buttons = ButtonBar(self)
	buttons.addButton( 'Ok', self.okay)
	buttons.addButton( 'Cancel', self.cancel)
	buttons.pack({ 'fill' : 'x'})

    def okay(self, e = None):
	self.appends = self.entry.get()
	if (not len(self.appends)): return
	self.quit()

    def cancel(self):
	self.appends = None
	self.quit()

    def __init__(self, Master = None):
	RHFrame.__init__(self, Master)
	self.createWidgets()
	self.pack({ 'expand' : '1', 'fill' : 'x' })
	self.append = None
	if (Master):
	    Master.title("Kernel Parameters")

class LiloConfirmWindow(RHFrame):

    def createWidgets(self, text):
	l = Label(self, { 'text' : "Here's the lilo.conf I'll use:",
			  'anchor' : 'w' } )
	l.pack({ 'anchor' : 'w' })

	f = Frame(self)
	
	l = Listbox(f, { 'width' : '30' } )
	hs = Scrollbar(f, { 'command' : l.xview, 'orient' : 'horiz' } )
	hs.pack({ 'side' : 'bottom', 'fill' : 'x' })
	for line in text:
	    if (line[0] == "\t"):
		line = "        " + line[1:]
	    l.insert('end', line)
	vs = Scrollbar(f, { 'command' : l.yview } )
	l['yscrollcommand'] = vs.set
	l['xscrollcommand'] = hs.set
	l.pack({ 'side' : 'left', 'expand' : '1', 'fill' : 'both' })
	vs.pack({ 'side' : 'left', 'fill' : 'y' })
	f.pack({ 'expand' : '1', 'fill' : 'both' })

	l = Label(self, { 'text' : 
			"What should I do with this lilo configuration?",
			  'anchor' : 'w' } )

	l.pack({ 'anchor' : 'w' })
	buttons = ButtonBar(self)
	buttons.addButton( 'Install', self.install)
	buttons.addButton( 'Start over', self.restart)
	buttons.addButton( 'Cancel', self.cancel)
	buttons.pack({ 'fill' : 'x'})

    def install(self):
	self.result = "install"
	self.quit()

    def restart(self):
	self.result = "restart"
	self.quit()

    def cancel(self):
	self.result = "cancel"
	self.quit()

    def __init__(self, text, Master = None):
	RHFrame.__init__(self, Master)
	self.createWidgets(text)
	self.pack({ 'fill' : 'both', 'expand' : '1' })
	self.append = None
	if (Master):
	    Master.title("Lilo Confirmation")

class LiloAskAppendWindow(RHFrame):

    def createWidgets(self, default):
	self.message = Message(self, {
		  'text' : 
	               "If you needed to specify hardware parameters on the " +
                       "LILO command line to boot the install disk, you will" +
                       " need to add some information to your lilo " +
		       "configuration.",
		  'aspect' : '600' })
	self.message.pack()

	label = Label(self, { 'anchor' : 'w', 'text' :
			"Do you need to specify hardware parameters?" } )
	label.pack({ 'anchor' : 'w' })

	self.hasappends = StringVar()
	if (default):
	    self.hasappends.set("Yes")
	else:
	    self.hasappends.set("No")
	f = Frame(self)
	r = Radiobutton(f, { 'value' : 'Yes', 'variable' : self.hasappends,
		'text' : 'Yes' } )
	r.pack({ 'anchor' : 'w' })
	r = Radiobutton(f, { 'value' : 'No', 'variable' : self.hasappends,
		'text' : 'No' } )
	r.pack({ 'anchor' : 'w' })
	f.pack()

	buttons = ButtonBar(self)
	buttons.addButton( 'Ok', self.okay)
	buttons.addButton( 'Cancel', self.cancel)
	buttons.pack({ 'fill' : 'x'})

    def okay(self):
	self.canceled = 0
	if (self.hasappends.get() == "Yes"):
	    self.doappend = 1
	else:
	    self.doappend = 0
	self.quit()

    def cancel(self):
	self.canceled = 1
	self.quit()

    def wasCanceled(self):
	return self.canceled

    def __init__(self, default, Master = None):
	RHFrame.__init__(self, Master)
	self.createWidgets(default)
	self.pack()
	self.append = None
	if (Master):
	    Master.title("Kernel Parameters")

class LiloGetOtherOSWin(RHFrame):

    def createWidgets(self, fstab, partList, otheros):
	self.message = Message(self, {
		  'text' : 
	               "The LILO boot manager Red Hat uses can boot other" +
		       "operating systems as well. You need to tell me" +
		       "what partitions you would like to be able to boot" +
		       "and what label you want to use for each of them",
		  'aspect' : '800' })
	self.message.pack()

	self.list = MultifieldListbox(self, [ ( 'Device', 15, 0), 
					      ( 'Size (k)', 15, 0),
					      ( 'Type', 15, 0),
					      ( 'Boot Label', 10, 0) ])
	self.list.pack({ 'expand' : 1, 'fill' : 'both' })
	self.list.bind('<Double-1>', self.edit)
	dos = 0
	count = 0
	self.deviceLookup = {}
	for part in partList:
	    (device, blocks, id, type) = part
	    if ((not fstab.deviceGetsMounted(device) or id != '83') 
		and id != '5' and id != '82'):   # don't list "Linux Swap"
		# automatically select the first DOS partition to boot
		if (otheros):
		    if (otheros.has_key(device)):
			self.list.addItems([ (device, blocks, type, 
						otheros[device])])
		    else:
			self.list.addItems([ (device, blocks, type, '')])
		else:
		    if (not dos and (type[0:3] == "DOS")):
			dos = 1
			self.list.addItems([ (device, blocks, type, 'dos')])
		    else:
			self.list.addItems([ (device, blocks, type, '')])
		self.deviceLookup[device] = count
		count = count + 1

	self.buttons = ButtonBar(self)
	self.buttons.addButton("Edit", self.edit)
	self.buttons.addButton("Clear", self.clear)
	self.buttons.addButton("Cancel", self.cancel)
	self.buttons.addButton("Done", self.done)
	self.buttons.pack({ 'fill' : 'x' })

    def cancel(self):
	self.canceled = 1
	self.quit()

    def done(self):
	self.canceled = 0
	self.others = {}
	items = self.list.getAllItems()
	for tuple in items:
	    (device, size, type, label) = tuple
	    if (len(label)):
		self.others[device] = (type, label)
	self.quit()

    def clear(self):
	selection = self.list.curselection()
	if (len(selection)):
	    self.list.changeField(string.atoi(selection[0]), 3, "")
		
    def edit(self, e = None):
	selection = self.list.curselection()
	(num, ) = selection
	(device, blocks, type, label) = self.list.getItems(atoi(num))

	if (self.editing.has_key(device)):
	    return
	self.editing[device] = 1;
	editbox = EditBootLabel(device, label, self.editDone, self.checkLabel, 
				Toplevel())

    def checkLabel(self, device, label):
	if (len(label) == 0):
	    return 1

	if (regex.match("^[A-Za-z0-9\.]*$", label) == -1):
	    rhdialog.error(label + ' is not a valid boot label')
	    return 0
	elif (label == "linux"):
	    rhdialog.error('The linux partition you just installed' +
			    ' is called linux. Pick something else')
	    return 0
	else:
	    items = self.list.getAllItems()
	    for tuple in items:
		(odevice, osize, otype, olabel) = tuple
		if (device != odevice and label == olabel):
		    rhdialog.error('Only one device may be called ' +
				    label)
		    return 0

	return 1

    def editDone(self, keep, device, newValue):
	if (keep):
	    self.list.changeField(self.deviceLookup[device], 3, newValue)
	del self.editing[device]
	
    def wasCanceled(self):
	return self.canceled

    def getOthers(self):
	return self.others

    def __init__(self, fstab, partList, otheros):
	foundOne = 0
	for part in partList:
	    (device, blocks, id, type) = part
	    if ((not fstab.deviceGetsMounted(device) or id != '83') 
		and id != '5' and id != '82'):   # don't list "Linux Swap"
		foundOne = 1
	if (not foundOne):
	    self.others = {}
	    self.canceled = 0
	else:
	    Master = Toplevel()
	    RHFrame.__init__(self, Master)
	    self.pack({ 'expand' : '1', 'fill' : 'both' })
	    self.editing = {}
	    self.canceled = 0
	    if (Master):
		Master.title("Other Operating Systems")
	    self.createWidgets(fstab, partList, otheros)
	    self.update()
	    self.wait_window()

class EditBootLabel(RHFrame):

    def createWidgets(self):

	self.topFrame = Frame(self)
	self.leftFrame = Frame(self.topFrame)
	self.rightFrame = Frame(self.topFrame)
	self.leftFrame.l1 = Label(self.leftFrame, { 'text' : 'Device:',
						    'anchor' : 'w' } )
	self.leftFrame.l2 = Label(self.leftFrame, { 'text' : 'Label :' } )
	self.leftFrame.l1.pack({ 'expand' : '1', 'fill' : 'both' } )
	self.leftFrame.l2.pack({ 'expand' : '1', 'fill' : 'both' } )

	self.device = RHEntry(self.rightFrame, { 'relief' : 'sunk',
					       'width' : '20' } )
	self.field = RHEntry(self.rightFrame, { 'relief' : 'sunk',
					      'width' : '20' } )
	self.device.pack()
	self.field.pack()
	self.field.focus_set()
	self.field.bind('<Return>', self.ok)

	self.leftFrame.pack({ 'side' : 'left'})
	self.rightFrame.pack({ 'side' : 'right'})
	
	self.topFrame.pack()
	
	self.buttons = ButtonBar(self)
	self.buttons.addButton("Ok", self.ok)
	self.buttons.addButton("Cancel", self.cancel)
	self.buttons.pack({ 'expand' : '1', 'fill' : 'both', 'pady' : '4' } )
 
    def ok(self, e = None):
	label = self.field.get()
	if (self.checkMethod(self.device.get(), label)):
	    self.doneMethod(1, self.device.get(), label)
	    self.Master.destroy()

    def cancel(self):
	self.doneMethod(0, self.device.get(), "")
	self.Master.destroy()

    def __init__(self, device, currentLabel, doneMethod, checkMethod, 
		 Master = None):
	Frame.__init__(self, Master)
	self.doneMethod = doneMethod
	self.checkMethod = checkMethod
	self.Master = Master;
	Master.title("Boot Label")
	self.createWidgets()
	self.device.insert("0", device)
	self.device['state'] = 'disabled'
	self.field.insert("0", currentLabel)
	self.pack()

def runLilo(root, rootPart, fstab, partList, test):

    stage = "where"
    getappends = 0
    appends = None
    where = None
    otheros = {}

    while (stage != "done"):
	if (stage == "where"):
	    win = LiloWhereWindow(rootPart, Toplevel())
	    win.update()
	    win.grab_set()
	    win.wait_window()
	    where = win.final
	    if (not where): return
	    stage = "askappend"
	elif (stage == "askappend"):
	    win = LiloAskAppendWindow(getappends, Toplevel())
	    win.update()
	    win.grab_set()
	    win.wait_window()
	    if (win.wasCanceled()):
		stage = "where"
	    else:
		getappends = win.doappend
		stage = "getappend"
	elif (stage == "getappend"):
	    if (not getappends):
		stage = "otheros"
	    else:
		win = LiloGetAppendWindow(Toplevel())
		win.update()
		win.grab_set()
		win.wait_window()
		appendline = win.appends
		if (appendline):
		    stage = "otheros"
		else:
		    stage = "askappend"
	elif (stage == "otheros"):
	    win = LiloGetOtherOSWin(fstab, partList, otheros)
	    if (win.wasCanceled()):
		stage = "askappend"
	    else:
		otheros = win.getOthers()
		stage = "confirm"
	elif (stage == "confirm"):
	    conf = []
	    conf.append("compact")
	    conf.append("boot=" + where)
	    conf.append("map=/boot/map")
	    conf.append("install=/boot/boot.b")
	    conf.append("prompt")
	    conf.append("timeout=100")
	    conf.append("image=/vmlinuz")
	    conf.append("\tlabel=linux")
	    conf.append("\troot=" + rootPart)
	    if (getappends):
		conf.append('\tappend="' + appendline + '"')
	    conf.append("\tread-only")

	    for device in otheros.keys():
		(type, label) = otheros[device]
		if (type == 'Linux native'):
		    conf.append("image=/vmlinuz")
		    conf.append("\tlabel=" + label)
		    conf.append("\troot=" + device)
		    if (getappends):
			conf.append('\tappend="' + appendline + '"')
		    conf.append("\tread-only")
		else:
		    conf.append("other=" + device)
		    conf.append("\tlabel=" + label)
		    conf.append("\ttable="+ device[0:8])

	    win = LiloConfirmWindow(conf, Toplevel())
	    win.update()
	    win.grab_set()
	    win.wait_window()
	    if (win.result == "restart"):
		where = None
		getappends = 0
		otheros = None
		appends = None
		stage = "where"
	    elif (win.result == "cancel"):
		return
	    else:
		stage = "done"
	else:
	    print "Unknown stage", stage
		
    if (test):
	conffile = open("/dev/tty", "w")
	print root + "/etc/lilo.conf follows:"
    else:
	conffile = open(root + "/etc/lilo.conf", "w")

    for line in conf:
	conffile.write(line + "\n")
    conffile.close()

