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-buil*D*-in is not a mistake
                is_built_in=parse_bool(elem.findtext('data/is-build-in')),
                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.items()
                    ]
                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.items()
                    ])
                ])
            ]

        @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