from parallels.core import messages
import logging
import paramiko

from parallels.api.plesk.core import PleskError
from parallels.api import plesk as plesk_api
from parallels.core.utils import ssh_utils
from parallels.core import MigrationError

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, plesk_api, 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, "plesk_api") and "plesk_api" in checks:
				self.check_plesk_api(server.description(), server_options)
			if hasattr(server_options, "windows_auth") and "windows_auth" in checks:
				with server.runner() as runner:
					runner.check(server.description())

	def check_ssh(self, 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 as e:
			logger.debug(u'Exception:', exc_info=e)
			raise MigrationError(
				messages.UNABLE_LOGIN_S_SSH_SERVICE_DUE % (
					server_name
				)
			)
		except (paramiko.SSHException, EnvironmentError) as err:
			logger.debug(u"Exception:", exc_info=err)
			raise MigrationError(
				u"Failed to connect to %s by SSH: %s"
				% (server_name, err)
			)
		except Exception as err:
			logger.debug(u"Exception:", exc_info=err)
			raise MigrationError(
				u"Failed to check SSH connection to %s: %s"
				% (server_name, err)
			)

	def check_target_plesk_api(self, node_plesk_api, node_description):
		logger.debug(u"Check %s API connection", node_description)
		try:
			node_plesk_api.send(plesk_api.operator.ServerOperator.Get([
				plesk_api.operator.ServerOperator.Dataset.GEN_INFO
			])).data
		except (PleskError, EnvironmentError) as err:
			logger.debug(u"Exception:", exc_info=err)
			raise MigrationError(
				u"Failed to connect to %s Plesk API to '%s' url: %s"
				% (node_description, node_plesk_api.url, err)
			)
		except Exception as err:
			logger.debug(u"Exception:", exc_info=err)
			raise MigrationError(
				u"Failed to check %s Plesk API at '%s': %s"
				% (node_description, node_plesk_api.url, err)
			)

	def check_plesk_api(self, server_name, server_options):
		logger.debug(u"Check API connection for %s." % server_name)
		try:
			plesk_api.Client(
				server_options.plesk_api.url,
				server_options.plesk_api.auth.username,
				server_options.plesk_api.auth.password,
				'1.5.2.1',
				pretty_print=True
			).send(
				plesk_api.operator.ServerOperator.Get([
					plesk_api.operator.ServerOperator.Dataset.GEN_INFO
			])).data
		except PleskError as e:
			logger.debug(u"Exception:", exc_info=e)
			if e.code == 1001:
				raise PleskConnectionCheckError(
					messages.UNABLE_LOGIN_PLESK_API_SERVICE_DUE % server_options.id
				)
			if e.code == 1030:
				raise PleskConnectionCheckError(
					messages.LICENSE_KEY_EXPIRED_SOURCE_PLESK_SERVER % (
						server_options.id, server_options.ip
					)
				)
			raise
		except (PleskError, EnvironmentError) as err:
			logger.debug(u"Exception:", exc_info=err)
			raise MigrationError(
				u"Failed to connect to Plesk to '%s' url: %s"
				% (server_options.plesk_api.url, err)
			)
		except Exception as err:
			logger.debug(u"Exception:", exc_info=err)
			raise MigrationError(
				u"Failed to check Plesk API at '%s': %s"
				% (server_options.plesk_api.url, err)
			)

class PleskConnectionCheckError(MigrationError):
	pass

