package org.jivesoftware.openfire.plugin.gojara.messagefilter.processors;

import java.util.Timer;
import java.util.TimerTask;

import org.dom4j.Attribute;
import org.dom4j.Element;
import org.dom4j.tree.DefaultAttribute;
import org.dom4j.tree.DefaultElement;
import org.jivesoftware.openfire.interceptor.InterceptorManager;
import org.jivesoftware.openfire.interceptor.PacketInterceptor;
import org.jivesoftware.openfire.interceptor.PacketRejectedException;
import org.jivesoftware.openfire.session.Session;
import org.jivesoftware.util.JiveGlobals;
import org.xmpp.packet.IQ;
import org.xmpp.packet.Packet;

/**
 * This implements a special IQ package for Spark client. Spark checks the
 * disco#info package send from external component for a <registered> tag.
 * Because spectrum does not support this feature we have to modify the disco
 * package from spectrum with the registered tag if the user is registered with
 * this gateway. Part of command pattern used in {@link RemoteRosterInterceptor}
 * 
 * @author Holger Bergunde
 * 
 */
public class DiscoIQRegisteredProcessor extends AbstractRemoteRosterProcessor {
	private boolean _isRegistered = false;

	public DiscoIQRegisteredProcessor() {
		Log.info("Created DiscoIQRegisteredProcessor");
	}

	@Override
	public void process(Packet packet, final String subdomain, String to, String from) throws PacketRejectedException {
		Log.debug("Processing packet in DiscoIQRegisteredProcessor for " + subdomain);
		// Check if the jabber:iq:register is enabled in admin panel
		boolean isFeatureEnabled = JiveGlobals.getBooleanProperty("plugin.remoteroster.sparkDiscoInfo", false);
		if (!isFeatureEnabled) {
			Log.debug("Spark extension is deactivated. Won't change the disco#info");
			return;
		}

		final InterceptorManager interceptorManager = InterceptorManager.getInstance();
		final PacketInterceptor interceptor = new PacketInterceptor() {

			public void interceptPacket(Packet packet, Session session, boolean incoming, boolean processed) throws PacketRejectedException {
				if (!processed && incoming) {
					if (packet instanceof IQ) {
						IQ iqPacket = (IQ) packet;
						Element packetElement = iqPacket.getChildElement();
						if (packetElement == null)
							return;
						String ns = iqPacket.getChildElement().getNamespace().getURI();
						if (iqPacket.getType().equals(IQ.Type.result) && ns.equals("jabber:iq:register")
								&& iqPacket.getFrom().toString().equals(subdomain)) {
							// Check if we are already registered
							setRegistered(iqPacket.toString().contains("<registered/>"));
							throw new PacketRejectedException();
						} else if (iqPacket.getType().equals(IQ.Type.result) && ns.equals("http://jabber.org/protocol/disco#info")
								&& iqPacket.getFrom().toString().equals(subdomain)) {

							/*
							 * This is the answer of the disco#info from spark
							 * to our component. add the jabber:iq:register
							 * feature if we are registered
							 */
							if (isRegistered()) {
								Log.debug("Modifying disco#info packge to send registered iq feature to Spark user "
										+ iqPacket.getTo().toString());
								Attribute attribut = new DefaultAttribute("var", "jabber:iq:registered");
								iqPacket.getChildElement().addElement("feature").add(attribut);
							}
						}
					}
				}
			}
		};

		Log.debug("Creating my own listener for jabber:iq:register result to external component " + subdomain);
		interceptorManager.addInterceptor(interceptor);

		IQ askComponent = new IQ();
		askComponent.setTo(to);
		askComponent.setFrom(from);
		askComponent.setType(IQ.Type.get);
		Element query = new DefaultElement("query");
		query.addNamespace("", "jabber:iq:register");
		askComponent.setChildElement(query);

		// Remove the package intercepter in 1sec
		TimerTask removeInterceptorTask = new TimerTask() {

			@Override
			public void run() {
				Log.debug("Removing my created listener for jabber:iq:register. Component " + subdomain);
				interceptorManager.removeInterceptor(interceptor);
			}
		};

		Timer timer = new Timer();
		timer.schedule(removeInterceptorTask, 1000);

		// Send the register query to component
		dispatchPacket(askComponent);

	}

	private boolean isRegistered() {
		return _isRegistered;
	}

	private void setRegistered(boolean bool) {
		_isRegistered = bool;
	}
}
