# -*- coding: iso-8859-1 -*-
"""
    MoinMoin - jabber notification plugin for event system

    This code sends notifications using a separate daemon.

    @copyright: 2007 by Karol Nowak <grywacz@gmail.com>
    @license: GNU GPL, see COPYING for details.
"""

import xmlrpclib

from MoinMoin import log
logging = log.getLogger(__name__)

from MoinMoin.Page import Page
from MoinMoin.user import User, superusers
from MoinMoin.action.AttachFile import getAttachUrl

import MoinMoin.events.notification as notification
import MoinMoin.events as ev


def handle(event):
    """An event handler"""

    cfg = event.request.cfg

    # Check for desired event type and if notification bot is configured
    if not cfg.jabber_enabled:
        return

    if isinstance(event, (ev.PageChangedEvent, ev.TrivialPageChangedEvent)):
        return handle_page_changed(event)
    elif isinstance(event, (ev.JabberIDSetEvent, ev.JabberIDUnsetEvent)):
        return handle_jid_changed(event)
    elif isinstance(event, ev.FileAttachedEvent):
        return handle_file_attached(event)
    # TODO (needs also corresponding changes in xmppbot + testing)
    #elif isinstance(event, ev.FileRemovedEvent):
    #    return handle_file_removed(event)
    elif isinstance(event, ev.PageDeletedEvent):
        return handle_page_deleted(event)
    elif isinstance(event, ev.PageRenamedEvent):
        return handle_page_renamed(event)
    elif isinstance(event, ev.UserCreatedEvent):
        return handle_user_created(event)


def handle_jid_changed(event):
    """ Handles events sent when user's JID changes """

    request = event.request
    server = request.cfg.notification_server
    secret = request.cfg.secrets['jabberbot']
    try:
        if isinstance(event, ev.JabberIDSetEvent):
            server.addJIDToRoster(secret, event.jid)
        else:
            server.removeJIDFromRoster(secret, event.jid)
    except xmlrpclib.Error, err:
        logging.error("XML RPC error: %s" % str(err))
    except Exception, err:
        logging.error("Low-level communication error: %s" % str(err))


def handle_file_attached(event):
    """Handles event sent when a file is attached to a page"""

    names = set()
    request = event.request
    page = Page(request, event.pagename)
    subscribers = page.getSubscribers(request, return_users=1)
    notification.filter_subscriber_list(event, subscribers, True)
    recipients = []

    for lang in subscribers:
        recipients.extend(subscribers[lang])

    attachlink = request.getQualifiedURL(getAttachUrl(event.pagename, event.filename, request))
    pagelink = request.getQualifiedURL(page.url(request, {}))

    for lang in subscribers.keys():
        _ = lambda text: request.getText(text, lang=lang)
        data = notification.attachment_added(request, _, event.pagename, event.filename, event.size)
        links = [{'url': attachlink, 'description': _("Attachment link")},
                  {'url': pagelink, 'description': _("Page link")}]

        jids = [usr.jid for usr in subscribers[lang]]
        data['url_list'] = links
        data['action'] = "file_attached"

        if send_notification(request, jids, data):
            names.update(recipients)

    return notification.Success(names)


def handle_page_changed(event):
    """ Handles events related to page changes """
    request = event.request
    page = event.page

    subscribers = page.getSubscribers(request, return_users=1)
    notification.filter_subscriber_list(event, subscribers, True)
    return page_change("page_changed", request, page, subscribers, \
                       revisions=page.getRevList(), comment=event.comment)


def handle_page_deleted(event):
    """Handles event sent when a page is deleted"""

    request = event.request
    page = event.page

    subscribers = page.getSubscribers(request, return_users=1)
    notification.filter_subscriber_list(event, subscribers, True)
    return page_change("page_deleted", request, page, subscribers)


def handle_page_renamed(event):
    """Handles event sent when a page is renamed"""

    request = event.request
    page = event.page
    old_name = event.old_page.page_name

    subscribers = page.getSubscribers(request, return_users=1)

    # Change request's page so that we filter subscribers of the OLD page
    request.page = event.old_page
    notification.filter_subscriber_list(event, subscribers, True)
    request.page = page
    return page_change("page_renamed", request, page, subscribers, old_name=old_name)


def handle_user_created(event):
    """Handles an event sent when a new user is being created"""
    request = event.request
    sitename = request.cfg.sitename
    event_name = event.name
    email = event.user.email or u"NOT SET"
    username = event.user.name

    for usr in superusers(request):
        if usr.jid and event_name in usr.jabber_subscribed_events:
            _ = lambda text: request.getText(text, lang=usr.language or 'en')
            msg = notification.user_created_message(request, _, sitename, username, email)
            data = {'action': "user_created", 'subject': msg['subject'], 'text': msg['text'],
                    'url_list': []}
            send_notification(request, [usr.jid], data)


def page_change(change_type, request, page, subscribers, **kwargs):
    """Sends notification about page being changed in some way"""

    # send notifications to all subscribers
    if subscribers:
        recipients = set()

        for lang in subscribers:
            _ = lambda text: request.getText(text, lang=lang)
            jids = [u.jid for u in subscribers[lang] if u.jid]
            names = [u.name for u in subscribers[lang] if u.jid]
            msg = notification.page_change_message(change_type, request, page, lang, **kwargs)
            page_url = request.getQualifiedURL(page.url(request))
            url = {'url': page_url, 'description': _("Changed page")}
            data = {'action': change_type, 'subject': _('Page changed'),
                            'url_list': [url], 'text': msg['text'], 'diff': msg.get('diff', ''),
                            'comment': msg.get('comment', ''), 'editor': msg['editor'],
                            'old_name': msg.get('old_name', ''), 'page_name': msg.get('page_name', ''),
                            'revision': msg.get('revision', '')}

            result = send_notification(request, jids, data)

            if result:
                recipients.update(names)

        if recipients:
            return notification.Success(recipients)


def send_notification(request, jids, notification):
    """ Send notifications for a single language.

    @param jids: an iterable of Jabber IDs to send the message to
    @param message: message text
    @param subject: subject of the message, makes little sense for chats
    @param url_list: a list of dicts containing URLs and their descriptions
    @type url_list: list

    """
    server = request.cfg.notification_server

    if type(notification) != dict:
        raise ValueError("notification must be of type dict!")

    if type(notification['url_list']) != list:
        raise ValueError("url_list must be of type list!")

    try:
        server.send_notification(request.cfg.secrets['jabberbot'], jids, notification)
        return True
    except xmlrpclib.Error, err:
        logging.error("XML RPC error: %s" % str(err))
    except Exception, err:
        logging.error("Low-level communication error: %s" % str(err))

