"""
    Slixmpp: The Slick XMPP Library
    Copyright (C) 2011  Nathanael C. Fritz
    This file is part of Slixmpp.

    See the file LICENSE for copying permission.
"""

from slixmpp import Iq, Message
from slixmpp.xmlstream import register_stanza_plugin, ElementBase, ET, JID
from slixmpp.plugins import xep_0004
from slixmpp.plugins.xep_0060.stanza.base import OptionalSetting


class Pubsub(ElementBase):
    namespace = 'http://jabber.org/protocol/pubsub'
    name = 'pubsub'
    plugin_attrib = name
    interfaces = set(tuple())


class Affiliations(ElementBase):
    namespace = 'http://jabber.org/protocol/pubsub'
    name = 'affiliations'
    plugin_attrib = name
    interfaces = {'node'}


class Affiliation(ElementBase):
    namespace = 'http://jabber.org/protocol/pubsub'
    name = 'affiliation'
    plugin_attrib = name
    interfaces = {'node', 'affiliation', 'jid'}

    def set_jid(self, value):
        self._set_attr('jid', str(value))

    def get_jid(self):
        return JID(self._get_attr('jid'))


class Subscription(ElementBase):
    namespace = 'http://jabber.org/protocol/pubsub'
    name = 'subscription'
    plugin_attrib = name
    interfaces = {'jid', 'node', 'subscription', 'subid'}

    def set_jid(self, value):
        self._set_attr('jid', str(value))

    def get_jid(self):
        return JID(self._get_attr('jid'))


class Subscriptions(ElementBase):
    namespace = 'http://jabber.org/protocol/pubsub'
    name = 'subscriptions'
    plugin_attrib = name
    interfaces = {'node'}


class SubscribeOptions(ElementBase, OptionalSetting):
    namespace = 'http://jabber.org/protocol/pubsub'
    name = 'subscribe-options'
    plugin_attrib = 'suboptions'
    interfaces = {'required'}


class Item(ElementBase):
    namespace = 'http://jabber.org/protocol/pubsub'
    name = 'item'
    plugin_attrib = name
    interfaces = {'id', 'payload'}

    def set_payload(self, value):
        del self['payload']
        if isinstance(value, ElementBase):
            if value.tag_name() in self.plugin_tag_map:
                self.init_plugin(value.plugin_attrib, existing_xml=value.xml)
            self.xml.append(value.xml)
        else:
            self.xml.append(value)

    def get_payload(self):
        children = list(self.xml)
        if len(children) > 0:
            return children[0]

    def del_payload(self):
        for child in self.xml:
            self.xml.remove(child)


class Items(ElementBase):
    namespace = 'http://jabber.org/protocol/pubsub'
    name = 'items'
    plugin_attrib = name
    interfaces = {'node', 'max_items'}

    def set_max_items(self, value):
        self._set_attr('max_items', str(value))


class Create(ElementBase):
    namespace = 'http://jabber.org/protocol/pubsub'
    name = 'create'
    plugin_attrib = name
    interfaces = {'node'}


class Default(ElementBase):
    namespace = 'http://jabber.org/protocol/pubsub'
    name = 'default'
    plugin_attrib = name
    interfaces = {'node', 'type'}

    def get_type(self):
        t = self._get_attr('type')
        if not t:
            return 'leaf'
        return t


class Publish(ElementBase):
    namespace = 'http://jabber.org/protocol/pubsub'
    name = 'publish'
    plugin_attrib = name
    interfaces = {'node'}


class Retract(ElementBase):
    namespace = 'http://jabber.org/protocol/pubsub'
    name = 'retract'
    plugin_attrib = name
    interfaces = {'node', 'notify'}

    def get_notify(self):
        notify = self._get_attr('notify')
        if notify in ('0', 'false'):
            return False
        elif notify in ('1', 'true'):
            return True
        return None

    def set_notify(self, value):
        del self['notify']
        if value is None:
            return
        elif value in (True, '1', 'true', 'True'):
            self._set_attr('notify', 'true')
        else:
            self._set_attr('notify', 'false')


class Unsubscribe(ElementBase):
    namespace = 'http://jabber.org/protocol/pubsub'
    name = 'unsubscribe'
    plugin_attrib = name
    interfaces = {'node', 'jid', 'subid'}

    def set_jid(self, value):
        self._set_attr('jid', str(value))

    def get_jid(self):
        return JID(self._get_attr('jid'))


class Subscribe(ElementBase):
    namespace = 'http://jabber.org/protocol/pubsub'
    name = 'subscribe'
    plugin_attrib = name
    interfaces = {'node', 'jid'}

    def set_jid(self, value):
        self._set_attr('jid', str(value))

    def get_jid(self):
        return JID(self._get_attr('jid'))


class Configure(ElementBase):
    namespace = 'http://jabber.org/protocol/pubsub'
    name = 'configure'
    plugin_attrib = name
    interfaces = {'node', 'type'}

    def getType(self):
        t = self._get_attr('type')
        if not t:
            t == 'leaf'
        return t


class Options(ElementBase):
    namespace = 'http://jabber.org/protocol/pubsub'
    name = 'options'
    plugin_attrib = name
    interfaces = {'jid', 'node', 'options'}

    def __init__(self, *args, **kwargs):
        ElementBase.__init__(self, *args, **kwargs)

    def get_options(self):
        config = self.xml.find('{jabber:x:data}x')
        form = xep_0004.Form(xml=config)
        return form

    def set_options(self, value):
        if isinstance(value, ElementBase):
            self.xml.append(value.xml)
        else:
            self.xml.append(value)
        return self

    def del_options(self):
        config = self.xml.find('{jabber:x:data}x')
        self.xml.remove(config)

    def set_jid(self, value):
        self._set_attr('jid', str(value))

    def get_jid(self):
        return JID(self._get_attr('jid'))


class PublishOptions(ElementBase):
    namespace = 'http://jabber.org/protocol/pubsub'
    name = 'publish-options'
    plugin_attrib = 'publish_options'
    interfaces = {'publish_options'}
    is_extension = True

    def get_publish_options(self):
        config = self.xml.find('{jabber:x:data}x')
        if config is None:
            return None
        form = xep_0004.Form(xml=config)
        return form

    def set_publish_options(self, value):
        if value is None:
            self.del_publish_options()
        else:
            if isinstance(value, ElementBase):
                self.xml.append(value.xml)
            else:
                self.xml.append(value)
        return self

    def del_publish_options(self):
        config = self.xml.find('{jabber:x:data}x')
        if config is not None:
            self.xml.remove(config)
        self.parent().xml.remove(self.xml)


register_stanza_plugin(Iq, Pubsub)
register_stanza_plugin(Pubsub, Affiliations)
register_stanza_plugin(Pubsub, Configure)
register_stanza_plugin(Pubsub, Create)
register_stanza_plugin(Pubsub, Default)
register_stanza_plugin(Pubsub, Items)
register_stanza_plugin(Pubsub, Options)
register_stanza_plugin(Pubsub, Publish)
register_stanza_plugin(Pubsub, PublishOptions)
register_stanza_plugin(Pubsub, Retract)
register_stanza_plugin(Pubsub, Subscribe)
register_stanza_plugin(Pubsub, Subscription)
register_stanza_plugin(Pubsub, Subscriptions)
register_stanza_plugin(Pubsub, Unsubscribe)
register_stanza_plugin(Affiliations, Affiliation, iterable=True)
register_stanza_plugin(Configure, xep_0004.Form)
register_stanza_plugin(Items, Item, iterable=True)
register_stanza_plugin(Publish, Item, iterable=True)
register_stanza_plugin(Retract, Item)
register_stanza_plugin(Subscribe, Options)
register_stanza_plugin(Subscription, SubscribeOptions)
register_stanza_plugin(Subscriptions, Subscription, iterable=True)
