# 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 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):
	if (size != self.totalScale.get(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, title, numPackages, totalSize, Master = None):
	RHFrame.__init__(self, Master)
	self.totalSize = totalSize;
	self.numPackages = numPackages;
	self.createWidgets()
	self.startTime = int(time())

	if (Master):
	    Master.title(title)

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

    def get(self):
	return self.val


splitlabel = regex.compile("(.*):(.*):(.*)")
splitamount = regex.compile("^([0-9][0-9]*)")

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 (currfile != ""):
	    splitamount.search(arg)
	    arg = string.atof(splitamount.group(1))
	    if (arg == 100):
		total = total + sizes[currfile]
		numPackages = numPackages + 1
		currfile = ""
		state.set((currfile, total, numPackages))
		win.setNumPackages(numPackages)
	    else:
		total = total + sizes[currfile] * (arg / 100)

	    win.setPackageScale(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, upgrade, root, test):
    totalsize = 0

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

    if (test):
	print "args:", rpmargs

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

    state = State()
    state.set((0, 0, 0))
    (code, out, err) = rhrun("/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) 

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

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

    InstallPackages(packages, 1, root, test)
    

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, 0, root, test)
