import tarfile

class ResourceException(Exception):
	"""
	When a file isn't in the archive this is raised.
	"""
	pass

class ResourceFileObject:
	def __init__(self, fp):
		"""
		This is a file-like object which acts as a cache for already loaded files.
		It keeps a single copy of the file read from the tarball and can be read like a regular python
		file object with read(), etc.

		pass in fp which is a filepointer to an existing file in the archive.

		Please remember this is a pretty sketchy implementation. You must be careful when using it.
		It keeps a cached copy of a single file so if multiple things open a file at the same time,
		it will probably break. It doesn't check if a 'file' is closed before reading from it. Any
		'file' that closes is reset for all instances of that file.

		Be careful!
		"""
		self.data = fp.read()
		self.name = fp.name
		self.size = fp.size
		self.closed = fp.closed
		self.mode = fp.mode
		# this points to where we're up to in the data
		self.current = 0
	
	def close(self):
		self.closed = True
		self.current = 0
	
	def read(self, size=None):
		#print "READ size: " + str(size)
		current = self.current
		if (size):
			self.current += size
			return self.data[current:current+size]
		else:
			self.current = 0
			return self.data[self.current:]
	
	def seek(self, offset, whence=0):
		#print "Seek called on " + self.name + " @ " + str(self.current) + " with offset " + str(offset) + " and whence " + str(whence)
		if (whence == 0):
			self.current = offset
		elif (whence == 1):
			self.current += offset
		elif (whence == 2):
			self.current = self.size - offset

		#print "New pos: " + str(self.current)
	
	def tell(self):
		#print "Tell called"
		return self.current
	
	def readline(self):
		if (self.current < self.size):
			chunk = self.data[self.current:self.data.index("\n", self.current) + 1]
			self.current += len(chunk)
			return chunk
		else:
			return None
	
class ResourceFile:
	def __init__(self, filename):
		"""
		Open a new resource file.

		This stores a hashed cache of all resource files in memory for increased speed access.
		After the first loading/decompression of the file from the tarball, subsequent loads are passed the 
		ResourceFileObject file-like object which can be read and processed like a normal file.
		It's missing lots of 'normal' file functions - it just includes those bare minimum needed.
		"""
		self.rfile = tarfile.open(filename, "r:gz")
		self.cache = {}
		
		#for tarinfo in tar:
		#	print tarinfo.name, "is", tarinfo.size, "bytes in size and is",
		#if tarinfo.isreg():
		#	print "a regular file."
	    	#elif tarinfo.isdir():
		#	print "a directory."
	    	#else:
		#	print "something else."
	
	def FileList(self, extension):
		"""
		Get a list of all files of a certain type, by their extension.
		extension can be something such as "wav".
		"""
		# make a copy of the tarball listing to we can modify it
		dirlist = self.rfile.getnames()
		# weed out files that aren't of a certain extension
		dirlist = filter(lambda x: ((x[-4:] == ("." + extension))), dirlist)
		
		return dirlist
	
	def GetFile(self, filename):
		"""
		Get a file from the resource file.
		Store a copy of it in our cache.
		Next time you get it, you'll get the cached copy.
		"""
		if (self.cache.has_key(filename)):
			return self.cache[filename]
		else:
			fobject = None
			
			try:
				fobject = ResourceFileObject(self.rfile.extractfile(filename))
				self.cache[filename] = fobject
				return self.cache[filename]
			except KeyError:
				raise ResourceException, "That file '%s' is not in the archive."%filename
	
	def ExtractFile(self, filename):
		"""
		Extracts a file from the resource file.
		"""
		self.rfile.extract(self.rfile.getmember(filename))
	
	def __del__(self):
		"""
		Close the tar file when we're done.
		"""
		self.rfile.close()


