"""
File adapters that allow to read Plesk backup files (including backup XML files) 
from Plesk backup archives of different versions and OSes
"""
import tarfile
import zipfile
import gzip
from contextlib import closing
from StringIO import StringIO
import email

class TarFileAdapter:
	def __init__(self, file_name):
		self.tar = tarfile.open(file_name)

	def close(self):
		self.tar.close()

	def get_names(self):
		return self.tar.getnames()

	def get_members(self):
		return map(TarFileAdapter.FileInfo, self.tar.getmembers())

	def extract(self, name):
		return self.tar.extractfile(name)

	class FileInfo:
		def __init__(self, member):
			self.member = member

		@property
		def is_file(self): return self.member.isfile()

		@property
		def name(self): return self.member.name

		@property
		def size(self): return self.member.size

class ZipFileAdapter:
	def __init__(self, file_name):
		self.zip = zipfile.ZipFile(file_name)
	
	def close(self):
		self.zip.close()

	def get_names(self):
		return self.zip.namelist()

	def get_members(self):
		return map(ZipFileAdapter.FileInfo, self.zip.infolist())

	def extract(self, name):
		return self.zip.open(name)

	class FileInfo:
		def __init__(self, info):
			self.info = info

		@property
		def is_file(self): return self.info.external_attr & 0x10 == 0 # 0x10 is a directory attribute

		@property
		def name(self): return self.info.filename

		@property
		def size(self): return self.info.file_size

class Plesk8UnixBackupFileAdapter:
	def __init__(self, file_name):
		with closing(gzip.open(file_name)) as fp:
			self.msg = email.message_from_file(fp)
			self.files = self.parse(self.msg)

	@classmethod
	def parse(cls, msg):
		files = {}

		if msg.is_multipart():
			for submsg in msg.get_payload():
				files.update(cls.parse(submsg))
		else:
			files[msg.get_param('name')] = msg

		return files

	def close(self):
		pass

	def get_names(self):
		return self.files.keys()

	def get_members(self):
		return [Plesk8UnixBackupFileAdapter.FileInfo(name, len(value.get_payload())) for name, value in self.files.iteritems()]

	def extract(self, name):
		return StringIO(self.files[name].get_payload())

	class FileInfo:
		def __init__(self, name, size):
			self.name = name
			self.size = size

		@property
		def is_file(self): return True

