from collections import namedtuple

from .. import core
from parallels.core.utils.common import parse_bool
from parallels.core.utils.common.xml import elem, text_elem, bool_elem, seq

RoleInfo = namedtuple('RoleInfo', ('name', 'owner_guid', 'is_built_in', 'permissions'))
PermissionInfo = namedtuple('PermissionInfo', ('name', 'type', 'default_value', 'writable_by'))


class RoleOperator(object):
	FilterAll = core.FilterAllWithNode
	FilterName = core.declare_filter('FilterName', 'name')

	class Get(core.operation_with_filter('Get', ('owner_guid',))):
		operator_name = 'role'
		operation_name = 'get'
		min_api_version = '1.6.4.0'
		max_api_version = None

		def data_xml(self):
			return seq(
				text_elem('owner-guid', self.owner_guid) if self.owner_guid is not None else None
			)

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

		@classmethod
		def _parse_data(cls, elem):
			return RoleInfo(
				name=elem.findtext('data/name'),
				owner_guid=elem.findtext('data/owner-guid'),
				is_built_in=parse_bool(elem.findtext('data/is-build-in')), # is-buil*D*-in is not a mistake
				permissions=dict([
					(perm_node.findtext('name'), parse_bool(perm_node.findtext('value')))
					for perm_node in elem.findall('data/permissions/permission')
				])
			)
	
	class Add(core.operation('Add', ('name', 'owner_guid', 'permissions'))):
		operator_name = 'role'
		operation_name = 'add'
		min_api_version = '1.6.4.0'
		max_api_version = None

		def inner_xml(self):
			if self.owner_guid is not None:
				owner = text_elem('owner-guid', self.owner_guid)
			else:
				owner = None
			if len(self.permissions) > 0:
				permission_list = [
						elem('permission', [
							text_elem('name', name), bool_elem('value', value)])
						for name, value in self.permissions.iteritems()
					]
				permissions = elem('permissions', permission_list)
			else:
				permissions = None
			return seq(text_elem('name', self.name), owner, permissions)

		@classmethod
		def parse(cls, elem):
			return core.Result.parse(elem.find('result'), cls._parse_data)

		@classmethod
		def _parse_data(cls, elem):
			pass

	class Set(core.operation_with_filter('Set', ('owner_guid', 'permissions'))):
		operator_name = 'role'
		operation_name = 'set'
		min_api_version = '1.6.4.0'
		max_api_version = None

		def data_xml(self):
			return [
				text_elem('owner-guid', self.owner_guid) if self.owner_guid is not None else None,
				elem('values', [
					elem('permissions', [
						elem('permission', [text_elem('name', name), bool_elem('value', value)])
						for name, value in self.permissions.iteritems()
					])
				])
			]

		@classmethod
		def parse(cls, elem):
			return core.Result.parse(elem.find('result'), cls._parse_data)

		@classmethod
		def _parse_data(cls, elem):
			pass

	class GetPermissionDescriptor(core.operation_with_filter('GetPermissionsDescriptor')):
		operator_name = 'role'
		operation_name = 'get-permission-descriptor'
		min_api_version = '1.6.4.0'
		max_api_version = None

		FilterOwnerGuid = core.declare_filter('FilterOwnerGuid', 'owner-guid')

		@classmethod
		def parse(cls, elem):
			return core.Result.parse(elem.find('result'), cls._parse_data)

		@classmethod
		def _parse_data(cls, elem):
			permission_info = []
			for prop in elem.findall('descriptor/property'):
				permission_info.append(PermissionInfo(
					name=prop.findtext('name'),
					type=prop.findtext('type'),
					default_value=parse_bool(prop.findtext('default-value')) if prop.findtext('type') == 'boolean' else prop.findtext('default-value'),
					writable_by=set(node.text for node in prop.findall('writable-by'))
				))
			return permission_info