from xml.etree import ElementTree

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


class CapabilityXMLConverter(object):
    """Class to create capability dump XML out of capability dump model"""

    def __init__(self, capability_model):
        """
        :type capability_model: parallels.plesk.source.plesk.capability_dump.model.base.model.CapabilityDumpModel
        """
        self._capability_model = capability_model

    def write_xml(self, filename):
        """
        :param filename: str|unicode
        """
        capability_dump_contents = xml_to_string_pretty(self.create_xml())
        with open_no_inherit(filename, 'w') as fp:
            fp.write(capability_dump_contents)

    def create_xml(self):
        """
        :rtype: xml.etree.ElementTree.ElementTree
        """
        admin = self._capability_model.get_admin()
        return ElementTree.ElementTree(
            elem(
                'capability-dump', [
                    self._create_reseller_node(reseller) for reseller in self._capability_model.get_resellers()
                ] + [
                    self._create_client_node(client) for client in self._capability_model.get_clients(admin.admin_id)
                ] + [
                    self._create_domain_node(domain) for domain in self._capability_model.get_domains(admin.admin_id)
                ] + [
                    self._create_server_node()
                ]
            )
        )

    def _create_reseller_node(self, reseller):
        """
        :type reseller: parallels.plesk.source.plesk.capability_dump.model.base.reseller.Reseller
        :rtype: xml.etree.ElementTree.Element
        """
        clients = self._capability_model.get_clients(reseller.reseller_id)
        domains = self._capability_model.get_domains(reseller.reseller_id)
        return elem(
            'reseller', [
                text_elem('name', reseller.login)
            ] + ([
                elem('clients', [self._create_client_node(client) for client in clients])
            ] if clients else []) + ([
                elem('domains', [self._create_domain_node(domain) for domain in domains])
            ] if domains else [])
        )

    def _create_client_node(self, client):
        """
        :type client: parallels.plesk.source.plesk.capability_dump.model.base.client.Client
        :rtype: xml.etree.ElementTree.Element
        """
        domains = self._capability_model.get_domains(client.client_id)
        return elem(
            'client', [
                text_elem('name', client.login)
            ] + ([
                elem('domains', [self._create_domain_node(domain) for domain in domains])
            ] if domains else [])
        )

    def _create_domain_node(self, domain):
        """
        :type domain: parallels.plesk.source.plesk.capability_dump.model.base.domain.Domain
        :rtype: xml.etree.ElementTree.Element
        """
        return elem(
            'domain', seq(
                text_elem('name', domain.name),
                text_elem('vendor-login', domain.vendor_login)
            ) + [
                self._create_ip_node(ip) for ip in self._capability_model.get_domain_ips(domain.domain_id)
            ] + [
                elem('capability-info', seq(
                    self._create_components_node(self._capability_model.get_domain_components(domain.domain_id)),
                    self._create_resource_usage_node(self._capability_model.get_domain_resource_usage(domain.domain_id)),
                    self._create_miscellaneous_node(self._capability_model.get_domain_settings(domain.domain_id)),
                ))
            ]
        )

    def _create_ip_node(self, ip):
        """
        :type ip: parallels.plesk.source.plesk.capability_dump.model.base.ip_address.IpAddress
        :rtype: xml.etree.ElementTree.Element
        """
        return elem(
            'ip', [
                elem(
                    ip.ip_address_type, [
                        text_elem('source', ip.ip_address)
                    ]
                )
            ]
        )

    def _create_server_node(self):
        """
        :rtype: xml.etree.ElementTree.Element
        """
        return elem(
            'server', [
                elem('capability-info', seq(
                    self._create_components_node(self._capability_model.get_server_components()),
                    self._create_resource_usage_node(self._capability_model.get_server_resource_usage()),
                    self._create_miscellaneous_node(self._capability_model.get_server_settings()),
                    self._create_database_servers_node(self._capability_model.get_database_servers()),
                    self._create_apache_modules_node(self._capability_model.get_apache_modules()),
                ))
            ]
        )

    def _create_components_node(self, components):
        """
        :type components: list[tuple[str|unicode, str|unicode]]
        :rtype: xml.etree.ElementTree.Element
        """
        return elem(
            'components', [
                elem('component', seq(
                    text_elem('name', name),
                    text_elem('value', value)
                ))
                for name, value in components
            ]
        )

    def _create_resource_usage_node(self, resource_usage):
        """
        :type resource_usage: list[tuple[str|unicode, str|unicode]]
        :rtype: xml.etree.ElementTree.Element
        """
        return elem(
            'resource-usage', [
                elem('resource', seq(
                    text_elem('name', name),
                    text_elem('value', value)
                ))
                for name, value in resource_usage
            ]
        )

    def _create_miscellaneous_node(self, settings):
        """
        :type settings: list[tuple[str|unicode, str|unicode]]
        :rtype: xml.etree.ElementTree.Element
        """
        return elem(
            'miscellaneous', [
                elem('setting', seq(
                    text_elem('name', name),
                    text_elem('value', value)
                ))
                for name, value in settings
            ]
        )

    def _create_database_servers_node(self, database_servers):
        """
        :type database_servers: list[parallels.plesk.source.plesk.capability_dump.model.base.database_server.DatabaseServer]
        :rtype: xml.etree.ElementTree.Element
        """
        return elem(
            'database-servers', [
                elem('database-server', seq(
                    text_elem('type', database_server.server_type),
                    text_elem('host', database_server.host),
                    text_elem('port', database_server.port),
                    text_elem('local', database_server.local),
                    text_elem('version', database_server.version),
                ))
                for database_server in database_servers
            ]
        )

    def _create_apache_modules_node(self, modules):
        """
        :type modules: list[tuple[str|unicode, str|unicode]]
        :rtype: xml.etree.ElementTree.Element
        """
        return elem(
            'apache-modules', [
                elem('module', seq(
                    text_elem('name', name),
                    text_elem('value', value)
                ))
                for name, value in modules
                ]
        )
