
# Slixmpp: The Slick XMPP Library
# Copyright (C) 2012 Erik Reuterborg Larsson, Nathanael C. Fritz
# This file is part of Slixmpp.
# See the file LICENSE for copying permission.

from slixmpp.stanza import Message
from slixmpp.xmlstream import register_stanza_plugin
from slixmpp.xmlstream.handler import Callback
from slixmpp.xmlstream.matcher import StanzaPath
from slixmpp.plugins import BasePlugin
from slixmpp.plugins.xep_0184 import stanza, Request, Received


class XEP_0184(BasePlugin):

    """
    XEP-0184: Message Delivery Receipts
    """

    name = 'xep_0184'
    description = 'XEP-0184: Message Delivery Receipts'
    dependencies = {'xep_0030'}
    stanza = stanza
    default_config = {
        'auto_ack': True,
        'auto_request': False
    }

    ack_types = ('normal', 'chat', 'headline')

    def plugin_init(self):
        register_stanza_plugin(Message, Request)
        register_stanza_plugin(Message, Received)

        self.xmpp.add_filter('out', self._filter_add_receipt_request)

        self.xmpp.register_handler(
                Callback('Message Receipt',
                    StanzaPath('message/receipt'),
                    self._handle_receipt_received))

        self.xmpp.register_handler(
                Callback('Message Receipt Request',
                    StanzaPath('message/request_receipt'),
                    self._handle_receipt_request))

    def plugin_end(self):
        self.xmpp['xep_0030'].del_feature('urn:xmpp:receipts')
        self.xmpp.del_filter('out', self._filter_add_receipt_request)
        self.xmpp.remove_handler('Message Receipt')
        self.xmpp.remove_handler('Message Receipt Request')

    def session_bind(self, jid):
        self.xmpp['xep_0030'].add_feature('urn:xmpp:receipts')

    def ack(self, msg):
        """
        Acknowledge a message by sending a receipt.

        Arguments:
            msg -- The message to acknowledge.
        """
        ack = self.xmpp.Message()
        ack['to'] = msg['from']
        ack['receipt'] = msg['id']
        ack.send()

    def _handle_receipt_received(self, msg):
        self.xmpp.event('receipt_received', msg)

    def _handle_receipt_request(self, msg):
        """
        Auto-ack message receipt requests if ``self.auto_ack`` is ``True``.

        Arguments:
            msg -- The incoming message requesting a receipt.
        """
        if self.auto_ack:
            if msg['type'] in self.ack_types:
                if not msg['receipt']:
                    self.ack(msg)

    def _filter_add_receipt_request(self, stanza):
        """
        Auto add receipt requests to outgoing messages, if:

            - ``self.auto_request`` is set to ``True``
            - The message is not for groupchat
            - The message does not contain a receipt acknowledgment
            - The recipient is a bare JID or, if a full JID, one
              that has the ``urn:xmpp:receipts`` feature enabled

        The disco cache is checked if a full JID is specified in
        the outgoing message, which may mean a round-trip disco#info
        delay for the first message sent to the JID if entity caps
        are not used.
        """

        if not self.auto_request:
            return stanza

        if not isinstance(stanza, Message):
            return stanza

        if stanza['request_receipt']:
            return stanza

        if stanza['type'] not in self.ack_types:
            return stanza

        if stanza['receipt']:
            return stanza

        if not stanza['body']:
            return stanza

        if stanza['to'].resource:
            if not self.xmpp['xep_0030'].supports(stanza['to'],
                    feature='urn:xmpp:receipts',
                    cached=True):
                return stanza

        stanza['request_receipt'] = True
        return stanza
