import logging
from parallels.hosting_check import ServerRunnerBase
from parallels.hosting_check import NonZeroExitCodeException
from parallels.common.utils import unix_utils

logger = logging.getLogger(__name__)

class HostingCheckerRunnerAdapter(ServerRunnerBase):
	"""
	Implement hosting checker' server interface.

	Implementation should be compatible with Python 2.4, therefore we hide Python
	2.5+ features, like context manager.  
	"""
	def __init__(self, runner_contextmanager_constructor):
		"""
		Object constructor.

		Arguments:
			server: A contextmanager that contains runner.
		"""
		self.runner_contextmanager_constructor = runner_contextmanager_constructor
		self.connection = None
		self.contextmanager = None

	def connect(self):
		"""Open server connection.  """
		self._assert( 
			self.contextmanager is None and self.connection is None, \
			"Can not open connection which is already open"
		)
		
		self.contextmanager = self.runner_contextmanager_constructor()
		self.connection = self.contextmanager.__enter__()

	def disconnect(self):
		"""Close server connection."""
		self._assert( 
			self.contextmanager is not None and self.connection is not None, 
			"Can not close connection that is not open"
		)
		self.contextmanager.__exit__(None, None, None)
		self.contextmanager = None
		self.connection = None
		
	def sh(self, cmd, arguments=dict()):
		"""Run a command on server.
		Args:
			cmd: template command string
			arguments: dictionary of named arguments for 'cmd' template
		"""
		self._assert(
			self.contextmanager is not None and self.connection is not None,
			"Can not execute commands on connection that is not open"
		)
		exit_code, stdout, stderr = self.sh_unchecked(cmd, arguments)
		if exit_code != 0:
			cmd_str = unix_utils.format_command(cmd, **arguments)
			raise NonZeroExitCodeException(
				exit_code, stdout, stderr, cmd_str)
		return stdout

	def sh_unchecked(self, *args, **kwargs):
		self._assert( 
			self.contextmanager is not None and self.connection is not None,
			"Can not execute commands on connection that is not open"
		)
		return self.connection.sh_unchecked(*args, **kwargs)

	def upload_file_content(self, *args, **kwargs):
		self._assert( 
			self.contextmanager is not None and self.connection is not None,
			"Can not upload files commands on connection that is not open"
		)
		self.connection.upload_file_content(*args, **kwargs)

	@staticmethod
	def _assert(condition, message):
		"""Assert some pre-condition
		
		Comparing to built-in assert function, this one raises
		simple Exception, not AssertionError which causes migration
		tool to completely fail in all situations
		"""
		if not condition:
			raise Exception(message)
