from contextlib import contextmanager

from parallels.core import messages
from parallels.core.connections.ssh.connection_pool import SSHConnectionPool
from parallels.core.migrator_config import PhysicalUnixServerConfig, PhysicalWindowsServerConfig
from parallels.core.registry import Registry
from parallels.core.run_command import WindowsAgentRunner
from parallels.core.utils import session_dir
from parallels.core.utils.common import cached


class PhysicalServer(object):
	@property
	def node_id(self):
		"""For compatibility with old code.

		Switch to server_id property instead"""
		return self.settings().server_id

	@contextmanager
	def runner(self):
		raise NotImplementedError()

	def is_windows(self):
		"""
		:rtype: bool
		"""
		raise NotImplementedError()

	def settings(self):
		"""
		:rtype: parallels.core.migrator_config.PhysicalServerConfig
		"""
		raise NotImplementedError()

	def ip(self):
		"""
		:rtype: str
		"""
		return self.settings().ip

	def description(self):
		"""
		:rtype: unicode
		"""
		return messages.PHYSICAL_SERVER_DESCRIPTION % self.ip()

	def get_session_file_path(self, filename):
		return self.session_dir_object().get_file_path(filename)

	def session_dir(self):
		return self.session_dir_object().get_session_dir_path()

	@cached
	def session_dir_object(self):
		if self.is_windows():
			return session_dir.WindowsSessionDir(
				self.runner, self.settings().session_dir
			)
		else:
			return session_dir.UnixSessionDir(
				self.runner, self.settings().session_dir
			)


class PhysicalWindowsServer(PhysicalServer):
	def __init__(self, settings):
		"""
		:type settings: parallels.core.migrator_config.PhysicalWindowsServerConfig
		"""
		self._settings = settings

	def settings(self):
		"""
		:rtype: parallels.core.migrator_config.PhysicalWindowsServerConfig
		"""
		return self._settings

	def is_windows(self):
		"""
		:rtype: bool
		"""
		return True

	@contextmanager
	def runner(self):
		migrator_server = Registry().get_instance().get_context().migrator_server
		yield WindowsAgentRunner(self._settings, migrator_server)


class PhysicalUnixServer(PhysicalServer):
	def __init__(self, settings):
		"""
		:type settings: parallels.core.migrator_config.PhysicalUnixServerConfig
		"""
		self._settings = settings

	def settings(self):
		"""
		:rtype: parallels.core.migrator_config.PhysicalUnixServerConfig
		"""
		return self._settings

	def is_windows(self):
		"""
		:rtype: bool
		"""
		return False

	@contextmanager
	def runner(self):
		yield SSHConnectionPool.get_instance().get(self._settings, self.description())


def create_physical_server(settings):
	"""
	:rtype: parallels.core.connections.physical_server.PhysicalServer
	"""
	if isinstance(settings, PhysicalUnixServerConfig):
		return PhysicalUnixServer(settings)
	elif isinstance(settings, PhysicalWindowsServerConfig):
		return PhysicalWindowsServer(settings)
	else:
		assert False