from collections import namedtuple

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

DbServerInfo = namedtuple('DbServerInfo', ('id', 'host', 'port', 'dbtype', 'admin', 'password', 'status', 'db_num', 'default', 'local'))


class DbServerOperator(object):
    FilterAll = core.FilterAll
    FilterById = core.declare_filter('FilterById', 'id')

    class Get(core.operation_with_filter('Get')):
        operator_name = 'db_server'
        operation_name = 'get'
        min_api_version = '1.3.5.1'
        max_api_version = None

        @classmethod
        def parse(cls, elem):
            results = [core.Result.parse(r, cls._parse_data) for r in elem.findall('result')]
            if len(results) == 1 and results[0].ok and results[0].data is None:
                results = []
            return results
        
        @classmethod
        def _parse_data(cls, elem):
            db_server_id = if_not_none(elem.findtext('id'), int)
            if db_server_id is None:
                return None
            data_node = elem.find('data')
            return DbServerInfo(
                id=db_server_id,
                host=data_node.findtext('host'),
                port=if_not_none(data_node.findtext('port'), int),
                dbtype=data_node.findtext('type'),
                admin=data_node.findtext('admin'),
                password=data_node.findtext('password'),
                status=data_node.findtext('status'),
                db_num=int(data_node.findtext('db_num')),
                default=data_node.find('default') is not None,
                local=data_node.find('local') is not None,
            )

    class Add(core.operation('Add', ('host', 'port', 'db_type', 'admin', 'password', 'default'))):
        operator_name = 'db_server'
        operation_name = 'add'
        min_api_version = '1.3.5.1'
        max_api_version = None

        def inner_xml(self):
            return seq(
                text_elem('host', self.host),
                text_elem('port', self.port),
                text_elem('type', self.db_type),
                text_elem('admin', self.admin),
                text_elem('password', self.password),
                elem('default') if self.default else None,
            )
            
        @classmethod
        def parse(cls, elem):
            return core.Result.parse(elem.find('result'), cls._parse_data)
        
        @classmethod
        def _parse_data(cls, elem):
            return int(elem.findtext('id'))

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

    class LocalDbRef(namedtuple('LocalDbRef', ('dbtype',))):
        def inner_xml(self):
            return [text_elem('type', self.dbtype)]

    class SetDefault(core.operation('SetDefault', ('db_ref',))):
        operator_name = 'db_server'
        operation_name = 'set-default'
        min_api_version = '1.6.4.0'
        max_api_version = None

        def inner_xml(self):
            return self.db_ref.inner_xml()

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