import os
from parallels.pmm_unix_migrator.pmm_agent import PmmMigrationAgentBase
from parallels.common import MigrationError
import textwrap

class PleskXPmmMigrationAgent(PmmMigrationAgentBase):
	"""Migration agent for Plesk panel and Expand.

	'self.max_pleskversion' specifies maximum version of source Plesk panel
	that is supported by the agent.
	"""
	def __init__(self, migrator_pmm_dir, server, settings):
		self.max_pleskversion = {'MAJOR': 11, 'MINOR': 5, 'PATCH': 30}
		self.dump_directories = 'clients domains resellers .discovered'
		self.remote_log_filename = 'dump.log'
		cli_options = '--dump-all --configuration-only --server -v 5'
		super(PleskXPmmMigrationAgent, self).__init__(
			migrator_pmm_dir, server, settings, cli_options)

	def run_agent(self, local_data_filename, local_log_filename):
		"""Run migration agent on a source panel and download the results.
		
		Execute the agent which puts results into XML dump file.
		Download dump XML file and log file to specified locations:
		- dump_xml_filename - local filename to put dump XML to
		- dump_log_filename - local filename to put dump log to

		Raise MigrationError in case of any failure.
		"""
		self.logger.info(u"Create source panel migration dump.")
		self.local_log_filename = local_log_filename
		self._patch_template(self.max_pleskversion)
		self.logger.debug(u"Run migration agent.")
		self._make_dump()
		self._download_dump(local_data_filename)

	def _patch_template(self, max_pleskversion):
		"""Fill in maximum supported Plesk version."""
		command = (u"""
				sed "s/@@MAJOR_VERSION@@/{MAJOR}/;
				s/@@MINOR_VERSION@@/{MINOR}/;
				s/@@PATCH_VERSION@@/{PATCH}/;" \\
				./PleskMaxVersion.pm.in > ./PleskMaxVersion.pm"""
			.format(**max_pleskversion))
		self._run_agent_command(
			u"cd {path}; %s" % textwrap.dedent(command),
			{'path': self.settings.agent_home})

	def _make_dump(self):
		"""Run the agent and crate migraion dump.

		Download agent log file even in case, if the agent has failed.
		"""
		self.logger.debug(u"Run migration agent.")
		command = u"""cd {path}; perl {script} %s > {log} 2>&1"""
		try:
			self._run_agent_command(
				command % (self.cli_options),
				{
					'path':	self.settings.agent_home,
					'script': self.settings.agent_script_name,
					'log': self.remote_log_filename,
				}
			)
		finally:
			self._download_agent_file(
					self.remote_log_filename, self.local_log_filename)

	def _download_dump(self, local_data_filename):
		self.logger.debug(u"Download dump XML to '%s'", local_data_filename)
		remote_dump_file = 'migration_dump.tar'
		command = (ur"""
			cd {path}; rm -f {dumpfile};
			for i in %s ;
				do test -d $i && tar rf {dumpfile} $i ;
			done;
			tar rf {dumpfile} backup_info*""")
		self._run_agent_command(
			command % self.dump_directories,
			{
				'path':	self.settings.agent_home,
				'dump_directories': self.dump_directories,
				'dumpfile': remote_dump_file,
			}
		)
		self._download_agent_file(remote_dump_file, local_data_filename)

	def _download_agent_file(self, remote_file, local_file):
		"""Download a file from agent directory on source server."""
		try:
			with self.server.runner() as runner:
				self.logger.debug(
					u"Download a file to '%s'", local_file)
				runner.get_file( 
					os.path.join(
						self.settings.agent_home, remote_file), local_file)
		except Exception as e:
			self.logger.debug(u'Exception', exc_info=True)
			self.logger.error(
				u"Error downloading file: %s" % e)

	def _run_agent_command(self, command, arguments):
		"""Run a command on the source server."""
		try:
			with self.server.runner() as runner:
				runner.sh(textwrap.dedent(command), arguments)
		except Exception as e:
			self.logger.debug(u'Exception', exc_info=True)
			raise MigrationError(u"Error running command: %s" % e)
