from parallels.combination.ppa_sn_to_ppa_sn import messages
import logging
from collections import namedtuple
import xml.etree.ElementTree as et

from parallels.core.utils.common import ip, format_list
from parallels.combination.ppa_sn_to_ppa_sn.ppa_data import SubscriptionNotFoundException

MoveList = namedtuple('MoveList', ('web', 'mail', 'db_mysql',))

logger = logging.getLogger(__name__)

def read_move_list(fileobj, ppa_data, db_mysql_hosts):
	"""Read move list from fileobj, return MoveList object, where:
- 'web' is a dict with keys - domain names and values - target service node IP
- 'mail' is a dict with keys - domain names and values - target service node IP
- 'db_mysql' is a dict with keys - domain names and values - target hostnames (not IPs)

Example of move list XML: 
<move>
	<domain name="test.tld">
		<web>10.58.1.1</web>
		<mail>10.58.1.3</mail>
		<db-mysql>localhost</db-mysql>
	</domain>
	<domain name="domain.tld">
		<web>10.58.1.2</web>
		<mail>10.58.1.4</mail>
		<db-mysql>192.168.1.1</db-mysql>
	</domain>
</move>
"""

	move_list = MoveList(web={}, mail = {}, db_mysql={})
	errors = []

	try:
		root_node = et.fromstring(fileobj.read())
	except Exception as err:
		logger.debug(u"Exception:", exc_info=err)
		errors.append(messages.FAILED_TO_READ_MOVE_LIST_FILE % (str(err),))
	else:
		for domain_xml_node in root_node:
			if domain_xml_node.tag == 'domain':
				domain_name = domain_xml_node.attrib.get('name')
				if domain_name is not None:
					if domain_name.strip() != '':
						for service_xml_node in domain_xml_node:
							if service_xml_node.tag == 'web':
								try:
									ppa_data.get_subscription_info(domain_name)
								except SubscriptionNotFoundException:
									errors.append(messages.WEB_SERVICE_OF_SUBSCRIPTION_DOES_NOT_EXIST % (domain_name,))
								else:
									target_ip = service_xml_node.text
									if target_ip is not None:
										if ip.is_ipv4(target_ip) or ip.is_ipv6(target_ip):
											move_list.web[domain_name] = target_ip
										else:
											errors.append(messages.WEB_SERVICE_NODE_IP_INVALID % (target_ip, domain_name,))
									else:
										errors.append(messages.TARGET_WEB_SERVICE_NODE_IP_NOT_SPECIFIED % (domain_name,))
							elif service_xml_node.tag == 'mail':
								try:
									ppa_data.get_subscription_info(domain_name)
								except SubscriptionNotFoundException:
									errors.append(messages.MAIL_SERVICE_DOES_NOT_EXIST % (domain_name,))
								else:
									target_ip = service_xml_node.text
									if target_ip is not None:
										if ip.is_ipv4(target_ip) or ip.is_ipv6(target_ip):
											move_list.mail[domain_name] = target_ip
										else:
											errors.append(messages.MAIL_SERVICE_NODE_IP_INVALID % (target_ip, domain_name,))
									else:
										errors.append(messages.MAIL_SERVICE_NODE_IP_NOT_SPECIFIED % (domain_name,))
							elif service_xml_node.tag == 'db-mysql':
								target_host = service_xml_node.text
								if target_host is not None and target_host.strip() != '':
									if target_host in db_mysql_hosts:
										move_list.db_mysql[domain_name] = service_xml_node.text
									else:
										errors.append(messages.MYSQL_DATABASE_SERVICE_HOST_NOT_EXIST % (target_host, format_list(db_mysql_hosts)))
								else:
									errors.append(messages.DATABASE_SERVICE_NODE_HOSTNAME_NOT_SPECIFIED % (domain_name,))
							else:
								errors.append("Unknown service to migrate: <%s>" % (service_xml_node.tag))
					else:
						errors.append(messages.ATTRIBUTE_NAME_OF_DOMAIN_NODE_CAN_NOT_BE_EMPTY)
				else:
					errors.append(messages.ATTRIBUTE_NAME_IS_NOT_SET)
			else:
				errors.append('Unknown node <%s>: expected <domain> node' % (domain_xml_node.tag,))

	return move_list, errors


def filter_move_list(move_list, subscriptions):
	return MoveList(
		web={subscription: ip for subscription, ip in move_list.web.iteritems() if subscription in subscriptions},
		mail={subscription: ip for subscription, ip in move_list.mail.iteritems() if subscription in subscriptions},
		db_mysql={subscription: host for subscription, host in move_list.db_mysql.iteritems() if subscription in subscriptions}
	)


