import logging
from collections import namedtuple

from parallels.core.hosting_check import ChildHostingObjectsList, \
	BaseHostingCheckSource, BaseHostingObject, HostingCheckEntitiesList
from parallels.core.hosting_check.utils.runner_adapter import \
	HostingCheckerRunnerAdapter
from parallels.hosting_check.panel_services import \
	LinuxWebServiceBase, LinuxFTPService, LinuxDNSService, LinuxMailServiceBase, \
	LinuxMysqlService, LinuxPostgresqlService, WindowsWebServiceBase, \
	WindowsFTPServiceBase, WindowsDNSService, WindowsMailServiceBase, \
	WindowsMysqlService, WindowsMssqlServiceBase, \
	create_windows_plesk_service, create_linux_plesk_service
from parallels.core.utils.common import cached
from parallels.hosting_check import Service

TargetServiceInfo = namedtuple('TargetServiceInfo', (
	'service_type',
	'node'
))

logger = logging.getLogger(__name__)

LinuxDBServices = {
	'mysql': LinuxMysqlService,
	'postgresql': LinuxPostgresqlService
}

WindowsDBServices = {
	'mysql': WindowsMysqlService,
	'mssql': WindowsMssqlServiceBase
}


class ServiceCheckSource(BaseHostingCheckSource):
	"""Source for service hosting checks

	Arguments:
	- target_services - list of TargetServiceInfo
	- main_node - object of class TargetConnections
	"""
	def __init__(
		self, target_services, main_node
	):
		self.service_nodes = self._get_service_nodes_to_check(
			target_services, main_node
		)

	def _get_service_nodes_to_check(
		self, target_services, main_node
	):
		def _add_service_node(service_nodes, service_node):
			for _service_node in service_nodes:
				if service_node.description == _service_node.description and \
					service_node.service == _service_node.service:
					return
			service_nodes.append(service_node)

		service_nodes = []
		for target_service in target_services:
			if target_service.service_type == 'web':
				web_service = WindowsWebServiceBase if target_service.node.is_windows() else LinuxWebServiceBase
				_add_service_node(
					service_nodes,
					Service(
						host=target_service.node.ip(),
						description=target_service.node.description(),
						runner=self._get_node_runner(target_service.node),
						service=web_service
					)
				)

				ftp_service = WindowsFTPServiceBase if target_service.node.is_windows() else LinuxFTPService
				_add_service_node(
					service_nodes,
					Service(
						host=target_service.node.ip(),
						description=target_service.node.description(),
						runner=self._get_node_runner(target_service.node),
						service=ftp_service
					)
				)
			elif target_service.service_type == 'mail':
				mail_service = WindowsMailServiceBase if target_service.node.is_windows() else LinuxMailServiceBase
				_add_service_node(
					service_nodes,
					Service(
						host=target_service.node.ip(),
						description=target_service.node.description(),
						runner=self._get_node_runner(target_service.node),
						service=mail_service
					)
				)
			elif target_service.service_type == 'dns':
				dns_service = WindowsDNSService if target_service.node.is_windows() else LinuxDNSService
				_add_service_node(
					service_nodes,
					Service(
						host=target_service.node.ip(),
						description=target_service.node.description(),
						runner=self._get_node_runner(target_service.node),
						service=dns_service
					)
				)
			else:
				db_services = WindowsDBServices if target_service.node.is_windows() else LinuxDBServices
				for db_type, db_service in db_services.iteritems():
					if target_service.service_type == db_type:
						_add_service_node(
							service_nodes,
							Service(
								host=target_service.node.ip(),
								description=target_service.node.description(),
								runner=self._get_node_runner(target_service.node),
								service=db_service
							)
						)

		if main_node.is_windows:
			plesk_service = create_windows_plesk_service(main_node.panel_port)
		else:
			plesk_service = create_linux_plesk_service(main_node.panel_port)

		_add_service_node(
			service_nodes,
			Service(
				host=main_node.main_node_ip,
				description=main_node.main_node_description(),
				runner=self._get_node_runner(main_node.plesk_server),
				service=plesk_service
			)
		)
		return service_nodes

	def get_root_hosting_object(self):
		return HostingObjectServices(self.service_nodes)

	@cached
	def _get_node_runner(self, server):
		return HostingCheckerRunnerAdapter(server.runner)


class HostingObjectServices(BaseHostingObject):
	"""Source for service hosting checks
	
	Arguments:
	- service_nodes - List of ServiceNodeInfo
	"""
	def __init__(self, service_nodes):
		self.type = 'Services'
		self.name = None
		self.service_nodes = service_nodes

	def get_child_hosting_objects(self):
		"""Child hosting objects: client's subscriptions"""
		result = ChildHostingObjectsList()
		for service_node in self.service_nodes:
			result.child_hosting_objects.append(
				HostingObjectService(
					service_node
				)
			)
		return result


class HostingObjectService(BaseHostingObject):
	"""Source for service hosting checks
	
	Arguments:
	- service_node - ServiceNodeInfo
	"""
	def __init__(
		self, service_node
	):
		self.type = 'Service'
		self.name = '%s on %s' % (service_node.service.type, service_node.description)
		self.service_node = service_node

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

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

		result.hosting_check_entities.append(
			self.service_node
		)

		return result
