from contextlib import contextmanager

import parallels.common.connections_config as connections_config
from parallels import plesk_api
from parallels.common.connections.nested_context_ssh import NestedContextSSH
from parallels.common.connections.checker import ConnectionChecker
from parallels.common import run_command
from parallels.common.config_utils import ConfigSection

from parallels.common.connections.target_connections import TargetConnections
from parallels.common.utils.session_dir import UnixSessionDir
from parallels.common.utils.session_dir import WindowsSessionDir
from parallels.utils import cached

class PleskTargetConnections(TargetConnections):
	def __init__(self, config):
		self.config = config
		self._plesk_settings = connections_config.read_target_plesk_settings(config, 'plesk')
		if not self._plesk_settings.is_windows:
			self._nested_main_node_ssh = NestedContextSSH(self._plesk_settings, 'target Plesk server')

		if self._plesk_settings.is_windows:
			self._session_dir = WindowsSessionDir(
				self.main_node_runner, self._plesk_settings.windows_session_dir
			)
		else:
			self._session_dir = UnixSessionDir(
				self.main_node_runner, self._plesk_settings.unix_session_dir
			)

	@property
	def main_node_ip(self):
		return self._plesk_settings.ip

	@contextmanager
	def main_node_runner(self):
		if not self._plesk_settings.is_windows:
			with self._nested_main_node_ssh.runner() as runner:
				yield runner
		else:
			if self._plesk_settings.is_local:
				yield run_command.LocalWindowsRunner()
			else:
				yield self._get_windows_main_node_runner()

	@cached
	def _get_windows_main_node_runner(self):
		if self._plesk_settings.agent_settings.enabled:
			return run_command.WindowsAgentRunner(self._plesk_settings)
		else:
			global_section = ConfigSection(self.config, 'GLOBAL') 
			return run_command.WinexeRunner( 
				self._plesk_settings, 
				# XXX we should not read config file except for target
				# plesk options there
				local_temp_dir=global_section.get(
					'session-dir', 'migration-session'
				) 
			)

	def main_node_session_file_path(self, filename):
		return self._session_dir.get_file_path(filename)

	def main_node_description(self):
		return 'target Plesk server (%s)' % (self.main_node_ip,)

	@property
	def panel_admin_password(self):
		return self._plesk_settings.plesk_api.auth.password

	def plesk_api(self):
		return plesk_api.Client(
			self._plesk_settings.plesk_api.url,
			self._plesk_settings.plesk_api.auth.username,
			self._plesk_settings.plesk_api.auth.password,
			plesk_api.api_versions['11.5'],
			pretty_print=True
		)

	@property
	def unix_session_dir(self):
		return self._plesk_settings.unix_session_dir

	@property
	def windows_session_dir(self):
		return self._plesk_settings.windows_session_dir
	
	def check_connections(self):
		connection_checker = ConnectionChecker()
		connection_checker.check_target_plesk_api(self.plesk_api(), self.main_node_description())
		if not self._plesk_settings.is_windows:
			connection_checker.check_ssh(self.main_node_description(), self._plesk_settings)
		else:
			with self.main_node_runner() as runner:
				runner.check(self.main_node_description())

	@property
	def is_windows(self):
		return self._plesk_settings.is_windows

	@property
	def is_local(self):
		"""If main node of target server is local or remote

		Local server means that migrator works on the target node, remote means
		that migrator's node and target node are different servers
		"""
		return self._plesk_settings.is_local
