import logging
import itertools

from parallels.common.hosting_check.entity_source.common import \
	HostingObjectSubscriptionBase
from parallels.common.hosting_check import \
	BaseHostingObject, ChildHostingObjectsList, HostingCheckEntitiesList

from parallels.common.hosting_check import DomainDNSService
from parallels.common.hosting_check import DomainDNSForwarding
from parallels.common.hosting_check import DomainDNSExternal
from parallels.common.hosting_check import DNSRecord

logger = logging.getLogger(__name__)

class HostingObjectDNSSubscription(HostingObjectSubscriptionBase):
	"""Source for hosting checks - subscription with DNS hosting
	
	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
	- skip_dns_forwarding_test - whether we should perform DNS forwarding test
	  or not
	"""
	def __init__(
		self, backup, subscription, create_migrated_subscription, 
		skip_dns_forwarding_test, skip_dns_external_test=False
	):
		super(HostingObjectDNSSubscription, self).__init__(
			backup, subscription
		)
		self.create_migrated_subscription = create_migrated_subscription
		self.skip_dns_forwarding_test = skip_dns_forwarding_test
		self.skip_dns_external_test = skip_dns_external_test

	def get_child_hosting_objects(self):
		"""Get child hosting objects (domains with DNS hosting) to check 
		
		Return: ChildHostingObjectsList which contains list of
		objects-subclasses of BaseHostingObject class
		"""
		result = ChildHostingObjectsList()

		subscription = self.create_migrated_subscription(
			self.subscription.name
		)

		converted_subscription = subscription.converted_backup
		for domain in itertools.chain(
			converted_subscription.iter_domains(),
			converted_subscription.iter_aliases()
		):
			result.child_hosting_objects.append(
				HostingObjectDNSDomain(
					subscription, domain, 
					self.skip_dns_forwarding_test,
					self.skip_dns_external_test
				)
			)
		return result

class HostingObjectDNSDomain(BaseHostingObject):
	"""Source for hosting checks - domain with mail hosting
	
	Domain may be represented by main domain of subscription or
	addon domain 

	Arguments:
	- subscription - instance of MigrationSubscription
	- domain_name - name of domain to be checked (string)
	- import_api - import API to communicate with target panel, instance of
	  common.import_api.ImportAPI
	- skip_dns_forwarding_test - whether we should perform DNS forwarding test
	  or not
	- skip_dns_forwarding_test - whether we should perform DNS test with
	  external DNS servers
	"""
	def __init__(
		self, subscription, domain, 
		skip_dns_forwarding_test, skip_dns_external_test
	):
		self.subscription = subscription
		self.domain = domain
		self.name = domain.name
		self.skip_dns_forwarding_test = skip_dns_forwarding_test
		self.skip_dns_external_test = skip_dns_external_test
		self.type = 'DNS zone'

	def get_hosting_check_entities(self):
		"""Return DNS zone services to be checked.

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

		source_dns_ips = self.subscription.source_dns_ips
		target_dns_ips = self.subscription.target_dns_ips
		
		if (
			self.domain.dns_zone is not None 
			and 
			self.domain.dns_zone.zone_type == 'slave'
		):
			logger.debug(
				"Skip checking of domain '%s' because it is in slave mode", self.name
			)
			return result

		if (
			self.domain.dns_zone is None 
			or 
			not self.domain.dns_zone.enabled
		):
			logger.debug(
				"Skip checking of domain '%s' because it has no DNS zone "
				"or DNS zone is disabled" % (
					self.name
				)
			)
			return result

		# DNS zone exists and it is in master mode
		records=[
			DNSRecord(rec_type=r.rec_type, src=r.src, dst=r.dst, opt=r.opt) 
			for r in self.domain.dns_zone.iter_dns_records() 
			if 
				# NS records are completely controlled by PPA, we do not
				# specify them in backup and don't know how they look like
				# after migration So, skip checking of all NS records
				r.rec_type.upper() != 'NS' and
				# We do not set up DNS forwarding for reverse zones as that has
				# no sense. So, skip checking all PTR records.
				r.rec_type.upper() != 'PTR'
		]

		result.hosting_check_entities.append(
			DomainDNSService(
				domain_name=self.domain.name,
				dns_records=records,
				dns_servers=target_dns_ips
			)
		)

		if len(target_dns_ips) > 0:
			if not self.skip_dns_forwarding_test:
				result.hosting_check_entities.append(
					DomainDNSForwarding(
						domain_name=self.domain.name,
						dns_records=records,
						source_dns_servers=source_dns_ips,
						target_dns_server=target_dns_ips[0]
					)
				)
			if not self.skip_dns_external_test:
				result.hosting_check_entities.append(
					DomainDNSExternal(
						domain_name=self.domain.name,
						dns_records=records,
						source_dns_servers=source_dns_ips,
						target_dns_servers=target_dns_ips
					)
				)

		return result
