import logging
from parallels.hosting_check.utils.dns_utils import \
	DnsRequestTimeoutException, get_difference_between_dns_servers, \
	get_authoritative_dns_servers

from parallels.hosting_check.utils.text_utils import format_list
from parallels.hosting_check import DomainIssue, Severity
from parallels.hosting_check import  DNSExternalIssueType as IT

from parallels.hosting_check.messages import MSG

logger = logging.getLogger(__name__)

class DNSExternalChecker(object):
	def __init__(
		self, external_dns_servers, max_difference_lines=3, 
		save_external_report_data_function=None
	):
		self.external_dns_servers = external_dns_servers
		self.max_difference_lines = max_difference_lines
		self.save_external_report_data_function = \
			save_external_report_data_function

	def check(self, domains_to_check, ):
		issues = []

		for domain_to_check in domains_to_check:
			for external_dns_server_ip in self.external_dns_servers:
				self._check_single_external_server(
					domain_to_check, external_dns_server_ip, issues
				)

		return issues

	def _check_single_external_server(
		self, domain_to_check, external_dns_server_ip, issues
	):
		def add_issue(severity, category, problem):
			issues.append(
				DomainIssue(
					domain_name=domain_to_check.domain_name, 
					severity=severity, 
					category=category, problem=problem
				)
			)

		logger.info(
			MSG(
				'dns_external_log_checking',
				server_ip=external_dns_server_ip
			)
		)
		try:
			dns_servers = get_authoritative_dns_servers(
				domain_to_check.domain_name, external_dns_server_ip
			)
			if len(dns_servers) == 0:
				add_issue(
					Severity.INFO, IT.NOT_REGISTERED,
					MSG(IT.NOT_REGISTERED)
				)
			else:
				unknown_dns_servers = [
					dns_server 
					for dns_server in dns_servers
					if len(dns_server.ips) == 0
				]
				if len(unknown_dns_servers) > 0:
					add_issue(
						Severity.INFO,
						IT.SERVED_BY_UNKNOWN_DNS_SERVERS,
						MSG(
							IT.SERVED_BY_UNKNOWN_DNS_SERVERS,
							dns_servers_list=format_list([
								dns_server.hostname 
								for dns_server in unknown_dns_servers
							])
						)
					)
				else:
					dns_server_ips = set(
						sum([dns_server.ips for dns_server in dns_servers], [])
					)
					target_dns_server_ips = set(
						domain_to_check.target_dns_servers
					)
					source_panel_dns_server_ips = set(
						domain_to_check.source_dns_servers
					)
					if (
						dns_server_ips 
						<= 
						target_dns_server_ips | source_panel_dns_server_ips
					):
						difference = get_difference_between_dns_servers(
							domain_to_check.dns_records, 
							domain_to_check.target_dns_servers[0], 
							external_dns_server_ip
						)

						if len(difference) > 0:
							self._report_difference(
								domain_to_check, external_dns_server_ip, 
								difference, issues
							)
					else:
						add_issue(
							Severity.INFO,
							IT.NOT_SERVED_BY_SOURCE_OR_TARGET,
							MSG(
								IT.NOT_SERVED_BY_SOURCE_OR_TARGET
							)
						)
		except DnsRequestTimeoutException, e:
			logger.debug(u"Exception:", exc_info=e)
			# do not show any report comparing records - just a timeout message
			add_issue(
				Severity.WARNING,
				IT.DNS_SERVER_TIMEOUT,
				MSG(
					IT.DNS_SERVER_TIMEOUT,
					external_dns_server_ip=e.server_ip
				)
			)
		except Exception, e:
			logger.debug(u"Exception:", exc_info=e)
			# do not show any report comparing records - just a general failure
			# message
			add_issue(
				Severity.WARNING,
				IT.INTERNAL_ERROR, 
				MSG(
					IT.INTERNAL_ERROR,
					reason=str(e),
					external_dns_server_ip=external_dns_server_ip
				)
			)

	def _report_difference(
		self, domain_to_check, external_dns_server_ip, difference, issues
	):
		if (
			len(difference) <= self.max_difference_lines 
			or 
			self.save_external_report_data_function is None
		): 
			# put all differences to screen immediately
			difference_str = MSG(
				'dns_difference_full',
				difference=u"\n".join(difference)
			)
		else:
			# put first 3 differences to screen as an example, put all other
			# differences into a separate file
			filename = self.save_external_report_data_function(
				"dns.external.difference.%s" % (domain_to_check.domain_name), 
				MSG(
					'dns_external_difference_file',
					external_dns_server_ip=external_dns_server_ip,
					target_dns_server_ip=domain_to_check.target_dns_servers[0],
					difference=u"\n".join(difference)
				)
			)
			difference_str = MSG(
				'dns_external_difference_example',
				difference=u"\n".join(difference[:3]),
				filename=filename
			)

		issues.append(
			DomainIssue(
				domain_name=domain_to_check.domain_name,
				severity=Severity.WARNING,
				category=IT.DIFFERENT_RECORDS,
				problem=MSG(
					IT.DIFFERENT_RECORDS,
					external_dns_server_ip=external_dns_server_ip, 
					target_dns_server_ip=domain_to_check.target_dns_servers[0],
					difference=difference_str
				)
			)
		)
