import logging

import parallels.hosting_check
from parallels.common import checking
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

logger = logging.getLogger(__name__)

class HostingObjectWebSubscription(HostingObjectSubscriptionBase):
	"""Source for hosting checks - subscription with web hosting"""
	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(HostingObjectWebSubscription, self).__init__(
			backup, subscription
		)
		self.create_migrated_subscription = create_migrated_subscription 

	def get_child_hosting_objects(self):
		"""Get child hosting objects (web domains) to check 
		
		Return: ChildHostingObjectsList which contains list of
		objects-subclasses of BaseHostingObject class
		"""
		subscription = self.create_migrated_subscription(
			self.subscription.name
		)

		result = ChildHostingObjectsList()
		if not subscription.converted_backup.is_enabled:
			logger.debug(
				u"Skipped checking the sites of the subscription %s "
				u"because this subscription is disabled" % 
				self.subscription.name
			)
			return result

		for domain in subscription.converted_backup.iter_domains():
			if subscription.is_fake and domain.name == subscription.name:
				continue
			result.child_hosting_objects.append(
				HostingObjectWebDomain(
					subscription, domain.name
				)
			)
		return result

class HostingObjectWebDomain(BaseHostingObject):
	"""Source for hosting checks - domain with web hosting
	
	Domain may be represented by main domain of subscription,
	addon domain or subdomain
	"""
	def __init__(self, subscription, domain_name):
		"""
		Arguments:
		- subscription - instance of MigrationSubscription
		- domain_name - name of domain to be checked (string)
		"""
		self.subscription = subscription
		self.name = domain_name

		if subscription.is_windows:
			self.type = u"IIS web site"
		else:
			self.type = u"Apache web site"

	def get_hosting_check_entities(self):
		result = HostingCheckEntitiesList()

		converted_domain = self.subscription.converted_backup.get_domain(
			self.name
		)
		raw_domain = self.subscription.raw_backup.get_domain(
			self.name
		)
		raw_subscription = self.subscription.raw_backup

		# if there is no site, do not check it
		if converted_domain.hosting_type == 'none':
			logger.debug(
				u"Skipped checking the sites of the domain %s"
				u" because it has no web hosting" % self.name
			)
			return result

		if not converted_domain.is_enabled:
			logger.debug(
				u"Skipped checking site %s of subscription %s"
				u" because this site is disabled" % (
					self.name, self.subscription.name
				)
			)
			return result

		if converted_domain.is_maintenance:
			logger.debug(
				u"Skipped checking site %s of subscription %s"
				u" because this site is in maintenance" % (
					self.name, self.subscription.name
				)
			)
			return result

		# retrieve src_ip 
		#(any) H-Sphere site may have different web IP than
		# the corresponding H-Sphere subscription has So, first try to use
		# site's ip address, and if it's not defined, use subscription's IP
		# address.
		src_ip = raw_domain.web_ips.v4 or raw_domain.web_ips.v6\
			 or raw_subscription.ip or raw_subscription.ipv6
		if src_ip is None:
			warnmsg = (
				u"The settings of the domain %s on the source server are " 
				u"inconsistent: web hosting is configured for this domain, "
				u"but the domain is not associated with an IP address." % (
					self.name
				)
			)
			logger.error(warnmsg)
			result.issues.append(checking.Issue(
				checking.Problem(
					'real_check_web_failure', checking.Problem.WARNING, warnmsg
				),
				u"Resolve the inconsistency on the source server."
			))
			return result

		web_ip = self.subscription.target_web_ip

		if web_ip:
			dst_ips = [ web_ip ]
		else:
			dst_ips = []
		if len(dst_ips) == 0:
			errmsg = (
				u"The target panel webspace %s is not associated with a web "
				u"IP address. Unable to check the site %s in the "
				u"target panel." % (
					self.subscription.name, self.name
				)
			)
			logger.error(errmsg)
			result.issues.append(checking.Issue(
				checking.Problem(
					'real_check_web_failure', checking.Problem.ERROR, errmsg
				),
				u"Make sure that web hosting is configured for this "
				u"webspace in the target panel."
			))
			return result

		# protocols
		protocols = [ 'http' ]
		if converted_domain.https_enabled:
			protocols.append('https')

		def get_domain_aps_urls(domain, protocol):
			urls = []
			for application in converted_domain.get_direct_aps_applications():
				application_domain_urls = \
					application.get_public_urls()
				urls.extend([
					domain_relative_url
					for aps_protocol, domain_relative_url 
					in application_domain_urls
					if aps_protocol == protocol
				])
			return urls

		web_target_server = self.subscription.web_target_server

		def _get_error_logs(domain_name):
			if web_target_server is not None \
					and not web_target_server.is_windows():
				server = web_target_server.get_hosting_server()
				return server.get_unix_vhost_error_log_files(domain_name)
			else:
				return None

		def _get_target_node_runner():
			if web_target_server is not None:
				return HostingCheckerRunnerAdapter(web_target_server.runner)
			else:
				return None

		for dst_ip in dst_ips:
			for protocol in protocols:
				result.hosting_check_entities.append(
					parallels.hosting_check.DomainWebService(
						domain_name=self.name, 
						web_server_ip=dst_ip, 
						protocol=protocol, 
						source_web_server_ip=src_ip, 
						aps_domain_relative_urls=get_domain_aps_urls(
							converted_domain, protocol
						),
						runner=_get_target_node_runner(),
						error_logs=_get_error_logs(self.name)
					)
				)
		return result
