package com.reucon.openfire.plugin.archive.xep0136;

import com.reucon.openfire.plugin.archive.model.ArchivedMessage;
import com.reucon.openfire.plugin.archive.model.Conversation;
import com.reucon.openfire.plugin.archive.util.XmppDateUtil;
import com.reucon.openfire.plugin.archive.xep.AbstractIQHandler;
import com.reucon.openfire.plugin.archive.xep0059.XmppResultSet;
import org.dom4j.Element;
import org.jivesoftware.openfire.auth.UnauthorizedException;
import org.xmpp.packet.IQ;
import org.xmpp.packet.JID;
import org.xmpp.packet.PacketError;

import java.util.List;

/**
 * Message Archiving Retrieve Handler.
 */
public class IQRetrieveHandler extends AbstractIQHandler {

	private static final String NAMESPACE = "urn:xmpp:archive";

	public IQRetrieveHandler() {
		super("Message Archiving Retrieve Handler", "retrieve", NAMESPACE);
	}

	public IQ handleIQ(IQ packet) throws UnauthorizedException {
		final IQ reply = IQ.createResultIQ(packet);
		final RetrieveRequest retrieveRequest = new RetrieveRequest(
				packet.getChildElement());
		int fromIndex; // inclusive
		int toIndex; // exclusive
		int max;

		final Conversation conversation = retrieve(packet.getFrom(),
				retrieveRequest);
		if (conversation == null) {
			return error(packet, PacketError.Condition.item_not_found);
		}

		final Element chatElement = reply.setChildElement("chat", NAMESPACE);
		chatElement.addAttribute("with", conversation.getWithJid());
		chatElement.addAttribute("start",
				XmppDateUtil.formatDate(conversation.getStart()));

		max = conversation.getMessages().size();
		fromIndex = 0;
		toIndex = max > 0 ? max : 0;

		final XmppResultSet resultSet = retrieveRequest.getResultSet();
		if (resultSet != null) {
			if (resultSet.getMax() != null && resultSet.getMax() <= max) {
				max = resultSet.getMax();
				toIndex = fromIndex + max;
			}

			if (resultSet.getIndex() != null) {
				fromIndex = resultSet.getIndex();
				toIndex = fromIndex + max;
			} else if (resultSet.getAfter() != null) {
				fromIndex = resultSet.getAfter().intValue() + 1;
				toIndex = fromIndex + max;
			} else if (resultSet.getBefore() != null) {
				if (resultSet.getBefore()!=Long.MAX_VALUE)
                    			toIndex = resultSet.getBefore().intValue();
                		else
                    			toIndex = conversation.getMessages().size();
				fromIndex = toIndex - max;
			}
		}
		fromIndex = fromIndex < 0 ? 0 : fromIndex;
		toIndex = toIndex > conversation.getMessages().size() ? conversation
				.getMessages().size() : toIndex;
		toIndex = toIndex < fromIndex ? fromIndex : toIndex;

		final List<ArchivedMessage> messages = conversation.getMessages()
				.subList(fromIndex, toIndex);
		for (int i = 0; i < messages.size(); i++) {
			if (i == 0) {
				addMessageElement(chatElement, conversation, messages.get(i), null);
			} else {
				addMessageElement(chatElement, conversation, messages.get(i), messages.get(i - 1));
			}
		}

		if (resultSet != null) {
			if (messages.size() > 0) {
                		resultSet.setFirst((long) fromIndex);
                		resultSet.setFirstIndex(fromIndex);
                		resultSet.setLast((long) toIndex - 1);
            		}
            		resultSet.setCount(conversation.getMessages().size());
            		chatElement.add(resultSet.createResultElement());
		}

		return reply;
	}

	private Conversation retrieve(JID from, RetrieveRequest request) {
		return getPersistenceManager().getConversation(from.toBareJID(),
				request.getWith(), request.getStart());
	}

	private Element addMessageElement(Element parentElement,
			Conversation conversation, ArchivedMessage message, ArchivedMessage previousMessage) {
		final Element messageElement;
		
		final long secs;
		if (previousMessage == null) {
			secs = (message.getTime().getTime() - conversation.getStart().getTime()) / 1000;
		} else {
			secs = (message.getTime().getTime() - previousMessage.getTime().getTime()) / 1000;
		}
		
		messageElement = parentElement.addElement(message.getDirection()
				.toString());
		messageElement.addAttribute("secs", Long.toString(secs));
		if (message.getWithJid() != null) {
			messageElement.addAttribute("jid", message.getWithJid().toBareJID());
		}
		messageElement.addElement("body").setText(message.getBody());

		return messageElement;
	}
}
