from collections import namedtuple

from parallels.core.utils.common.xml import seq, elem, text_elem
from parallels.core.utils.common import if_not_none
from .. import core
from .dns import DnsZone, Soa

OBJECT_TYPE_DOMAIN = 'domain'
OBJECT_TYPE_ALIAS = 'alias'

MasterServerRecord = namedtuple('MasterServerRecord', ('id', 'ip_address', 'domain_id', 'domain_alias_id'))
EnableResult = namedtuple('EnableResult', ('domain_id', 'domain_alias_id'))
DisableResult = namedtuple('DisableResult', ('domain_id', 'domain_alias_id'))


class DnsOperator9(object):
	class Dataset(object):
		SOA = 'soa'
		values = [SOA]

	FilterAll = core.FilterAll
	FilterById =  core.declare_filter('FilterById', 'id')
	FilterByDomainId = core.declare_filter('FilterByDomainId', 'domain_id')
	FilterByDomainAliasId = core.declare_filter('FilterByDomainId', 'domain_alias_id')

	class Set(core.operation_with_filter('Set', ('soa',))):
		operator_name = 'dns'
		operation_name = 'set'
		# The doc says "API RPC version: all versions". Assume 8.0.1 and later
		min_api_version = '1.4.1.2'
		max_api_version = '1.6.5.0'

		def data_xml(self):
			return seq(
				elem('soa', [
					text_elem(k, getattr(self.soa, k))
					for k in ('ttl', 'refresh', 'retry', 'expire', 'minimum')
					if getattr(self.soa, k) is not None
				])
			)

		@classmethod
		def parse(cls, elem):
			return [core.Result.parse(r) for r in elem.findall('result')]

	class Get(core.operation_with_filter('Get', ('soa',))):
		operator_name = 'dns'
		operation_name = 'get'
		min_api_version = '1.4.1.2'
		max_api_version = '1.6.5.0'

		def data_xml(self):
			return seq(
				elem('soa') if self.soa else None
			)

		@classmethod
		def parse(cls, elem):
			return [core.Result.parse(r, cls._parse_data) for r in elem.findall('result')]

		@classmethod
		def _parse_data(cls, elem):
			domain_id = elem.findtext('domain_id')
			if domain_id is not None:
				object_id = int(domain_id)
				object_type = OBJECT_TYPE_DOMAIN
			else:
				object_type = OBJECT_TYPE_ALIAS
				domain_alias_id = elem.findtext('domain_alias_id')
				object_id = int(domain_alias_id)
			if elem.findtext('soa') is not None:
				soa = Soa(
					ttl=int(elem.findtext('soa/ttl')),
					refresh=int(elem.findtext('soa/refresh')),
					retry=int(elem.findtext('soa/retry')),
					expire=int(elem.findtext('soa/expire')),
					minimum=int(elem.findtext('soa/minimum'))
				)
			else:
				soa = None

			return DnsZone(
				object_id=object_id,
				object_type=object_type,
				soa=soa
			)

	class Switch(core.operation_with_filter('Switch', ('zone_type',))):
		operator_name = 'dns'
		operation_name = 'switch'
		min_api_version = '1.4.0.0'
		max_api_version = '1.6.5.0'

		def data_xml(self):
			return [
				text_elem('zone_type', self.zone_type)
			]

		@classmethod
		def parse(cls, elem):
			return [core.Result.parse(r, cls._parse_data) for r in elem.findall('result')]

		@classmethod
		def _parse_data(cls, elem):
			return None

	class GetMasterServer(core.operation_with_filter('GetMasterServer', ())):
		operator_name = 'dns'
		operation_name = 'get_master_server'
		min_api_version = '1.4.0.0'
		max_api_version = '1.6.2.9'     # less than 1.6.3.0

		@classmethod
		def parse(cls, elem):
			return core.parse_result_set(elem, cls._parse_data, 'id')

		@classmethod
		def _parse_data(cls, elem):
			return MasterServerRecord(
				id=int(elem.findtext('id')),
				ip_address=elem.findtext('ip_address'),
				domain_id=if_not_none(elem.findtext('domain_id'), int),
				domain_alias_id=if_not_none(elem.findtext('domain_alias_id'), int)
			)

	class AddMasterServer(core.operation('AddMasterServer', ('target', 'ip_address',))):
		operator_name = 'dns'
		operation_name = 'add_master_server'
		min_api_version = '1.4.0.0'
		max_api_version = '1.6.2.9'	 # less than 1.6.3.0

		class TargetDomainId(namedtuple('TargetDomainId', ('id',))):
			def inner_xml(self):
				return [text_elem('domain_id', self.id)]

		class TargetDomainAliasId(namedtuple('TargetDomainAliasId', ('id',))):
			def inner_xml(self):
				return [text_elem('domain_alias_id', self.id)]

		def inner_xml(self):
			return self.target.inner_xml() + seq(
				text_elem('ip_address', self.ip_address),
			)

		@classmethod
		def parse(cls, elem):
			return [core.Result.parse(r, cls._parse_data) for r in elem.findall('result')]

		@classmethod
		def _parse_data(cls, elem):
			return int(elem.findtext('id'))

	class DelMasterServer(core.operation_with_filter('DelMasterServer', ())):
		operator_name = 'dns'
		operation_name = 'del_master_server'
		min_api_version = '1.4.0.0'
		max_api_version = '1.6.2.9'  # less than 1.6.3.0

		@classmethod
		def parse(cls, elem):
			return core.parse_result_set(elem, cls._parse_data, 'id')

		@classmethod
		def _parse_data(cls, elem):
			return int(elem.findtext('id'))

	class Enable(core.operation_with_filter('Enable', ())):
		operator_name = 'dns'
		operation_name = 'enable'
		min_api_version = '1.4.0.0'
		max_api_version = '1.6.2.9'  # less than 1.6.3.0

		@classmethod
		def parse(cls, elem):
			return [core.Result.parse(r, cls._parse_data) for r in elem.findall('result')]

		@classmethod
		def _parse_data(cls, elem):
			return EnableResult(
				domain_id=if_not_none(elem.findtext('domain_id'), int),
				domain_alias_id=if_not_none(elem.findtext('domain_alias_id'), int)
			)

	class Disable(core.operation_with_filter('Disable', ())):
		operator_name = 'dns'
		operation_name = 'disable'
		min_api_version = '1.4.0.0'
		max_api_version = '1.6.2.9'  # less than 1.6.3.0

		@classmethod
		def parse(cls, elem):
			return [core.Result.parse(r, cls._parse_data) for r in elem.findall('result')]

		@classmethod
		def _parse_data(cls, elem):
			return DisableResult(
				domain_id=if_not_none(elem.findtext('domain_id'), int),
				domain_alias_id=if_not_none(elem.findtext('domain_alias_id'), int)
			)