package org.buddycloud.channelserver.packetprocessor.iq.namespace.pubsub.set;

import java.util.Collection;
import java.util.concurrent.BlockingQueue;

import org.buddycloud.channelserver.channel.ChannelManager;
import org.buddycloud.channelserver.db.exception.NodeStoreException;
import org.buddycloud.channelserver.packetprocessor.iq.namespace.pubsub.JabberPubsub;
import org.buddycloud.channelserver.packetprocessor.iq.namespace.pubsub.PubSubElementProcessorAbstract;
import org.buddycloud.channelserver.pubsub.affiliation.Affiliations;
import org.buddycloud.channelserver.pubsub.model.NodeSubscription;
import org.buddycloud.channelserver.utils.node.item.payload.Buddycloud;
import org.dom4j.Element;
import org.dom4j.Namespace;
import org.dom4j.dom.DOMElement;
import org.xmpp.packet.IQ;
import org.xmpp.packet.JID;
import org.xmpp.packet.Message;
import org.xmpp.packet.Packet;
import org.xmpp.packet.PacketError;
import org.xmpp.resultsetmanagement.ResultSet;

public class NodeDelete extends PubSubElementProcessorAbstract {

    private static final String NODE_REG_EX = "^/user/[^@]+@[^/]+/[^/]+$";

    public NodeDelete(BlockingQueue<Packet> outQueue, ChannelManager channelManager) {
        setChannelManager(channelManager);
        setOutQueue(outQueue);
    }

    public void process(Element elm, JID actorJID, IQ reqIQ, Element rsm) throws Exception {

        this.element = elm;
        this.response = IQ.createResultIQ(reqIQ);
        this.request = reqIQ;
        this.actor = actorJID;
        this.node = element.attributeValue("node");

        if (actorJID == null) {
            actor = request.getFrom();
        }
        if (!validateNode()) {
            outQueue.put(response);
            return;
        }
        if (!channelManager.isLocalNode(node)) {
            makeRemoteRequest();
            return;
        }
        if (!nodeExists() || !actorIsRegistered() || !nodeHandledByThisServer() || !actorAllowedToDelete()) {
            outQueue.put(response);
            return;
        }
        deleteNode();
        sendNotifications();
    }

    private void sendNotifications() throws NodeStoreException {
        try {
            ResultSet<NodeSubscription> subscriptions = channelManager.getNodeSubscriptionListeners(node);
            Message notification = createNotificationMessage();
            if (subscriptions != null) {
                for (NodeSubscription subscription : subscriptions) {
                    notification.setTo(subscription.getListener().toString());
                    outQueue.put(notification.createCopy());
                }
            }
            Collection<JID> admins = getAdminUsers();
            for (JID admin : admins) {
                notification.setTo(admin);
                outQueue.put(notification.createCopy());
            }
        } catch (Exception e) {
            logger.error(e);
        }
    }

    private Message createNotificationMessage() {
        Message notification = new Message();
        notification.setType(Message.Type.headline);
        notification.getElement().addAttribute("remote-server-discover", "false");
        Element eventEl = notification.addChildElement("event", JabberPubsub.NS_PUBSUB_EVENT);
        Element deleteEl = eventEl.addElement("delete");
        deleteEl.addAttribute("node", node);
        return notification;
    }

    private void deleteNode() throws InterruptedException {
        try {
            channelManager.deleteNode(node);
        } catch (NodeStoreException e) {
            logger.error(e);
            setErrorCondition(PacketError.Type.wait, PacketError.Condition.internal_server_error);
            outQueue.put(response);
            return;
        }
        response.setType(IQ.Type.result);
        outQueue.put(response);
    }

    public boolean accept(Element elm) {
        return elm.getName().equals("delete");
    }

    private boolean validateNode() {
        if (node != null && !node.trim().equals("")) {
            return true;
        }
        response.setType(IQ.Type.error);
        Element nodeIdRequired = new DOMElement("nodeid-required", new Namespace("", JabberPubsub.NS_PUBSUB_ERROR));
        Element badRequest = new DOMElement(PacketError.Condition.bad_request.toXMPP(), new Namespace("", JabberPubsub.NS_XMPP_STANZAS));
        Element error = new DOMElement("error");
        error.addAttribute("type", "modify");
        error.add(badRequest);
        error.add(nodeIdRequired);
        response.setChildElement(error);
        return false;
    }

    private boolean nodeExists() throws NodeStoreException {
        if (channelManager.nodeExists(node)) {
            return true;
        }
        setErrorCondition(PacketError.Type.cancel, PacketError.Condition.item_not_found);
        return false;
    }

    private boolean actorIsRegistered() {
        if (actor.getDomain().equals(getServerDomain())) {
            return true;
        }
        setErrorCondition(PacketError.Type.auth, PacketError.Condition.forbidden);
        return false;
    }

    private boolean actorAllowedToDelete() throws NodeStoreException {
        boolean isOwner = channelManager.getNodeMembership(node, actor).getAffiliation().equals(Affiliations.owner);

        if (isOwner) {
            return true;
        }
        setErrorCondition(PacketError.Type.auth, PacketError.Condition.not_authorized);
        return false;
    }

    private boolean nodeHandledByThisServer() {
        if (!node.matches(NODE_REG_EX)) {
            setErrorCondition(PacketError.Type.modify, PacketError.Condition.bad_request);
            return false;
        }

        if (!node.contains("@" + getServerDomain()) && !node.contains("@" + getTopicsDomain())) {
            setErrorCondition(PacketError.Type.modify, PacketError.Condition.not_acceptable);
            return false;
        }
        return true;
    }

    private void makeRemoteRequest() throws InterruptedException {
        request.setTo(new JID(node.split("/")[2]).getDomain());
        Element actor = request.getElement().element("pubsub").addElement("actor", Buddycloud.NS);
        actor.addText(request.getFrom().toBareJID());
        outQueue.put(request);
    }
}

@@ -72,16 +72,44 @@
 b.set;%0A%0A
+import java.util.ArrayList;%0A
 import j
@@ -125,24 +125,24 @@
 Collection;%0A
-
 import java.
@@ -987,16 +987,67 @@
 sultSet;
+%0Aimport org.xmpp.resultsetmanagement.ResultSetImpl;
 %0A%0Apublic
@@ -1180,16 +1180,68 @@
 %5B%5E/%5D+$%22;
+%0A%09private ResultSet%3CNodeSubscription%3E subscriptions;
 %0A%0A    pu
@@ -2146,32 +2146,60 @@
 turn;%0A        %7D%0A
+        getNodeListeners();%0A
         deleteNo
@@ -2261,81 +2261,167 @@
 oid 
-sendNotifications() throws NodeStoreException %7B%0A        try %7B%0A           
+getNodeListeners() %7B%0A    %09try %7B%0A%09%09%09subscriptions = channelManager.getNodeSubscriptionListeners(node);%0A%09%09%7D catch (NodeStoreException e) %7B%0A%09%09%09subscriptions = new
  Res
@@ -2418,32 +2418,36 @@
  = new ResultSet
+Impl
 %3CNodeSubscriptio
@@ -2452,75 +2452,128 @@
 ion%3E
- subscriptions = channelManager.getNodeSubscriptionListeners(node);
+(new ArrayList%3CNodeSubscription%3E());%0A%09%09%7D%0A%09%7D%0A%0A%09private void sendNotifications() throws NodeStoreException %7B%0A        try %7B
 %0A   

Send notifications