from collections import namedtuple

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

UserAddInfo = namedtuple('UserAddInfo', ('id', 'guid'))
UserContactInfo = namedtuple(
    'UserContactInfo', (
        'company', 'phone', 'fax', 'address', 'city', 'state', 'zip',
        'country', 'im', 'imtype', 'comment'))
UserGetInfo = namedtuple('UserGetInfo', ('gen_info', 'roles'))
UserGenInfo = namedtuple('UserGenInfo', ('login', 'name', 'owner_guid', 'status', 'guid', 'is_built_in', 'contact_info', 'external_id'))


class UserOperator(object):
    FilterAll = core.FilterAll
    FilterOwnerGuid = core.declare_filter('FilterOwnerGuid', 'owner-guid')

    class Dataset(object):
        GEN_INFO = 'gen-info'
        ROLES = 'roles'

        values = [GEN_INFO, ROLES]

    STATUS_DISABLED = 'disabled'
    STATUS_ENABLED = 'enabled'

    class Add(
            core.operation(
                'Add', (
                    'login', 'passwd', 'owner_guid', 'name', 'roles',
                    'contact_info', 'subscription_domain_id', 'status',
                    'email'))):
        operator_name = 'user'
        operation_name = 'add'
        min_api_version = '1.6.4.0'
        max_api_version = None

        def inner_xml(self):
            return [
                elem('gen-info', seq(
                    text_elem('login', self.login),
                    text_elem('passwd', self.passwd),
                    text_elem('owner-guid', self.owner_guid),
                    text_elem('name', self.name),
                    elem('contact-info', [
                            text_elem(name, value) for name, value in self.contact_info._asdict().items()
                        ]) if self.contact_info is not None else None,
                    text_elem('status', self.status),
                    text_elem('subscription-domain-id', self.subscription_domain_id),
                    text_elem('email', self.email),
                )),
                elem('roles', [
                    text_elem('name', role) for role in self.roles
                ])
            ]

        @classmethod
        def parse(cls, elem):
            assert(len(elem) == 1)
            return core.Result.parse(elem[0], cls._parse_data)

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

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

        def data_xml(self):
            return [
                elem('dataset', [elem(i) for i in sort_list_by_another(self.dataset, UserOperator.Dataset.values)])
            ]

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

        @classmethod
        def _parse_data(cls, elem):
            gen_info = if_not_none(
                elem.find('data/gen-info'),
                lambda gen_info_node:
                    UserGenInfo(
                        login=gen_info_node.findtext('login'),
                        name=gen_info_node.findtext('name'),
                        owner_guid=gen_info_node.findtext('owner-guid'), 
                        status=gen_info_node.findtext('status'),
                        guid=gen_info_node.findtext('guid'),
                        is_built_in=parse_bool(gen_info_node.findtext('is-built-in')),
                        contact_info=if_not_none(
                            gen_info_node.find('contact-info'), 
                            lambda contact_node:
                                UserContactInfo(
                                    company=contact_node.findtext('company'), 
                                    phone=contact_node.findtext('phone'), 
                                    fax=contact_node.findtext('fax'), 
                                    address=contact_node.findtext('address'), 
                                    city=contact_node.findtext('city'), 
                                    state=contact_node.findtext('state'), 
                                    zip=contact_node.findtext('zip'), 
                                    country=contact_node.findtext('country'),
                                    im=contact_node.findtext('im'),
                                    imtype=contact_node.findtext('imtype'),
                                    comment=contact_node.findtext('comment'),
                                )
                        ), 
                        external_id=gen_info_node.findtext('external-id'),
                    )
            )

            roles = if_not_none(
                elem.find('data/roles'),
                lambda roles_node:
                    [name_node.text for name_node in roles_node.findall('name')]
            )

            return UserGetInfo(gen_info, roles)