# GLINT graphical package management
# Copyright (C) 1995 Red Hat, Inc
#
# 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; either version 2 of the License, or
# (at your option) any later version.
#
# 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 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., 675 Mass Ave, Cambridge, MA 02139, USA.

from Tkinter import *
from rhtkinter import *
from package import *
from packageset import *
from buttonbar import *
from listbox import *
from rhdialog import *
from rhutil import rhrun
from listbox import MultifieldListbox
import string
import regex
import os
import posixpath

regex.set_syntax(RE_SYNTAX_AWK)
md5output = regex.compile("([^ \t]*)[ \t]+(.*)")

class VerifyDetailsWindow(RHFrame):

    def createWidgets(self):
	f = Frame(self)
	lf = Frame(f)
	rf = Frame(f)

	l = Label(lf, { 'text' : 'File' } )
	l.pack({ 'anchor' : 'w' })
	l = Label(lf, { 'text' : 'Package' } )
	l.pack({ 'anchor' : 'w' })

	lf.pack({'side' : 'left', 'anchor' : 'w' })
	rf.pack({'side' : 'left', 'anchor' : 'w' })
	f.pack({ 'anchor' : 'w' })

	self.path = Label(rf)
	self.path.pack({ 'anchor' : 'w' })
	self.package = Label(rf)
	self.package.pack({ 'anchor' : 'w' })

	self.l = MultifieldListbox(self, [ ('Attribute', 15, 1),
				('Expected', 32, 1), ('Current', 32, 1) ] )
	self.l.pack({ 'expand' : '1', 'fill' : 'both' })

	b = ButtonBar(self)
	b.addButton('Close', self.close)
	b.pack()

	self.pack({ 'expand' : '1', 'fill' : 'both' })

    def close(self):
	self.closecb()
	self.quit()

    def setDetails(self, path, package, details):
	self.path['text'] = path
	self.package['text'] = package
	self._Master.title("Problems with " + package)
	self.l.addItems(details)

    def __init__(self, closecb, Master = None):
	RHFrame.__init__(self, Toplevel())
	self._Master.title("Problems")
	self.createWidgets()
	self.closecb = closecb

class VerifyStatusWindow(RHFrame):

    def createWidgets(self):
	self.l = MultifieldListbox(self, [ ( 'Package', 25, 1),
				           ( 'File', 35, 1),
				           ( 'Problem', 20, 1) ])
	self.l.pack({ 'expand' : '1', 'fill' : 'both' })
	self.finishedState = 0

	buttons = ButtonBar(self)
	buttons.addButton('Details', self.showDetails)
	buttons.addButton('Close', self.doClose)

	buttons.pack({ 'fill' : 'x' })

    def showDetails(self, e = None):
	sel = self.l.curselection()
	if not sel:
	    return
	(index, ) = sel
	index = string.atoi(index)

	if (self.finishedState):
	    (path, package, details) = self.info[index]
	    if (len(details)):
		win = VerifyDetailsWindow(self.verifyWinClosed)
		win = win.setDetails(path, package, details)
	
    def verifyWinClosed(self):
	pass

    def setFinishedState(self):
	self.l.bind('<Double-1>', self.showDetails)
	self.finishedState = 1

    def doClose(self):
	if (self.finishedState): self.quit()

    def addFile(self, packageName, file, problem, details):
	self.l.addItems([ ( packageName, file, problem ) ] )
	self.update()
	self.info.append((file, packageName, details))
	
    def delLastFile(self):
	self.l.delete('end')
	del self.info[len(self.info) - 1]

    def __init__(self, Master = None):
	RHFrame.__init__(self, Master)
	if (Master):
	    Master.title("Verify")
	self.createWidgets()
	self.pack({ 'fill' : 'both', 'expand' : '1' })
	self.itemnum = 0
	self.info = []
    
def VerifyPackage(package, win):
    label = package.getLabel()
    speci = package.getSpeci()    

    paths = ()
    md5sum = {}

    for file in speci.getFileEntries().values():
	if (file.getRdev() == '0' and file.getLink() == 'X'):
		paths = paths + (file.getName(), )

    if (len(paths)):
	(code, out, err) = rhrun("/usr/bin/md5sum", paths)
	for line in string.splitfields(out, "\n"):
	    if (md5output.search(line) != -1):
		(md5, path) = md5output.group(1, 2)
		md5sum[path] = md5

    for file in speci.getFileEntries().values():
	path = file.getName()
	details = []

	win.addFile(label, path, "(checking)", "")
	if (not os.path.exists(path)):
	    win.delLastFile()
	    win.addFile(label, path, "missing", "")
	    continue

	(mode, inode, dev, nlinks, uid, gid, size, atime, 
	    mtime, ctime) = os.lstat(path)

	problems = None
	if ("%o" % mode != file.getMode()):
	    problems = "mode"
	    details.append(('permissions', file.getMode(), "%o" % mode))

	# no way of getting device info from python!
	#print ("%x" % rdev, file.getRdev())
	#if ("%x" % rdev != file.getRdev()):
	    #problems = problems + "differnet device "

	if (not posixpath.isdir(path)):
	    if ("%d" % size != file.getSize()):
		details.append(('file size', file.getSize(), "%d" % size,))
		if (problems):
		    problems = problems + ", size"
		else:
		    problems = "size"

	if ("%d" % uid != file.getUid()):
	    details.append(('owner', file.getUid(), "%d" % uid))
	    if (problems):
		problems = problems + ", uid"
	    else:
		problems = "uid"
	if ("%d" % gid != file.getGid()):
	    details.append(('group', file.getGid(), "%d" % gid))
	    if (problems):
		problems = problems + ", gid"
	    else:
		problems = "gid"
	if (file.getMd5() != '0' and md5sum.has_key(file.getName())):
	    if (file.getMd5() != md5sum[file.getName()]):
		details.append(('checksum', file.getMd5(), 
						md5sum[file.getName()]))
		if (problems):
		    problems = problems + ", md5"
		else:
		    problems = "md5"
    
	win.delLastFile()
	if (problems):
	    win.addFile(label, path, problems, details)

def DoVerify(pset):
    packages = pset.getPackages()

    if (len(packages) == 0):
	error("No packages have been selected to install")
	return

    win = VerifyStatusWindow(Toplevel())
    win.update()
    
    for package in packages:
	VerifyPackage(package, win)

    win.setFinishedState()
    win.update()
    win.wait_window(win)

