from parallels.source_target_combination import messages

import os.path
import logging
import xml.etree.ElementTree as ElementTree

from parallels.common.utils import plesk_utils
from parallels.common.checking import Problem
from parallels.common.actions.base.common_action import CommonAction

logger = logging.getLogger(__name__)


class CheckCapabilityAction(CommonAction):
	def get_description(self):
		return messages.ACTION_CHECK_CAPABILITY_DESCRIPTION

	def get_failure_message(self, global_context):
		"""
		:type global_context: parallels.common.global_context.GlobalMigrationContext
		"""
		return messages.ACTION_CHECK_CAPABILITY_FAILURE

	def is_critical(self):
		"""If action is critical or not

		If action is critical and it failed, migration tool completely stops.
		Otherwise it proceeds to the next steps of migrations.

		:rtype: bool
		"""
		return False

	def run(self, global_context):
		"""
		:type global_context: parallels.common.global_context.GlobalMigrationContext
		"""
		common_issue_messages = set()
		for source_id in global_context.conn.get_source_plesks():
			capability_dump_path = global_context.session_files.get_path_to_capability_dump(source_id)
			capability_check_report_path = global_context.session_files.get_path_to_capability_check_report(source_id)
			if not os.path.exists(capability_dump_path):
				raise Exception('Unable to find capability dump %s' % capability_dump_path)
			plesk_utils.check_capability(
				global_context.conn.target.plesk_server,
				capability_dump_path,
				capability_check_report_path
			)
			if not os.path.exists(capability_check_report_path):
				raise Exception('Unable to find capability check report %s' % capability_check_report_path)
			report_tree = ElementTree.parse(capability_check_report_path)
			for message_node in report_tree.findall('.//message'):

				severity_node = message_node.find('severity')
				severity_string = severity_node.text if severity_node is not None else ''
				if severity_string == 'warning':
					severity = Problem.WARNING
				elif severity_string == 'error':
					severity = Problem.ERROR
				else:
					severity = Problem.INFO

				text_node = message_node.find('text')
				description = text_node.text if text_node is not None else None
				if description is None:
					continue

				resolution_text_node = message_node.find('resolutionDescription/text')
				solution = resolution_text_node.text if resolution_text_node is not None else None

				object_nodes = message_node.findall('objects-list/object')
				if len(object_nodes) == 0 and description not in common_issue_messages:
					# report common issue, not related to specific object
					global_context.pre_check_report.add_issue(
						Problem('capability_%s_%s' % (severity, source_id), severity, description),
						solution
					)
					common_issue_messages.add(description)
				else:
					for object_node in object_nodes:
						type_node = object_node.find('type')
						if type_node is None or type_node.text != 'domain':
							# skip all isses, not related to domains
							continue
						name_node = object_node.find('name')
						if name_node is None:
							continue
						subscription_name = name_node.text
						if not global_context.has_subscription(subscription_name):
							continue
						global_context.get_subscription(subscription_name).add_report_issue(
							global_context.pre_check_report,
							Problem('capability_%s_%s' % (severity, source_id), severity, description),
							solution
						)