#!/usr/bin/env python
import sys
import locale
import gobject
import pygtk
pygtk.require("2.0")
import gtk
import gtk.glade
import gnome
import gnome.ui
from os import path, spawnl, popen, system, P_NOWAIT, umask
from threading import Thread
from time import sleep
from select import select
from string import *
from socket import *
import errno
import re
import rpm
import os

debug = False

def debug_print(something):
	if debug:
		print something

def get_shared_path():
	testfile = 'version'
	sharedirs = [".",path.join(path.dirname(sys.argv[0]),"../share/rpmview")]
	sharepath = None
	for sharedir in sharedirs:
		fname = path.join(path.abspath(sharedir),testfile)
		if path.exists(fname):
			sharepath = path.abspath(sharedir)
			break
	
	if sharepath is None:
		raise Exception, "RPMView shared files " + testfile + " cannot be found in any of " + str(sharedirs) + " default paths"
	
	return sharepath

class AuxiliaryProgramNotFound(Exception):
	def __init__(self, value):
		self.value = value
	def __str__(self):
		return repr(self.value)

class NoBrowserError(AuxiliaryProgramNotFound):
	pass
	
class NoMailClientError(AuxiliaryProgramNotFound):
	pass

def get_full_path_to_program(program):
	possible_browsers = [program]
	for browser in possible_browsers:
		command = popen("LC_ALL=C which " + browser + " 2> /dev/null")
		r = command.readlines()
		command.close()
		if r:
			return strip(r[0])
	return None



def get_browser():
	possible_browsers = ["gnome-open","mozilla","firefox","konqueror"]
	for browser in possible_browsers:
		command = popen("LC_ALL=C which " + browser + " 2> /dev/null")
		r = command.readlines()
		command.close()
		if r:
			return strip(r[0])
	return None



def get_mail_client():
	possible_clients = ["gnome-open","evolution","kmail"]
	for client in possible_clients:
		command = popen("LC_ALL=C which " + client + " 2> /dev/null")
		r = command.readlines()
		command.close()
		if r:
			return strip(r[0])
	return None


def open_webpage(url):
	browser = get_browser()
	if browser is None:
		raise NoBrowserError, "No suitable browser found"
	system( browser + " '" + url + "'" )

def compose_mail(url):
	client = get_mail_client()
	if client is None:
		raise NoMailClientError, "No suitable mail client found"
	system( client  + " 'mailto:" + url + "'" )
	
met = 0
unmet = 1

OK = 0
changed = 1
permissions_changed = 2
deleted = 4
not_installed = 8

def dep_status_code_to_string(code):
	if code == met:
		return "met"
	if code == unmet:
		return "unmet"
	return "unknown"

def file_status_code_to_string(code):
	if code == OK:
		return "OK"
	if code == changed:
		return "changed"
	if code == permissions_changed:
		return "permissions changed"
	if code == deleted:
		return "deleted"
	if code == not_installed:
		return "not installed"
	return "unknown"

class RPMDependency:
	name = None
	status = unmet
	
	def __init__(self,name,status):
		self.name = name
		self.status = status

class RPMFile:
	filename = None
	status = OK
	
	def __init__(self,filename,status):
		self.filename = filename
		self.status = status

class RPMPackage:
	packagename = None
	version = None
	filename = None
	installedsize = None
	installed = False
	description = None
	source_package = False
	files = []
	dependencies = []

import commands
def shell_quote(s):
	d = "'" + s.replace("'","'\\''") + "'"
	return d
	
class RPMFileCorruptError(Exception):
	pass

class NotExistError(Exception):
	pass
	
def get_rpm_unerrored_output(command):
	output = commands.getoutput(command).strip()
	lines = output.splitlines()
	newlines = []
	for line in lines:
		if not line.startswith("warning"):
			newlines.append(line)
	newoutput = "\n".join(newlines)
	newoutput = newoutput.strip()
	return newoutput

def RPMPackageFromFile(filename):
	if not path.exists(filename):
		raise NotExistError

	olddir = os.getcwd()
	os.chdir(path.dirname(filename))
	filename = path.basename(filename)
	
	p = None
	p = RPMPackage()
	p.filename = filename

	command = "rpm -qp " + shell_quote(p.filename) + " --queryformat '%{description}'"
	p.description = get_rpm_unerrored_output(command).strip()
	command = "rpm -qp " + shell_quote(p.filename) + " --queryformat '%{name}'"
	p.packagename = get_rpm_unerrored_output(command).strip()
	command = "rpm -qp " + shell_quote(p.filename) + " --queryformat '%{version}'"
	p.version = get_rpm_unerrored_output(command).strip()
	command = "rpm -q " + shell_quote(p.packagename) + " --queryformat '%{version}'"
	inst = get_rpm_unerrored_output(command).strip()
	if (inst == p.version):
		p.installed = True
	command = "rpm -qp " + shell_quote(p.filename) + " --queryformat '%{size}'"
	installedsize = get_rpm_unerrored_output(command).strip()
	p.installedsize = int(installedsize)/1024
	command = "rpm -qpl " + shell_quote(p.filename) + ""
	filelist = get_rpm_unerrored_output(command).strip().split()
	installedfilelist = None
	if p.installed is True:
		defaultstatus = OK
		command = "rpm -V " + shell_quote(p.packagename + "-" + p.version)
		prelimfilelist = get_rpm_unerrored_output(command).splitlines()
		installedfilelist = []
		for a in prelimfilelist:
			tupl = a.split("    ",2)
			tupl[1] = tupl[1].strip()
			installedfilelist.append( tupl ) 
		print installedfilelist
	else:
		defaultstatus = not_installed
	for e in filelist:
		if e:
			status = defaultstatus
			if installedfilelist is not None:
				for a in installedfilelist:
					if e == a[1]:
						if a[0].find("5") != -1:
							status = changed
						elif a[0].find("M") != -1:
							status = permissions_changed
						elif a[0].find("missing") != -1:
							status = deleted
						break
			p.files.append(RPMFile(e,status))
	command = "rpm -qp --queryformat '%{source}' " + shell_quote(p.filename) + ""
	source_package = get_rpm_unerrored_output(command).strip()
	if source_package != "(none)":
		p.source_package = True
	
	command = "rpm -qp --requires " + shell_quote(p.filename) + ""
	deplist = get_rpm_unerrored_output(command).strip().splitlines()
	for e in deplist:
		if e:
			p.dependencies.append(RPMDependency(e,32))
	
	os.chdir(olddir)
	return p

def install_rpm(rpmfilename):
	olddir = os.getcwd()
	os.chdir(path.dirname(rpmfilename))
	filename = path.basename(rpmfilename)
	
	command = "system-install-packages " + shell_quote(filename)
	debug_print ("Executing " + command)
	output = commands.getoutput(command).strip()
	debug_print (output)

	os.chdir(olddir)


class RPMView (gtk.glade.XML):
	window = None
	rpmfile = None
	
	def __init__ (self,sharepath,rpmfile):
		self.sharepath = sharepath
		self.rpmfile = os.path.abspath(rpmfile)
		gtk.glade.XML.__init__(self,path.join(self.sharepath,'rpmview.glade'))
		self.window = self.get_widget("window")
		self.prepare_widgets()
		self.connect_signals()
		self.display_file()
		#Si es archivo
		#do something
		#si es package name
		#do something
		
	def display_file(self):
		try:
			i = RPMPackageFromFile(self.rpmfile)
			self.display_rpm_info(i)
		except NotExistError:
			self.get_widget("error_dialog").connect("delete_event",self.exit_with_value,2)
			self.get_widget("error_dismiss").connect("clicked",self.exit_with_value,2)
			self.show_error_dialog("The file "+self.rpmfile+" does not exist or cannot be opened.","Cannot open package")
# 		except ValueError:
# 			self.get_widget("error_dialog").connect("delete_event",self.exit_with_value,2)
# 			self.get_widget("error_dismiss").connect("clicked",self.exit_with_value,2)
# 			self.show_error_dialog("The file "+self.rpmfile+" is not an RPM package or is corrupt.","Cannot open package")
	
	def main_window_closed(self,caller=None,data=None):
		self.quit()

	def display_rpm_info(self,info):
		srcpkg = ""
		if info.source_package is True:
			srcpkg = " source package"
		if info.installed and info.source_package is not True:
			title = "<big><big><b>%s %s</b> (installed)</big></big>\nInformation for installed package %s"%(info.packagename,info.version,info.filename)
		else:
			title = "<b><big><big>%s %s%s</big></big></b>\nInformation for package %s"%(info.packagename,info.version,srcpkg,info.filename)
		
		self.get_widget("title").set_markup(title)
		self.get_widget("window").set_title("Package: %s %s"%(info.packagename,info.version))
		if info.installed:
			self.get_widget("diskspacelabel").set_text("Disk space used:")
		self.get_widget("diskspace").set_markup("%d kilobytes"%(info.installedsize))
		self.get_widget("description").set_markup("%s"%(info.description))
		if info.installed:
			self.get_widget("uninstall").show()
		else:
			self.get_widget("install").show()
		
		store = gtk.ListStore(str,str)
		for e in info.files:
			store.append((e.filename,file_status_code_to_string(e.status)))
		treeview = self.get_widget("files")
		treeview.set_model(store)
		
		store = gtk.ListStore(str,str)
		for e in info.dependencies:
			store.append((e.name,dep_status_code_to_string(e.status)))
		treeview = self.get_widget("dependencies")
		treeview.set_model(store)
		
		self.window.present()
	
	def install_package(self,e=None):
		if not self.rpmfile:
			return
		
		self.window.set_sensitive(False)
		install_rpm(self.rpmfile)
		self.display_file()
		self.window.set_sensitive(True)

	def get_version(self):
		program = gnome.program_get()
		return program.get_property("app-version")
		# the following code is deprecated and will no longer be used
		file = path.join(self.sharepath,"version")
		f = open(file)
		lines = f.readlines()
		version = strip(lines[0])
		return version
		
	def connect_signals(self):
		self.signal_autoconnect(self)

	def prepare_widgets(self):

		self.get_widget("window").set_icon_from_file(path.join(self.sharepath,"rpmview.png"))
		self.get_widget("info_dialog").set_icon_from_file(path.join(self.sharepath,"rpmview.png"))
		self.get_widget("warning_dialog").set_icon_from_file(path.join(self.sharepath,"rpmview.png"))
		self.get_widget("error_dialog").set_icon_from_file(path.join(self.sharepath,"rpmview.png"))
		self.get_widget("about_dialog").set_icon_from_file(path.join(self.sharepath,"rpmview.png"))


		self.get_widget("package_icon").set_from_file(path.join(self.sharepath,"rpmview.png"))
		self.get_widget("about_image").set_from_file(path.join(self.sharepath,"rpmview.png"))
		title = "<span weight=\"bold\"><big><big>RPMView</big></big></span>"
		version = "<b>version "+self.get_version()+"</b>"
		subtitle = "A graphical application to install and uninstall RPMs"
		
		self.get_widget("label_about").set_markup(title + "\n" + version + "\n" + subtitle)
		
		treeview = self.get_widget("files")
		col_name = gtk.TreeViewColumn("File", gtk.CellRendererText(),text=0)
		col_status = gtk.TreeViewColumn("Status", gtk.CellRendererText(),text=1)
 		treeview.insert_column(col_name, 0)
 		treeview.insert_column(col_status, 1)
		
		treeview = self.get_widget("dependencies")
		col_name = gtk.TreeViewColumn("Name", gtk.CellRendererText(),text=0)
		col_status = gtk.TreeViewColumn("Status", gtk.CellRendererText(),text=1)
 		treeview.insert_column(col_name, 0)
 		treeview.insert_column(col_status, 1)

		
	def quit(self,caller=None,extraobject=None):
		gtk.main_quit()

	def show_dialog(self,dialogtype,message,title=None):
		if title:
			dialogtitle = title
			title = "<span weight='bold' size='larger'>" + title + "</span>\n\n"
		else:
			dialogtitle = "RPMView - error"
			title = ""
		self.get_widget(dialogtype + "_message").set_markup(title+message)
		self.get_widget(dialogtype + "_dialog").set_title(dialogtitle)
		self.get_widget(dialogtype + "_dialog").present()

	def show_error_dialog(self,message,title=None):
		return self.show_dialog("error",message,title)
	
	def show_info_dialog(self,message,title=None):
		return self.show_dialog("info",message,title)
	
	def show_warning_dialog(self,message,title=None):
		return self.show_dialog("warning",message,title)
	
	def show_about_dialog(self,caller=None):
		self.get_widget("about_dialog").present()
		
	def dismiss_error_dialog(self,caller=None,e=None):
		self.get_widget("error_dialog").hide()
		return False
		
	def exit_with_value(self,caller=None,e=None,value=0):
		sys.exit(value)
		return False
		
	def dismiss_about_dialog(self,caller=None,e=None):
		self.get_widget("about_dialog").hide()
		return True
		
	def dismiss_info_dialog(self,caller=None,e=None):
		self.get_widget("info_dialog").hide()
		return True
		
	def dismiss_warning_dialog(self,caller=None,e=None):
		self.get_widget("warning_dialog").hide()
		return True
		
	def open_website(self,caller = None):
		try:
			open_webpage("http://www.amautacorp.com/staff/Rudd-O/rpmview/")
		except NoBrowserError, e:
			pass
		
	def open_author_website(self,caller = None):
		try:
			open_webpage("http://www.amautacorp.com/staff/Rudd-O/")
		except NoBrowserError, e:
			pass
		
	def send_mail_to_author(self,caller = None):
		try:
			compose_mail("rudd-o@amautacorp.com")
		except NoBrowserError, e:
			pass
	
	def open_gpl(self,caller = None):
		try:
			open_webpage("http://www.fsf.org/copyleft/gpl.txt")
		except NoBrowserError, e:
			pass
		
		

def main():

	program = gnome.program_init("rpmview","0.5")

	
	if len(sys.argv) > 1:
		rpmfile = sys.argv[1]
	else:
		sys.stderr.write("error\n")
		sys.stderr.write("usage: rpmview /path/to/filename.rpm\n")
		sys.exit(1)

	gtk.threads_init()

	app = RPMView(get_shared_path(),rpmfile)

	gtk.main()


if __name__ == "__main__":
	main()
