from parallels.core import messages
import logging
from parallels.hosting_check import ServerRunnerBase
from parallels.hosting_check import NonZeroExitCodeException
from parallels.core.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,
			messages.CAN_NOT_OPEN_CONNECTION_WHICH_IS
		)
		
		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, 
			messages.CAN_NOT_CLOSE_CONNECTION_THAT_IS)
		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,
			messages.CAN_NOT_EXECUTE_COMMANDS_CONNECTION_THAT)
		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,
			messages.CAN_NOT_EXECUTE_COMMANDS_CONNECTION_THAT_1)
		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,
			messages.CAN_NOT_UPLOAD_FILES_COMMANDS_CONNECTION)
		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)
