#!/opt/panel-migrator-python/bin/python
# vim:filetype=python

import sys
import os.path
import argparse
import yaml
import logging
import logging.config
from xml.etree import ElementTree as et

# include all directories where migrator source code is located to sys.path
script_dir = os.path.dirname(__file__)
sys.path.extend(os.path.join(script_dir, name) for name in (
	'utils', 'common', 'hosting-check', 'plesks-migrator'
))

from parallels.common.hosting_check import \
	BaseHostingObject, BaseHostingCheckSource, \
	HostingCheckEntitiesList, ChildHostingObjectsList, \
	check_hosting_checks_source
from parallels.common.hosting_check.config import \
	HostingCheckersConfig

# Reporting
from parallels.common.checking import Report, Problem
from parallels.common.hosting_check.reporting import \
	print_backup_hosting_report
from parallels.common.utils import migrator_utils

# Entities
from parallels.hosting_check import \
	DomainWebService, DomainMailService, \
	DomainDNSService, DomainFTPService, \
	DomainRDPService, DomainSSHService

# Entities meta-information
from parallels.hosting_check.utils.entity_meta import \
	Entity, Property, \
	PropertyType, PropertyTypeString, \
	PropertyTypeList, PropertyTypeEntity

# Solutions
from parallels.utils import get_executable_file_name
from parallels.hosting_check import messages 

logger = logging.getLogger('parallels.utilities.hosting-checks-test-xml')

def main():
	set_up_logging()
	parser = argparse.ArgumentParser(
		description=\
			'Read information about checks from XML, perform '
			'post-migration checking and print report'
	)
	parser.add_argument(
		'--checks-xml-file', 
		required=True,
		help="Filename of XML to read information about checks from"
	)
	args = parser.parse_args()

	report = Report('Post-migration checks', None)

	util_name = get_executable_file_name()
	check_hosting_checks_source(
		HostingChecksXMLSource(args.checks_xml_file), 
		report, messages.get_solutions('plesk', util_name),
		HostingCheckersConfig(
			messages_delta_limit=5,
			external_dns_servers=[],
			save_external_report_data_function=None,
			dns_server_name='target DNS', 
			panel_file_id='target'
		)
	)
	print_backup_hosting_report(
		report,
		save_report_function=lambda contents: migrator_utils.save_report(
			contents, 'post-migration'
		)
	)

def set_up_logging():
	log_config=os.path.join(script_dir, "logging.config")
	if os.path.exists(log_config):
		with open(log_config) as f:
			logging.config.dictConfig(yaml.load(f))
	elif os.path.exists('/etc/panel-migrator/logging.config'):
		with open('/etc/panel-migrator/logging.config') as f:
			logging.config.dictConfig(yaml.load(f))
	logging.captureWarnings(True)

class HostingCheckXMLItem(BaseHostingObject):
	"""Item represents high-level object to be checked, e.g. subscription"""
	def __init__(self, node):
		self.node = node
		self.type = self.node.findtext('type')
		self.name = self.node.findtext('name')

	def get_hosting_check_entities(self):
		"""Iterate checks: HostingChecksXMLCheck"""
		result = HostingCheckEntitiesList()
		for checks_node in self.node.findall('checks'):
			for child in checks_node:
				result.hosting_check_entities.append(
					self._unserialize_check_node(child)
				)
		return result

	def get_child_hosting_objects(self):
		result = ChildHostingObjectsList()
		for child in self.node.findall('report'):
			result.child_hosting_objects.append(
				HostingCheckXMLItem(child)
			)
		return result

	@classmethod
	def _unserialize_check_node(cls, node):
		if node is None:
			return None

		types = {
			'domain-web-service': DomainWebService,
			'domain-mail-service': DomainMailService,
			'domain-ssh-service': DomainSSHService,
			'domain-rdp-service': DomainRDPService,
			'domain-ftp-service': DomainFTPService,
			'domain-dns-service': DomainDNSService,
		}

		entity_type = types[node.tag]
		return cls._unserialize_entity(node, PropertyTypeEntity(entity_type))

	@classmethod
	def _unserialize_entity(cls, node, property_type):
		props = {}
		for prop in property_type.entity_type.properties:
			prop_node = node.find(prop.name.replace('_', '-'))
			if prop_node is not None:
				props[prop.name] = cls._unserialize_type(prop_node, prop.type)
			else:
				props[prop.name] = prop.create_default()

		return property_type.entity_type(**props)

	@classmethod
	def _unserialize_type(cls, node, property_type):
		if type(property_type) == PropertyTypeString:
			return cls._unserialize_string(node)
		elif type(property_type) == PropertyTypeList:
			return cls._unserialize_list(node, property_type)
		elif type(property_type) == PropertyTypeEntity:
			return cls._unserialize_entity(node, property_type)

	@staticmethod
	def _unserialize_string(node):
		return node.text

	@classmethod
	def _unserialize_list(cls, node, list_property_type):
		hosting_objects = []
		for child_node in node:
			hosting_objects.append(
				cls._unserialize_type(
					child_node, list_property_type.item_property_type
				)
			)
		return hosting_objects

class HostingChecksXMLSource(BaseHostingCheckSource):
	"""Hosting checks XML represents whole XML"""
	def __init__(self, filename):
		with open(filename) as source:
			self.tree = et.ElementTree(file=source)

	def get_root_hosting_object(self):
		return HostingCheckXMLItem(self.tree.getroot().find('report'))

if __name__ == '__main__':
	main()
