from parallels.core import messages, MigrationNoContextError
import logging
import paramiko

from parallels.core.utils import ssh_utils
from parallels.plesk.utils.xml_rpc.plesk.core import PleskError
from parallels.plesk.utils.xml_rpc.plesk.operator import ServerOperator

logger = logging.getLogger(__name__)


class ConnectionChecker(object):
	def check(self, check_list):
		"""check_list contains items that should be checked here. Possible options are: ssh_auth, windows_auth."""
		for server, checks in check_list:
			server_options = server.node_settings
			if hasattr(server_options, "ssh_auth") and "ssh_auth" in checks: 
				self.check_ssh(server.description(), server_options)
			if hasattr(server_options, "windows_auth") and "windows_auth" in checks:
				with server.runner() as runner:
					runner.check(server.description())

	@staticmethod
	def check_ssh(server_name, server_options):
		logger.debug(messages.CHECK_SSH_CONNECTION_FOR_S_SERVER % server_name)
		try:
			with ssh_utils.connect(server_options) as ssh_client:
				ssh_client.get_transport().open_session()
		except paramiko.AuthenticationException:
			logger.debug(messages.LOG_EXCEPTION, exc_info=True)
			raise MigrationNoContextError(
				messages.UNABLE_LOGIN_S_SSH_SERVICE_DUE % (
					server_name
				)
			)
		except (paramiko.SSHException, EnvironmentError) as err:
			logger.debug(messages.LOG_EXCEPTION, exc_info=True)
			raise MigrationNoContextError(messages.CHECKER_FAILED_TO_CONNECT_BY_SSH % (server_name, err))
		except Exception as err:
			logger.debug(messages.LOG_EXCEPTION, exc_info=True)
			raise MigrationNoContextError(messages.CHECKER_FAILED_TO_CHECK_SSH_CONNECTION % (server_name, err))

	@staticmethod
	def check_plesk_api(plesk_server):
		"""
		:type plesk_server: parallels.core.connections.plesk_server.PleskServer
		"""
		logger.debug(messages.DEBUG_CHECK_API_CONNECTION % plesk_server.description())
		try:
			plesk_server.plesk_api().send(
				ServerOperator.Get([
					ServerOperator.Dataset.GEN_INFO
				])
			).data
		except PleskError as e:
			logger.debug(messages.LOG_EXCEPTION, exc_info=True)
			if e.code == 1001:
				raise PleskConnectionCheckError(
					messages.FAILED_TO_CHECK_PLESK_API_INVALID_CREDENTIALS.format(
						server=plesk_server.description()
					)
				)
			elif e.code == 1030:
				raise PleskConnectionCheckError(
					messages.FAILED_TO_CHECK_PLESK_API_EXPIRED_LICENSE.format(
						server=plesk_server.description()
					)
				)
			else:
				raise PleskConnectionCheckError(
					messages.FAILED_TO_CONNECT_BY_PLESK_API.format(
						server=plesk_server.description(), error=unicode(e)
					)
				)
		except EnvironmentError as e:
			logger.debug(messages.LOG_EXCEPTION, exc_info=True)
			raise PleskConnectionCheckError(
				messages.FAILED_TO_CONNECT_BY_PLESK_API.format(
					server=plesk_server.description(), error=unicode(e)
				)
			)
		except Exception as e:
			logger.debug(messages.LOG_EXCEPTION, exc_info=True)
			raise PleskConnectionCheckError(
				messages.FAILED_TO_CHECK_PLESK_API_CONNECTION.format(
					server=plesk_server.description(), error=unicode(e)
				)
			)


class PleskConnectionCheckError(MigrationNoContextError):
	pass