#
# FtpCube
# Copyright (C) 2001 Michael Gilfix
#
# This file is part of FtpCube.
#
# You should have received a file COPYING containing license terms
# along with this program; if not, write to Michael Gilfix
# (mgilfix@eecs.tufts.edu) for a copy.
#
# This version of FtpCube is open source; you can redistribute it and/or
# modify it under the terms listed in the file COPYING.
#
# 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.
#

import GTK, gtk, GtkExtra
import os, time, re
import main, app, ftp

class LocalWin:

	list = None
	dir = None
	status_label = None

	headings = [ 'Filename', 'Size', 'Date', 'Type', 'Truesize' ]
	time_re = re.compile ('[A-Za-z]+\s+([A-Za-z]+\s+\d+\s+\d+:\d+):(\d+)\s+\d+')


	def __init__ (self, container):

		box = gtk.GtkVBox ()
		box.show ()
		container.add (box)

		win = gtk.GtkScrolledWindow ()
		win.set_policy (gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
		win.show ()
		box.pack_start (win)

		bar = gtk.GtkHBox ()
		bar.set_usize (-1, 15)
		bar.show ()
		box.pack_start (bar, expand=gtk.FALSE, fill=gtk.TRUE)

		button = gtk.GtkButton ("B")
		button.connect ("clicked", self.enable_dir_update)
		button.set_usize (15, 15)
		button.show ()
		bar.pack_start (button, expand=gtk.FALSE, fill=gtk.FALSE)

		self.status_label = gtk.GtkLabel ("")
		self.status_label.show ()
		bar.pack_start (self.status_label, expand=gtk.FALSE, fill=gtk.FALSE, padding=6)

		self.list = gtk.GtkCList (5, self.headings)
		self.list.connect ("select_row", self.select_items)
		self.list.connect ("button_press_event", self.popup_menu)

		# Set up list column defaults
		for i in range(len (self.headings)):
			self.list.set_column_width (i, 100)
			self.list.set_column_justification (i, gtk.JUSTIFY_LEFT)
		# Explicitly make the first column for the filename bigger
		self.list.set_column_width (0, 200)
		# Hide the flags column
		self.list.set_column_visibility (3, 0)
		self.list.set_column_visibility (4, 0)

		self.list.set_selection_mode (GTK.SELECTION_MULTIPLE)
		win.add_with_viewport (self.list)
		self.list.show ()

		self.load_pixmaps ()

		# Open up the default directory for display
		if os.environ.has_key ('HOME'):
			self.dir = os.environ['HOME']
		else:
			self.dir = os.getcwd ()
		self.update_listing (self.dir)

	def load_pixmaps (self):

		self.folder_pixmap, self.folder_mask = gtk.create_pixmap_from_xpm (self.list, None, main.ICONS_PREFIX + os.sep + "folder.xpm")
		self.link_pixmap, self.link_mask = gtk.create_pixmap_from_xpm (self.list, None, main.ICONS_PREFIX + os.sep + "link.xpm")
		self.file_pixmap, self.file_mask = gtk.create_pixmap_from_xpm (self.list, None, main.ICONS_PREFIX + os.sep + "file.xpm")

	def select_pixmap (self, listitem):

		file, size, mtime, type, truesize = listitem
		if type == 'l':
			return self.link_pixmap, self.link_mask
		elif type == 'd':
			return self.folder_pixmap, self.folder_mask
		else:
			return self.file_pixmap, self.file_mask

	def select_items (self, list, r, c, event):

		if hasattr (event, 'type'):
			# Check for double clicks
			if event.type == 5:
				selected = list.get_pixtext (r, 0)[0]

				# Construct our new dir path
				if selected == ".":
					return
				elif selected == "..":
					self.dir = os.path.dirname (self.dir)
				else:
					if self.dir == '/':
						newpath = self.dir + selected
					else:
						newpath = self.dir + os.sep + selected
					if not os.path.isdir (newpath):
						return
					else:
						self.dir = newpath

				# If we've made it this far, load the new dir
				self.update_listing (self.dir)

	def popup_menu (self, list, event):

		if event.button == 3 and not list.selection == []:
			opts = [
				('/Upload Files',    None, self.upload_selected),
				('/Open',            None, self.open_selected),
				('/Edit',            None, self.edit_selected),
				('/View File',       None, None),
				('/Delete Selected Files', None, self.delete_selected),
				('/Rename File',           None, None),
				('/FTPSearch this file',   None, None),
				('/Create Directory',      None, None),
				('/Change Directory',      None, None),
				('/<separator>',           None, None),
				('/Change Drive',          None, None),
				('<separator>',            None, None),
				('/Compare Directories',   None, None),
				('/Open Current in Browser', None, None),
				('/Open Selected in Browser', None, None),
				('/Command Prompt Here',      None, None),
				('<separator>',               None, None),
				('/Directory Info',           None, None),
				('/<separator>',              None, None),
				('/Sort Order/Unsorted',      None, None),
				('/Sort Order/Sort by Name',  None, None),
				('/Sort Order/Sort by Size',  None, None),
				('/Sort Order/Sort by Date',  None, None),
				('/Sort Order/<separator>',   None, None),
				('/Sort Order/Directories First', None, None),
			]

			menu = GtkExtra.MenuFactory (GtkExtra.MENU_FACTORY_MENU)
			menu.add_entries (opts)
			menu.popup (None, None, None, event.button, event.time)
			menu.show ()

	def upload_selected (self, button):

		files = [ ]

		for i in self.list.selection:
			entry = [ ]
			entry.append (self.list.get_pixtext (i, 0)[0])
			# Get remaining entries
			for j in range (self.list.columns - 1):
				entry.append (self.list.get_text (i, j + 1))

			if entry[0] == "..":
				continue
			else:
				files.append (tuple (entry))

		self.list.unselect_all ()
		main.app.transfer (main.app.get_remote_dir (), self.get_dir (), files, ftp.UPLOAD)

	def open_selected (self, button):

		for i in self.list.selection:
			file = self.list.get_pixtext (i, 0)[0]
			path = self.get_dir () + os.sep + file

			# Skip the home directory entry
			if file == ".." or \
			   not os.path.isfile (path) or \
			   not os.access (path, os.X_OK):
				continue
			else:
				pid = os.fork ()
				if not pid:
					os.execv (path, args)

	def edit_selected (self, button):

		for file in self.list.selection:
			file = self.list.get_pixtext (i, 0)[0]
			path = self.get_dir () + os.sep + file

			# Editing code will go here

	def delete_selected (self, button):

		for i in self.list.selection:
			file = self.list.get_pixtext (i, 0)[0]
			type = self.list.get_text (i, 3)[0]
			path = self.dir + os.sep + file
			if type in '-lf':
				os.remove (path)
			else:
				os.rmdir (path)
		self.list.unselect_all ()
		self.update_listing (self.dir)

	def clear_items (self):
		self.list.clear ()

	def update_status_dir (self, dir):
		self.status_label.set_text (dir)

	def enable_dir_update (self, button):
		pass

	def get_dir (self):
		return self.dir

	def get_file_size (self, file):

		for i in range (self.list.rows):
			if self.list.get_pixtext (i, 0)[0] == file:
				return int (self.list.get_text (i, 4))
		return None

	def read_dir (self, dir):

		# If we say '.', we really mean our current directory
		if dir == '.':
			dir = self.dir

		try:
			files = os.listdir (dir)
		except OSError, (errno, strerror):
			# Couldn't read it, so do nothing right now
			# Will need to change this later
			print "Couldn't open directory: %s" %strerror
			return

		# Add the special file ".."
		files.insert (0, "..")

		# Now grab the file info and load it into the load
		listitems = []
		for f in files:
			(st_mode, st_ino, st_dev, st_nlink, st_uid, st_gid, st_size,
			 st_atime, st_mtime, st_ctime) = os.stat (dir + os.sep + f)

			# Beautify the size string
			size = app.beautify_size (st_size)

			# Beautify the time
			match = self.time_re.match (time.ctime (st_mtime))
			mtime = match.group (1)

			# Set the appropriate file type
			if os.path.islink (self.dir + os.sep + f):
				type = "l"
			elif os.path.isdir (self.dir + os.sep + f):
				type = "d"
			else:
				type = "f"

			listitems.append ((f, size, mtime, type, "%s" %st_size))

		return listitems

	def update_listing (self, dir):

		listitems = self.read_dir (dir)

		# Now change the list to reflect the new listing. Notice that we
		# pause the visuals during the update so it doesn't look funny
		self.list.freeze ()
		self.clear_items ()
		for i in range (len (listitems)):
			self.list.append (listitems[i])
			listitem = listitems[i]
			pixmap, mask = self.select_pixmap (listitem)
			self.list.set_pixmap (i, 0, pixmap, mask)
			self.list.set_pixtext (i, 0, listitem[0], 4, pixmap, mask)
		self.list.sort ()
		self.list.thaw ()

		# Update the status
		self.update_status_dir (dir)
