#!/usr/bin/env python
#
# main.py
# Copyright (C) Yasumichi Akahoshi 2011 <yasumichi@vinelinux.org>
# 
# pygtk-rpminstall 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 3 of the License, or
# (at your option) any later version.
# 
# pygtk-rpminstall 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, see <http://www.gnu.org/licenses/>.


from gi.repository import Gtk, GdkPixbuf, Gdk
import os, sys, fnmatch
import rpm
import progress, dependdialog, installed

#Comment the first line and uncomment the second before installing
#or making the tarball (alternatively, use project variables)
UI_FILE = "ui/rpminstall.ui"
RPM_ICON = "ui/icons/rpm.png"

rpmtsCallback_fd = None

#
# Class for main window
#
class GUI:
	def __init__(self):
		# Build user interface
		self.builder = Gtk.Builder()
		self.builder.set_translation_domain('rpminstall')
		self.builder.add_from_file(os.path.join (os.path.dirname(__file__), UI_FILE))
		self.builder.connect_signals(self)
		self.build_file_list_view()

		# add packages from command line arguments
		self.add_packages_from_argv ()

		# Show window
		self.window = self.builder.get_object('window')
		self.window.show_all()

	#
	# Build file list view
	#
	def build_file_list_view(self):
		# Build Column
		column_file = Gtk.TreeViewColumn(_("RPM Package"))
		
		renderer_pixbuf = Gtk.CellRendererPixbuf()
		column_file.pack_start(renderer_pixbuf,False)
		column_file.add_attribute(renderer_pixbuf,"pixbuf",0)
		
		renderer_text = Gtk.CellRendererText()
		column_file.pack_start(renderer_text, True)
		column_file.add_attribute(renderer_text, "text", 1)
		
		file_list_view = self.builder.get_object('file_list_view')
		file_list_view.append_column(column_file)

		# Enable multi select
		selection = file_list_view.get_selection()
		selection.set_mode(Gtk.SelectionMode.MULTIPLE)

		self.progress = 0

	#
	# add packages from command line arguments
	#
	def add_packages_from_argv(self):
		file_liststore = self.builder.get_object('file_liststore')
		pixbuf = GdkPixbuf.Pixbuf.new_from_file(os.path.join(os.path.dirname(__file__), RPM_ICON))

		for arg in sys.argv:
			for pattern in self.get_installable_pattern_list():
				if fnmatch.fnmatchcase(arg, pattern):
					file_liststore.append([pixbuf, arg])
					break

	#
	# Callback when add button is clicked
	#
	def add_button_clicked(self, window):
		dialog = Gtk.FileChooserDialog(_("Please choose a file"), window,
			Gtk.FileChooserAction.OPEN,
			(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
			Gtk.STOCK_OPEN, Gtk.ResponseType.OK))
		dialog.set_select_multiple(True)

		filter_text = Gtk.FileFilter()
		filter_text.set_name(_("RPM Binary Package"))
		for pattern in self.get_installable_pattern_list():
			filter_text.add_pattern(pattern)
		
		dialog.add_filter(filter_text)
		if dialog.run() == Gtk.ResponseType.OK:
			file_liststore = self.builder.get_object('file_liststore')
			pixbuf = GdkPixbuf.Pixbuf.new_from_file(os.path.join(os.path.dirname(__file__), RPM_ICON))
			for fname in dialog.get_filenames():
				file_liststore.append([pixbuf, fname])

		dialog.destroy()

	#
	# Callback when delete button is clicked
	#
	def delete_button_clicked(self, button):
		file_list_view = self.builder.get_object('file_list_view')
		file_liststore = self.builder.get_object('file_liststore')
		selection = file_list_view.get_selection()
		while True:
			(unused, paths) = selection.get_selected_rows()
			if paths == []:
				break
			file_liststore.remove( file_liststore.get_iter(paths[0]) )
		
	#
	# Callback when cancel button is clicked
	#
	def cancel_button_clicked(self,button):
		Gtk.main_quit()

	#
	# Callback when cancel button is clicked
	#
	def execute_button_clicked(self,widget):
		count = 0
		file_liststore = self.builder.get_object('file_liststore')
		
		ts = rpm.TransactionSet()

		newer_installed = []
		treeiter = file_liststore.get_iter_first()
		while treeiter != None:
			filename = str(file_liststore[treeiter][1])
			fd = os.open(filename, os.O_RDONLY)
			h = None
			try:
				h = ts.hdrFromFdno(fd)
				installed_info = self.check_installed(h)
				if installed_info == None:
					ts.addInstall(h, filename, 'u')
					h = None
					os.close(fd)
					count = count + 1
				else:
					newer_installed.append(installed_info)
			except rpm.error, e:
				print str(e)

			treeiter = file_liststore.iter_next(treeiter)

		if len(newer_installed) > 0:
			dialog = installed.InstalledDialog(newer_installed)
			dialog.run()

		if count > 0:
			if self.possibility_of_installation(ts):
				ts.order()
				dialog = progress.ProgressDialog(self.window, ts)
				response = dialog.run()
		else:
			dialog = Gtk.MessageDialog(self.window, 0, Gtk.MessageType.INFO,
				Gtk.ButtonsType.OK, _("No package is selected."))
			dialog.run()
			dialog.destroy()

	#
	# check installed version
	#
	def check_installed(self, h):
		ts = rpm.TransactionSet()
		pkg_ds = h.dsOfHeader()
		for inst_h in ts.dbMatch('name', h['name']):
			inst_ds = inst_h.dsOfHeader()
			if pkg_ds.EVR() <= inst_ds.EVR():
				return (h['name'], pkg_ds.EVR(), inst_ds.EVR())
			else:
				return None

	#
	# check dependency
	#
	def possibility_of_installation(self, ts):
		unresolved_dependencies = ts.check()
		if not unresolved_dependencies:
			return	True
		else:
			dialog = dependdialog.DependDialog(unresolved_dependencies)
			dialog.run ()
			return False

	#
	# get installable pattern list
	#
	def get_installable_pattern_list(self):
		pattern_list = [ '*.noarch.rpm' ]

		arch = rpm.expandMacro('%{_arch}')
		if arch == 'i386':
			pattern_list.append('*.i?86.rpm')
		elif arch == 'x86_64':
			pattern_list.append('*.i?86.rpm')
			pattern_list.append('*.x86_64.rpm')
		else:
			pattern_list.append('*.' + arch + '.rpm')
		
		return	pattern_list
			
	#
	# Callback when Gui is destroied
	#
	def destroy(window, self):
		Gtk.main_quit()

