from Tkinter import *
from rhtkinter import *
from package import *
from packageset import *
from buttonbar import *
from listbox import *
from rhdialog import *
from scale import Scale
from rhutil import rhrun
from time import *
import string
import regex

class InstallingWindow(RHFrame):

    def createWidgets(self):
	self.textFrame = Frame(self)

	self.leftLabels = Frame(self.textFrame)
	self.total = Frame(self.textFrame)
	self.done = Frame(self.textFrame)
	self.left = Frame(self.textFrame)

	self.leftLabels.time = Label(self.leftLabels, { 'text' : 'Time',
						'anchor' : 'w' } )
	self.leftLabels.time.pack({ 'side' : 'bottom', 'anchor' : 'w'})
	self.leftLabels.bytes = Label(self.leftLabels, { 'text' : 'kbytes',
						'anchor' : 'w' } )
	self.leftLabels.bytes.pack({ 'side' : 'bottom', 'anchor' : 'w'})
	self.leftLabels.packs = Label(self.leftLabels, { 'text' : 'Packages',
						'anchor' : 'w' } )
	self.leftLabels.packs.pack({ 'side' : 'bottom', 'anchor' : 'w'})
	self.leftLabels.pack({ 'side' : 'left', 'anchor' : 's'})

	self.total.time = Label(self.total, { 'text' : '??:??:??',
						'anchor' : 'e' } )
	self.total.time.pack({ 'side' : 'bottom', 'anchor' : 'e'})
	self.total.bytes = Label(self.total, { 'text' : "%d" % 
						   (self.totalSize / 1024),
						'anchor' : 'e' } )
	self.total.bytes.pack({ 'side' : 'bottom', 'anchor' : 'e'})
	self.total.packs = Label(self.total, { 'text' : "%d" % self.numPackages,
						'anchor' : 'e' } )
	self.total.packs.pack({ 'side' : 'bottom', 'anchor' : 'e'})
	self.total.label = Label(self.total, { 'text' : 'Total' } )
	self.total.label.pack({ 'side' : 'bottom' })
	self.total.pack({ 'side' : 'left', 'anchor' : 's'})

	self.done.time = Label(self.done, { 'text' : '00:00:00',
						'anchor' : 'e' } )
	self.done.time.pack({ 'side' : 'bottom', 'anchor' : 'e'})
	self.done.bytes = Label(self.done, { 'text' : '0', 'anchor' : 'e' } )
	self.done.bytes.pack({ 'side' : 'bottom', 'anchor' : 'e'})
	self.done.packs = Label(self.done, { 'text' : '0', 'anchor' : 'e' } )
	self.done.packs.pack({ 'side' : 'bottom', 'anchor' : 'e'})
	self.done.label = Label(self.done, { 'text' : 'Finished' } )
	self.done.label.pack({ 'side' : 'bottom' })
	self.done.pack({ 'side' : 'left', 'anchor' : 's', 'fill' : 'x'})

	self.left.time = Label(self.left, { 'text' : '??:??:??',
						'anchor' : 'e' } )
	self.left.time.pack({ 'side' : 'bottom', 'anchor' : 'e'})
	self.left.bytes = Label(self.left, { 'text' : "%d" %
						   (self.totalSize / 1024),
						'anchor' : 'e' } )
	self.left.bytes.pack({ 'side' : 'bottom', 'anchor' : 'e'})
	self.left.packs = Label(self.left, { 'text' : "%d" % self.numPackages,
						'anchor' : 'e' } )
	self.left.packs.pack({ 'side' : 'bottom', 'anchor' : 'e'})
	self.left.label = Label(self.left, { 'text' : 'Remaining' } )
	self.left.label.pack({ 'side' : 'bottom' })
	self.left.pack({ 'side' : 'left', 'anchor' : 's', 'fill' : 'x'})

	#self.textFrame.pack({ 'expand' : '1', 'fill' : 'x' })
	self.textFrame.pack()

	self.pkgScale = Scale(300, 50, 100, self)
	self.pkgScale.pack()
	self.totalScale = Scale(400, 50, self.totalSize, self)
	self.totalScale.pack()

	self.pack()

    def setPackageScale(self, percent):
	self.pkgScale.set(percent)
	self.update()

    def setAmountInstalled(self, size):
	self.totalScale.set(size)
	self.done.bytes['text'] = "%d" % (int(size) / 1024)
	self.left.bytes['text'] = "%d" % ((self.totalSize - int(size)) / 1024)
	self.bytesInstalled = size
	self.updateTime()
	self.update()

    def formatTime(self, secs):
	hours = int(secs / 3600);
	secs = secs % 3600;
	minutes = int(secs / 60);
	secs = secs % 60;

	return (string.zfill("%d" % hours, 2) + ":" +
		string.zfill("%d" % minutes, 2) + ":" + 
		string.zfill("%d" % secs, 2))

    def updateTime(self):
	multipleLeft = (self.totalSize * 1.0) / self.bytesInstalled;
	timeSpent = int(time()) - self.startTime;
	totalTime = int(timeSpent * multipleLeft);
	timeLeft = totalTime - timeSpent
	
	self.done.time['text'] = self.formatTime(timeSpent)
	self.left.time['text'] = self.formatTime(timeLeft)
	self.total.time['text'] = self.formatTime(totalTime)

    def setNumPackages(self, num):
	self.done.packs['text'] = num
	self.left.packs['text'] = self.numPackages - num

    def setFile(self, file):
	self.pkgScale.setLabel(file)

    def __init__(self, numPackages, totalSize, Master = None):
	RHFrame.__init__(self, Master)
	self.totalSize = totalSize;
	self.numPackages = numPackages;
	self.createWidgets()
	self.startTime = int(time())

	if (Master):
	    Master.title("Installing")

class State:
    def set(self, val):
	self.val = val

    def get(self):
	return self.val


splitlabel = regex.compile("(.*):(.*):(.*)")

def installProgress(args, line):
    # if it's not from --percent, and it's on stdout, ignore it
    if (line[0] != "%"): return

    (win, state, sizes) = args
    (currfile, total, numPackages) = state.get()

    code = line[1]
    arg = line[3:]
    
    if (code == "%"):
	if (arg == "100"):
	    total = total + sizes[currfile]
	    numPackages = numPackages + 1
	    state.set((currfile, total, numPackages))
	    currfile = ""
	    win.setNumPackages(numPackages)
	else:
	    total = total + sizes[currfile] * ((string.atof(arg)) / 100)

	win.setPackageScale(string.atof(arg))
	win.setAmountInstalled(total)
    elif (code == "f"):
	currfile = arg
	state.set((currfile, total, numPackages))
	splitlabel.search(currfile)
	name = splitlabel.group(1)
	win.setFile("%s (%dkb)" % (name, sizes[currfile] / 1024))
	win.setPackageScale(0)

def InstallPackages(packages, root, test):
    totalsize = 0

    rpmargs = ( "--percent", "--force", "-i")
    if (root):
	rpmargs = rpmargs + ("--root", root)
    totalsize = 0
    sizes = {}
    for p in packages:
	rpmargs = rpmargs + ( p.getPath(), )
	totalsize = totalsize + p.getSize()
	sizes[p.getLabel()] = p.getSize()

    win = InstallingWindow(len(packages), totalsize, Toplevel())
    win.update()
    win.grab_set()

    state = State()
    state.set((0, 0, 0))
    (code, out, err) = rhrun("/usr/bin/rpm", rpmargs, 
		(installProgress, (win, state, sizes)), test)

    win.setAmountInstalled(totalsize)

    win.quit()

    # now display a window with any errors that occured
    # this should be nicer
    # if (len(err)):
	# scrolledMessageDialog("Errors occured during the install", err) 
	# sys.stderr.write(err)

def DoInstall(pset, root = None, test = 0):
    packages = pset.getPackages()

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

    InstallPackages(packages, root, test)
