#!/usr/bin/env python

from gnomevfs import get_local_path_from_uri
from gc import collect
from os.path import join, getsize
from string import atoi

import gtk
import gtk.gdk
import gnome.ui
import gobject
import os
import gtk.glade
import locale

class ThumbnailChecker:
	def __init__(self):
		self.id = None
		self.first_time = True

		xml = gtk.glade.XML('thumbnail-checker.glade', None, None)
		self.model = gtk.TreeStore(str, str, str, int)

		self.window = xml.get_widget('window')
		self.treeview = xml.get_widget('treeview')
		self.progressbar = xml.get_widget('progressbar')
		self.progress = xml.get_widget('progress')
		self.button_start = xml.get_widget('button_start')
		self.button_stop = xml.get_widget('button_stop')
		self.image_view = xml.get_widget('image2')
		self.removeall = xml.get_widget('RemoveAllButton')
		xml.signal_autoconnect(self)

		self.treeview.set_search_column(1)
		self.treeview.set_model(self.model)

		renderer = gtk.CellRendererText()
		column = gtk.TreeViewColumn("File name or Thumbnail file", renderer, text=0)
		column.set_resizable(True)
		column.set_expand(True)
		self.treeview.append_column(column)

		renderer = gtk.CellRendererText()
		renderer.set_property('xalign', 1.0)
		column = gtk.TreeViewColumn("Size", renderer, text=1)
		column.set_resizable(True)
		column.set_min_width(80)
		column.set_resizable(True)
		self.treeview.append_column(column)

		column = gtk.TreeViewColumn("Thumbnail Path", None)
		column.set_visible(False)
		self.treeview.append_column(column)
	    
		column = gtk.TreeViewColumn("Size", None)
		column.set_visible(False)
		self.treeview.append_column(column)

		self.homedir = os.path.expanduser('~')
		(self.invalid_size, self.invalid_count, self.non_fd_size, self.non_fd_count, 
		    self.orphan_size, self.orphan_count, self.external_size, self.external_count) = (0,0,0,0,0,0,0,0)
		(self.orphan_iter, self.external_iter, self.invalid_iter, self.non_fd_iter) = (None, None, None, None)

	def show(self):
		self.window.show_all()

	def on_quit(self, *args):
		gtk.main_quit()

	def on_button_stop_clicked(self, button, *args):
		gobject.source_remove(self.id)
		self.button_stop.set_sensitive(False)
		self.button_start.set_sensitive(True)

	def on_button_start_clicked(self, button, *args):
		self.button_stop.set_sensitive(True)
		self.button_start.set_sensitive(False)
		if self.first_time:
			self.first_time = False
			self.task = self.walk()
		self.id = gobject.idle_add(self.task.next)

	def walk(self, *args):
		(self.invalid_size, self.invalid_count) = (0, 0)
		(self.non_fd_size, self.non_fd_count) = (0, 0)
		(self.orphan_size, self.orphan_count) = (0, 0)
		(self.external_size, self.external_count) = (0, 0)
		
		self.orphan_iter = self.model.append(None, ["Orphans", '0','',0])
		self.external_iter = self.model.append(None, ["Orphans and/or Externals", '0','',0])
		self.invalid_iter = self.model.append(None, ["Invalid (broken image)", '0','',0])
		self.non_fd_iter = self.model.append(None, ["No Free Desktop compliant", '0','',0])

		rootdir = os.path.expanduser('~/.thumbnails')
		for root, dirs, files in os.walk(rootdir):
			i = 0.0

			text = "%d of %d" % (0, len(files))
			self.progressbar.set_text(text)
			text = "Processing %s ..." % root
			self.progress.set_text(text)

			for name in files:
				i = i + 1.0
				uri = None
				filename = join(root, name)
				shortname = filename.replace(self.homedir, '~')

				self.progressbar.set_fraction(i / len(files))
				text = "%d of %d" % (i, len(files))
				self.progressbar.set_text(text)

				try:
					pixbuf = gtk.gdk.pixbuf_new_from_file(filename)
					uri = pixbuf.get_option('tEXt::Thumb::URI')
				except:
					# Broken thumbnail
					uri = ''

				try:
					local_path = get_local_path_from_uri(uri)
				except:
					# External resource or invalid uri
					local_path = ''

				if len(local_path) == 0 and uri is not None and len(uri):
					# external resource (vfs method and/or orphan)
					size = getsize(filename)
					self.external_size += size
					self.external_count += 1

					str_size = locale.format("%d", size, grouping=True)
					self.model.append(self.external_iter, [uri, str_size, filename, size])

					str_size = locale.format("%d", self.external_size, grouping=True)
					self.model.set(self.external_iter, 1, str_size)
					self.model.set(self.external_iter, 0, 
					               "Orphans and/or Externals [%d]" % self.external_count)

				elif len(local_path) and not os.path.lexists(local_path):
					# orphan thumbnail
					size = getsize(filename)
					self.orphan_size += size
					self.orphan_count += 1
					shortname = local_path.replace(self.homedir, '~')

					str_size = locale.format("%d", size, grouping=True)
					self.model.append(self.orphan_iter, [shortname, str_size, filename, size])

					str_size = locale.format("%d", self.orphan_size, grouping=True)
					self.model.set(self.orphan_iter, 1, str_size)
					self.model.set(self.orphan_iter, 0, "Orphans [%d]" % self.orphan_count)

				elif uri is None:
					# pixbuf is ok, but no FD compliant.
					size = getsize(filename)
					self.non_fd_size += size
					self.non_fd_count += 1

					str_size = locale.format("%d", size, grouping=True)
					self.model.append(self.non_fd_iter, [shortname, str_size, filename, size])

					str_size = locale.format("%d", self.non_fd_size, grouping=True)
					self.model.set(self.non_fd_iter, 1, str_size)
					self.model.set(self.non_fd_iter, 0, 
					               "Non Free Desktop compliant [%d]" % self.non_fd_count)

				elif len(uri) == 0:
					# thumbnail is not a valid pixbuf
					size = getsize(filename)
					self.invalid_size += size
					self.invalid_count += 1
					shortname = filename.replace(self.homedir, '~')

					str_size = locale.format("%d", size, grouping=True)
					self.model.append(self.invalid_iter, [shortname, str_size, filename, size])

					str_size = locale.format("%d", self.invalid_size, grouping=True)
					self.model.set(self.invalid_iter, 1, str_size)
					self.model.set(self.invalid_iter, 0, 
					               "Invalid (broken images) [%d]" % self.invalid_count)

				collect()
				yield True

			text = "%s done.  Trying the next one..." % root
			self.progress.set_text(text)
			yield True

		if self.non_fd_count+self.external_count+self.orphan_count+self.invalid_count != 0:
		    self.removeall.set_sensitive(True)

		self.button_stop.set_sensitive(False)
		self.button_start.set_sensitive(True)

		self.progressbar.set_text('Done')
		self.progress.set_text('')
		yield False
	
	def on_treeview_cursor_changed(self, *args):
		(path, col) = self.treeview.get_cursor()
		iter = self.model.get_iter(path)
		if self.model.iter_depth(iter) != 0:
		    value = self.model.get_value(iter, 2)
		    self.image_view.set_from_file(value)

	def on_treeview_key_press_event(self, widget, event, *args):
		if event.hardware_keycode == 107: # Delete key
		    (path, col) = self.treeview.get_cursor()
		    if path != None:
			iter = self.model.get_iter(path)
			if self.model.iter_depth(iter) != 0:
			    parent = self.model.iter_parent(iter)
			    value = self.model.get_value(iter, 2)
			    size = self.model.get_value(iter,3)
			    print "Deleting %s" % value
			    os.remove(value)
			    self.model.remove(iter)
			    if self.model.get_string_from_iter(parent) == self.model.get_string_from_iter(self.external_iter):
				self.external_size -= size
				self.external_count -= 1
				str_size = locale.format("%d", self.external_size, grouping=True)
				self.model.set(self.external_iter, 1, str_size)
				if self.external_count != 0:
				    self.model.set(self.external_iter, 0, 
					"Orphans and/or Externals [%d]" % self.external_count)
				else:
				    self.model.set(self.external_iter, 0, "Orphans and/or Externals")

			    elif self.model.get_string_from_iter(parent) == self.model.get_string_from_iter(self.orphan_iter):
				self.orphan_size -= size
				self.orphan_count -= 1
				str_size = locale.format("%d", self.orphan_size, grouping=True)
				self.model.set(self.orphan_iter, 1, str_size)
				if self.orphan_count != 0:
				   self.model.set(self.orphan_iter, 0, 
				    "Orphans [%d]" % self.orphan_count)
				else:
				    self.model.set(self.orphan_iter, 0, "Orphans")

			    elif self.model.get_string_from_iter(parent) == self.model.get_string_from_iter(self.non_fd_iter):
				self.non_fd_size -= size
				self.non_fd_count -= 1
				str_size = locale.format("%d", self.non_fd_size, grouping=True)
				self.model.set(self.non_fd_iter, 1, str_size)
				if self.non_fd_count != 0:
				    self.model.set(self.non_fd_iter, 0, 
					"Non Free Desktop compliant [%d]" % self.non_fd_count)
				else:
				    self.model.set(self.non_fd_iter, 0, "Non Free Desktop compliant")

			    elif self.model.get_string_from_iter(parent) == self.model.get_string_from_iter(self.invalid_iter):
				self.invalid_size -= size
				self.invalid_count -= 1
				str_size = locale.format("%d", self.invalid_size, grouping=True)
				self.model.set(self.invalid_iter, 1, str_size)
				if self.invalid_count != 0:
				    self.model.set(self.invalid_iter, 0, 
					"Invalid (broken images) [%d]" % self.invalid_count)
				else:
				    self.model.set(self.invalid_iter, 0, "Invalid (broken images)")

			    if self.non_fd_count+self.external_count+self.orphan_count+self.invalid_count == 0:
				self.removeall.set_sensitive(False)

			    if self.model.iter_is_valid(iter) == True:
				self.treeview.set_cursor(path, None, False)

	def on_RemoveAllButton_clicked(self, *args):

	    iter = self.model.get_iter_root()
	    while iter != None:
		if self.model.iter_has_child(iter) == True:
		    child_iter = self.model.iter_children(iter)
		    while child_iter != None:
			filename = self.model.get_value(child_iter,2)
#			print "Deleting %s" % filename
			os.remove(filename)
			child_iter = self.model.iter_next(child_iter)
		iter = self.model.iter_next(iter)
	    self.model.clear()

	
if __name__ == "__main__":
	locale.setlocale(locale.LC_ALL,locale.getdefaultlocale())

	checker = ThumbnailChecker()
	checker.show()

	gtk.main()
