from Tkinter import *
import Tkinter
from listbox import *
from rhtkinter import *
from buttonbar import *

import rhdialog
import regex
import string
import fstab
import os

ext2PartTypes = [ '83' ]
swapPartTypes = [ '82' ]
dosPartTypes = [ '1', '4', '6']
hpfsPartTypes = [ '7' ]

idToTypeMap = {}
idToTypeMap[ '1'] = 'msdos'
idToTypeMap[ '4'] = 'msdos'
idToTypeMap[ '6'] = 'msdos'
idToTypeMap[ '7'] = 'hpfs'
idToTypeMap['82'] = 'swap'
idToTypeMap['83'] = 'ext2'

finalfstab = fstab.Fstab()

importantParts = [ '/', '/usr', '/var', '/dev', '/bin', '/sbin', '/tmp'
		   '/usr/bin', '/usr/tmp', '/var/tmp', '/usr/spool', 
		   '/var/spool', '/usr/X11R6' ]

useablePartTypes = ext2PartTypes + swapPartTypes + dosPartTypes + hpfsPartTypes

class EditMountPointDialog(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' : 'Mount point:' } )
	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):
	where = self.Field.get()
	if (self.checkMethod(self.Device.get(), where, self)):
	    self.doneMethod(1, self.Device.get(), where)
	    self.Master.destroy()

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

    def __init__(self, Device, Id, CurrentPoint, DoneMethod, CheckMethod, 
		 Master = None):
	Frame.__init__(self, Master)
	self.doneMethod = DoneMethod
	self.checkMethod = CheckMethod
	self.Master = Master;
	Master.title("Mount Point")
	self.createWidgets()
	self.id = Id
	self.Device.insert("0", Device)
	self.Device['state'] = 'disabled'
	self.Field.insert("0", CurrentPoint)
	self.pack()

class PartitionWindow(RHFrame):

    def edit(self, e = None):
	selection = self.list.curselection()
	(num, ) = selection
	(device, size, id, type, mntpoint) = self.list.getItems(atoi(num))

	if (self.editing.has_key(device)):
	    return
	self.editing[device] = 1;
	editbox = EditMountPointDialog(device, id, mntpoint, self.editDone, 
					self.checkMountPoint, Toplevel())
 
    def checkMountPoint(self, device, mntpoint, win):
	if (len(mntpoint) == 0):
	    return 1

	if (regex.match("^/[A-Za-z0-9/]*$", mntpoint) == -1):
	    rhdialog.error(mntpoint + ' is not a valid mount point')
	    return 0
	elif (importantParts.count(mntpoint) and not ext2PartTypes.count(win.id)):
	    rhdialog.error('The ' + mntpoint + ' must be a Linux native ' +
			   'partition')
	    return 0
	else:
	    items = self.list.getAllItems()
	    for tuple in items:
		(odevice, osize, oid, otypename, omntpoint) = tuple
		if (device != odevice and mntpoint == omntpoint):
		    rhdialog.error('Only one device may be mounted as ' +
				    mntpoint)
		    return 0

	return 1

    def editDone(self, keep, device, newValue):
	if (keep):
	    self.list.changeField(self.deviceLookup[device], 4, newValue)
	del self.editing[device]

    def createWidgets(self, partList, root):
	self.list = MultifieldListbox(self, [ ('Device', 10, 0), 
			('Size (in K)', 15, 0), ('Id', 2, 0),
			('Type', 15, 0), ('Mount Point', 20, 0) ] )

	num = 0
	for part in partList:
	    (device, blocks, id, type) = part
	    if (useablePartTypes.count(id) and not swapPartTypes.count(id)):
		self.deviceLookup[device] = num
		self.devList.append(part)
		if (root == device):
		    self.list.addItems([ (device, blocks, id, type, "/"), ])
		else:
		    self.list.addItems([ (device, blocks, id, type, ""), ])
		num = num + 1

	self.list.pack({ 'expand' : 1, 'fill' : 'both' })
	self.list.bind('<Double-1>', self.edit)

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

    def done(self):
	global finalfstab

	if (len(self.editing.keys())):
	    return

	mnttable = fstab.Fstab()
	items = self.list.getAllItems()
	for tuple in items:
	    (device, size, id, typename, mntpoint) = tuple
	    if (mntpoint == '/'):
		mnttable.addMount(device, mntpoint, idToTypeMap[id],
				  "defaults", 1, 1)
	    elif (len(mntpoint)):
		mnttable.addMount(device, mntpoint, idToTypeMap[id],
				  "defaults", 1, 2)

	if (mnttable.findMountByPoint('/') == None):
	    rhdialog.error("You must select a root (/) partition")
	else:
	    finalfstab = mnttable
	    self.quit()

    def clear(self):
	selection = self.list.curselection()
	if (len(selection)):
	    self.list.changeField(string.atoi(selection[0]), 4, "")

    def __init__(self, partList, root, Master = None):
	RHFrame.__init__(self, Master)

	self.deviceLookup = {}
	self.pack({ 'expand' : '1', 'fill' : 'both' })
	self.editing = {}
	self.devList = []
	self.createWidgets(partList, root)
	self.partList = partList
	if (Master):
	    Master.title("Mount Table")

class RootPartitionWindow(RHFrame):

    def createWidgets(self, partList):
	self.message = Message(self, { 'text' : "The root partition forms " +
		"the base of your Linux filesystem. It holds everything " +
	 	"necessary for starting your system. Which partition would " +
		"you like to use for the root filesystem?", 
		'aspect' : '400' } )
	self.message.pack()

	self.list = MultifieldListbox(self, [ ('Device', 10, 0),
					      ( 'Size (in K)', 15, 0) ] )
	self.list.bind('<Double-1>', self.done)
	
	for part in partList:
	    (device, blocks, id, type) = part
	    if (ext2PartTypes.count(id)):
		self.list.addItems([ (device, blocks) ])
	self.list.pack({ 'expand' : '1', 'fill' : 'both' })

	self.buttons = ButtonBar(self)
	self.buttons.addButton("Done", self.done)
	self.buttons.pack()

    def done(self, e = None):
	selection = self.list.curselection()
	if (not len(selection)):
	    return

	(num,) = selection
        (self.root, blocks) = self.list.getItems(atoi(num))
	self.quit()
   
    def __init__(self, partList):
	num = 0
	for part in partList:
	    (device, blocks, id, type) = part
	    if (ext2PartTypes.count(id)):
		num = num + 1
		which = device

	if (num == 1):
	    self.root = which
	else:
	    self.master = Toplevel()
	    RHFrame.__init__(self, self.master)
	    self.createWidgets(partList)
	    self.pack({ 'expand' : '1', 'fill' : 'both' })
	    self.master.title("Root Partition")

	    self.update()
	    self.grab_set()
	    self.wait_window(self)

def setupFstab(partList):
    if (os.path.exists("/bootdisk/defaults/fstab")):
	pass

    win = RootPartitionWindow(partList)
    root = win.root

    num = 0
    for part in partList:
	(device, blocks, id, type) = part
	if (useablePartTypes.count(id) and not swapPartTypes.count(id)):
	    num = num + 1
	    dev = device
	    mntinfo = part

    if (num != 1 or dev != root):
	win = PartitionWindow(partList, root, Toplevel())
	win.update()
	win.wait_window(win)
    else:
	finalfstab.addMount(root, "/", "ext2", "defaults", 1, 1)
	rhdialog.message("You only have one mountable partition, " + root +
		         ", so I'm using that for your root partition.")
    
    # add in the swap paritions, which we get from /tmp/swap
    if (os.path.exists("/tmp/swap")):
	swaps = open("/tmp/swap", "r")
	line = swaps.readline()
	while (line):
	    line = line[0:len(line) - 1]   # chop
	    if (len(line)):
		finalfstab.addSwap(line)
	    line = swaps.readline()

    return finalfstab
