import logging

from parallels.hosting_check import *
from parallels.common import checking

from parallels.hosting_check.checkers.service_checker \
	import ServiceChecker
from parallels.hosting_check.checkers.mssql_database_checker \
	import MSSQLDatabaseChecker
from parallels.hosting_check.checkers.mysql_database_checker \
	import MySQLDatabaseChecker
from parallels.hosting_check.checkers.postgresql_database_checker \
	import PostgreSQLDatabaseChecker
from parallels.hosting_check.checkers.website_availability_checker \
	import WebsiteAvailabilityChecker
from parallels.hosting_check.checkers.ftp_auth_checker \
	import FTPAuthChecker
from parallels.hosting_check.checkers.ssh_auth_checker \
	import SSHAuthChecker
from parallels.hosting_check.checkers.rdp_auth_checker \
	import RDPAuthChecker
from parallels.hosting_check.checkers.mail_auth_checker \
	import MailAuthChecker
from parallels.hosting_check.checkers.dns_checker \
	import DNSChecker
from parallels.hosting_check.checkers.dns_external_checker \
	import DNSExternalChecker
from parallels.hosting_check.checkers.dns_forwarding_checker \
	import DNSForwardingChecker

logger = logging.getLogger(__name__)


class BaseHostingObject(object):
	"""BaseHostingObject represents and abtraction of a checked hosting object

	It could be: server, client, reseller, subscription, domain, web service,
	mail service, DNS service, and so on.
	
	It could contain:
	1) Several hosting check entities. For example, domain's web service
	may have DomainWebService entity to check.

	Examples of hosting entities to check: 
	- hosting_check.DomainWebService
	- hosting_check.DomainDNSService
	- hosting_check.DomainMailService
	- hosting_check.DomainFTPService

	2) Several child hosting objects. For example, client may have several
	subscriptions, subscription may have several domains, 
	domain may have mail service, web service, and so on.
	"""
	def get_hosting_check_entities(self):
		"""Get hosting entities to check for this item. 
		
		Return: HostingCheckEntitiesList"""
		return HostingCheckEntitiesList()

	def get_child_hosting_objects(self):
		"""Get child hosting objects - subclasses of BaseHostingObject class
		
		Return: ChildHostingObjectsList"""
		return ChildHostingObjectsList()

	def _check_web_ip(self, result):
		if not self.subscription.target_web_ip:
			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 False
		return True


class HostingCheckEntitiesList(object):
	"""
	Properties:
	- hosting_check_entities - list of entities to check
	- issues - list of issues that happened when listing entities to check
	"""
	def __init__(self, hosting_check_entities=None):
		if hosting_check_entities is None:
			self.hosting_check_entities = []
		else:
			self.hosting_check_entities = hosting_check_entities

		self.issues = []

	def __repr__(self):
		return (
			'HostingCheckEntitiesList'
			'(hosting_check_entities=%r, issues=%r)' % (
				self.hosting_check_entities, self.issues
			)
		)


class ChildHostingObjectsList(object):
	"""
	Properties:
	- child_hosting_objects - child hosting objects of this hosting object
	- issues - issues that happend when listing child hosting objects
	"""
	def __init__(self, child_hosting_objects=None):
		if child_hosting_objects is None:
			self.child_hosting_objects = []
		else:
			self.child_hosting_objects = child_hosting_objects
		self.issues = []

	def __repr__(self):
		return (
			'ChildHostingObjectsList'
			'(child_hosting_objects=%r, issues=%r)' % (
				self.child_hosting_objects, self.issues
			)
		)


class BaseHostingCheckSource(object):
	"""Source of items (check entities and hosting objects hierarchy) to check.
	
	Possible implementations: Plesk backup (read info about domains from 
	Plesk backup), XML or JSON
	"""
	def get_root_hosting_object(self):
		"""Get root item to check - instance of BaseHostingObject"""
		raise NotImplementedError()


def check_hosting_checks_source(source, report, solutions, config):
	"""Perform checks on a checks source and compose a report

	Arguments:
	- source - source of checks and objects hierarchy
	instance of BaseHostingCheckSource
	- report - Report object to put found issues to
	- solutions - dictionary with key - issue id, value - solution text
	issue id could be found at hosting_check.*Issue*Type
	- config - instance of HostingCheckersConfig, global configuration of 
	the checkers
	"""
	_check_hosting_object(
		source.get_root_hosting_object(), report, solutions, 
		_create_checkers(config) 
	)


def _check_hosting_object(hosting_object, report, solutions, checkers):
	if hosting_object.type is not None:
		if hosting_object.name is not None:
			logger.info("Checking: %s %s", hosting_object.type, hosting_object.name)
		else:
			logger.info("Checking: %s", hosting_object.type)

	for child_hosting_object in \
		hosting_object.get_child_hosting_objects().child_hosting_objects:
			subreport = report.subtarget(
				child_hosting_object.type, 
				child_hosting_object.name
			)
			_check_hosting_object(
				child_hosting_object, subreport, solutions, checkers
			)

	get_hosting_check_entities_result = \
		hosting_object.get_hosting_check_entities()
	for hosting_check_entity in \
			get_hosting_check_entities_result.hosting_check_entities:
		try:
			checker = checkers[type(hosting_check_entity)]
			issues = checker.check([hosting_check_entity])

			for issue in issues:
				report.add_issue(
					checking.Problem(issue.category, issue.severity, issue.problem),
					solutions.get(issue.category, '')
				)
		except Exception as e:
			logger.debug("Exception: ", exc_info=True)
			report.add_issue(
				checking.Problem('generic-internal-error', 'error', 'Generic internal error: %s' % e),
				''
			)

	for issue in get_hosting_check_entities_result.issues:
		report.add_issue_obj(issue)


def _create_checkers(config):
	return {
		Service: ServiceChecker(),
		DomainMySQLDatabases: MySQLDatabaseChecker(),
		DomainMSSQLDatabases: MSSQLDatabaseChecker(),
		DomainPostgreSQLDatabases: PostgreSQLDatabaseChecker(),
		DomainWebService: WebsiteAvailabilityChecker(config.website_availability_check_timeout),
		DomainFTPService: FTPAuthChecker(),
		DomainSSHService: SSHAuthChecker(),
		DomainRDPService: RDPAuthChecker(),
		DomainMailService: MailAuthChecker(config.messages_delta_limit),
		DomainDNSService: DNSChecker(
			save_external_report_data_function=\
				config.save_external_report_data_function,
			dns_server_name=\
				config.dns_server_name,
			difference_file_panel_id=config.panel_file_id
		),
		DomainDNSForwarding: DNSForwardingChecker(
			save_external_report_data_function=\
				config.save_external_report_data_function,
		),
		DomainDNSExternal: DNSExternalChecker(
			external_dns_servers=config.external_dns_servers,
			save_external_report_data_function=\
				config.save_external_report_data_function,
		),
	}
