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

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import org.apache.log4j.Logger;
import org.buddycloud.channelserver.channel.ChannelManager;
import org.buddycloud.channelserver.db.exception.NodeStoreException;
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.pubsub.model.impl.NodeItemImpl;
import org.buddycloud.channelserver.pubsub.model.impl.NodeSubscriptionImpl;
import org.buddycloud.channelserver.pubsub.subscription.Subscriptions;
import org.dom4j.Element;
import org.xmpp.packet.IQ;
import org.xmpp.packet.JID;

public class ItemsResult extends PubSubElementProcessorAbstract {

	private static final String MISSING_NODE = "Missing node";
	private static final String DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.S'Z'";

	private static final Logger logger = Logger.getLogger(ItemsResult.class);
	private SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT);
	private boolean subscriptionNode = false;

	public ItemsResult(ChannelManager channelManager) {
		this.channelManager = channelManager;
	}

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

		this.request = reqIQ;
		
		if (-1 != request.getFrom().toString().indexOf("@")) {
			logger.debug("Ignoring result packet, only interested in stanzas "
					+ "from other buddycloud servers");
			return;
		}

		if (null != elm.attributeValue("node")) 
			this.setNode(elm.attributeValue("node"));

		if ((null == node) || (true == node.equals(""))) {
			throw new NullPointerException(MISSING_NODE);
		}

		subscriptionNode = (true == node.substring(node.length() - 13,
				node.length()).equals("subscriptions"));

		if ((false == subscriptionNode)
				&& (false == channelManager.nodeExists(node)))
			channelManager.addRemoteNode(node);

		@SuppressWarnings("unchecked")
		List<Element> items = request.getElement().element("pubsub")
				.element("items").elements("item");

		for (Element item : items) {
			if (true == subscriptionNode) {
				processSubscriptionItem(item);
			} else {
				processPublishedItem(item);
			}
		}
	}

	private void processSubscriptionItem(Element item)
			throws NodeStoreException {
		JID user = new JID(item.attributeValue("id"));
		List<Element> items = item.element("query").elements("item");
		for (Element subscription : items) {
			try {
			    addSubscription(subscription, user);
			} catch (IllegalArgumentException e) {
				logger.error(e);
			}
		}
	}

	private void addSubscription(Element item, JID user)
			throws NodeStoreException {

		String node = item.attributeValue("node");
		
		// If its a local JID and/or a local node, that's our turf!
		if ((true == channelManager.isLocalNode(node))
				&& (true == channelManager.isLocalJID(user)))
			return;
        if (true == channelManager.isLocalNode(node)) return; 
        
		JID listener = request.getFrom();
		Subscriptions sub = Subscriptions.createFromString(item
				.attributeValue("subscription"));
		Affiliations aff = Affiliations.createFromString(item
				.attributeValue("affiliation"));
		NodeSubscription subscription = new NodeSubscriptionImpl(node, user,
				listener, sub);

		if (false == channelManager.nodeExists(node))
			channelManager.addRemoteNode(node);

		channelManager.addUserSubscription(subscription);
		channelManager.setUserAffiliation(node, user, aff);
	}

	private void processPublishedItem(Element item) throws ParseException,
			NodeStoreException {

		Element entry = item.element("entry");

		try {
			// Probably a tombstone'd item
			if (null == entry.elementText("updated")) {
				logger.debug("Entry has no 'updated' element, won't process");
				return;
			}

			Date updatedDate = sdf.parse(entry.elementText("updated"));
			NodeItemImpl nodeItem = new NodeItemImpl(node,
					entry.elementText("id"), updatedDate, entry.asXML());
			try {
				channelManager
						.deleteNodeItemById(node, entry.elementText("id"));
			} catch (NodeStoreException e) {
				logger.error("Attempt to delete an item which didn't exist... its ok");
			}
			channelManager.addNodeItem(nodeItem);
		} catch (ParseException e) {
			logger.error(e);
			e.printStackTrace();
			return;
		}
	}

	public boolean accept(Element elm) {
		return elm.getName().equals("items");
	}
}
@@ -3973,16 +3973,256 @@
 n;%0A%09%09%09%7D%0A
+%09%09%09String inReplyTo = null;%0A%09%09%09Element reply;%0A%09%09%09%0A%09%09%09if (null != (reply = entry.element(%22in-reply-to%22))) %7B%0A%09%09%09%09String%5B%5D inReplyToParts = reply.attributeValue(%22ref%22).split(%22,%22);%0A%09%09%09%09inReplyTo = inReplyToParts%5BinReplyToParts.length - 1%5D;%0A%09%09%09%7D
 %0A%09%09%09Date
@@ -4383,16 +4383,27 @@
 .asXML()
+, inReplyTo
 );%0A%09%09%09tr

Add in-reply-to details to incoming item results