# Domain service types
from parallels.hosting_check import DomainFTPService
from parallels.hosting_check import DomainSSHService
from parallels.hosting_check import DomainRDPService

# Common types
from parallels.hosting_check import User

# Hosting checks source
from parallels.common.hosting_check.entity_source.common import \
	HostingObjectSubscriptionBase
from parallels.common.hosting_check import \
	BaseHostingObject, ChildHostingObjectsList, HostingCheckEntitiesList
from parallels.common.hosting_check.utils.runner_adapter import \
	HostingCheckerRunnerAdapter


class HostingObjectSubscriptionWithUsers(HostingObjectSubscriptionBase):
	"""Source for hosting checks - subscription with its users"""
	def __init__(self, backup, subscription, create_migrated_subscription):
		"""
		Arguments:
		- backup - source backup instance
		(parallels.common.plesk_backup.plesk_backup_xml.PleskBackupSource*
		- subscription - subscription from backup
		(parallels.common.plesk_backup.model.Subscription*)
		- create_migrated_subscription - function that can create instances of
		common.migrated_subscription.MigrationSubscription
		"""
		super(HostingObjectSubscriptionWithUsers, self).__init__(
			backup, subscription
		)
		self.create_migrated_subscription = create_migrated_subscription 

	def get_child_hosting_objects(self):
		"""Get child hosting objects (FTP/SSH/RDP services) to check 
		
		Return: ChildHostingObjectsList which contains list of
		objects-subclasses of BaseHostingObject class
		"""
		subscription = self.create_migrated_subscription(
			self.subscription.name
		)
		result = ChildHostingObjectsList()
		result.child_hosting_objects.append(
			HostingObjectFTPService(subscription)
		)
		if subscription.is_windows:
			result.child_hosting_objects.append(
				HostingObjectRDPService(subscription)
			)
		else:
			result.child_hosting_objects.append(
				HostingObjectSSHService(subscription)
			)
		return result


class HostingObjectFTPService(BaseHostingObject):
	"""Source for hosting checks - FTP service with FTP users"""
	def __init__(self, subscription):
		"""Arguments:
		- subscription - instance of MigrationSubscription
		"""
		self.subscription = subscription
		self.name = subscription.name
		self.type = 'FTP service'

	def get_hosting_check_entities(self):
		"""Return a list of FTP accounts to be checked.

		Returns: an object of type 'HostingCheckEntitiesList'
		"""
		if self.subscription.converted_backup.hosting_type == 'none':
			# If there is no web hosting then there are no FTP users, so
			# nothing to check
			return HostingCheckEntitiesList([])

		subscription_disabled = _is_subscription_login_disabled(
			self.subscription.converted_backup
		)

		service = DomainFTPService(
			domain_name=self.subscription.name, 
			web_server_ip=self.subscription.target_web_ip,
			users=[],
			inactive_users=[]
		)

		users = [
			User(login, password, password_type)
			for login, password, password_type in _iter_all_sysusers_info(
				self.subscription.converted_backup
			)
		]
		# Skip checking Windows for inactive user because of a bug - users of
		# suspended subscriptions still can login over FTP
		if subscription_disabled and not self.subscription.is_windows:
			service.inactive_users.extend(users)
		elif not subscription_disabled:
			service.users.extend(users)

		return HostingCheckEntitiesList([service])


class HostingObjectSSHService(BaseHostingObject):
	"""Source for hosting checks - SSH service with SSH users"""
	def __init__(self, subscription):
		"""Arguments:
		- subscription - instance of MigrationSubscription
		"""
		self.subscription = subscription
		self.name = subscription.name
		self.type = 'SSH service'

	def get_hosting_check_entities(self):
		"""Return a list of SSH accounts to be checked.

		Returns: an object of type 'HostingCheckEntitiesList'
		"""
		sysuser = self.subscription.converted_backup.get_phosting_sysuser()
		login, password, password_type = _get_main_sysuser_info(
			self.subscription.converted_backup
		)
		
		if login is None or password is None:
			# If there is no system user (for example, web hosting is disabled
			# for the subscription), or we can not use password (for example it
			# is not set, or it is encrypted)
			return HostingCheckEntitiesList()

		service = DomainSSHService(
			domain_name=self.subscription.name, 
			web_server_ip=self.subscription.target_web_ip,
			users=[],
			inactive_users=[]
		)
		user = User(login, password, password_type)
		if (
			not _is_subscription_login_disabled(self.subscription.converted_backup)
			and 
			sysuser.has_shell_access
		):
			service.users.append(user)
		else:
			service.inactive_users.append(user)

		return HostingCheckEntitiesList([service])


class HostingObjectRDPService(BaseHostingObject):
	"""Source for hosting checks - RDP service with RDP users"""
	def __init__(self, subscription):
		"""Arguments:
		- subscription - instance of MigrationSubscription
		"""
		self.subscription = subscription
		self.name = subscription.name
		self.type = 'RDP service'

	def get_hosting_check_entities(self):
		"""Return a list of RDP accounts to be checked.

		Returns: an object of type 'HostingCheckEntitiesList'
		"""
		result = HostingCheckEntitiesList()

		if not self._check_web_ip(result):
			return result

		sysuser = self.subscription.converted_backup.get_phosting_sysuser()
		login, password, _ = _get_main_sysuser_info(self.subscription.converted_backup)
		
		if login is None or password is None:
			# If there is no system user (for example, web hosting is disabled
			# for the subscription), or we can not use password (for example it
			# is not set, or it is encrypted)
			return result

		web_target_server = self.subscription.web_target_server
		if web_target_server is not None:
			runner = HostingCheckerRunnerAdapter(web_target_server.runner)
		else:
			runner = None

		service = DomainRDPService(
			domain_name=self.subscription.name, 
			web_server_ip=self.subscription.target_web_ip,
			users=[],
			inactive_users=[],
			runner=runner,
		)
		user = User(login, password)
		if sysuser.has_shell_access:
			service.users.append(user)
		else:
			service.inactive_users.append(user)
		result.hosting_check_entities.append(service)

		return result


def _is_subscription_login_disabled(subscription):
	"""Return True if login to subscription is enabled, False otherwise"""
	return not subscription.is_enabled and not subscription.is_in_maintenance_mode


def _iter_all_sysusers_info(subscription):
	"""Iterate through tuples (login, password) of all system users"""
	for user in subscription.iter_system_users():
		yield _get_sysuser_info(user)


def _get_main_sysuser_info(subscription):
	"""Return tuple (login, password) of main system user"""
	return _get_sysuser_info(subscription.get_phosting_sysuser())


def _get_sysuser_info(sysuser):
	"""Return tuple (login, password, pasword type) of specified system user"""
	if sysuser is None:
		return None, None, None
	if sysuser.name is None or sysuser.name == '':
		return None, None, None

	return sysuser.name, sysuser.password.text, sysuser.password.type
