/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package com.rebelmonkey.monkeywrench.mweb.api;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpSession;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.sun.enterprise.web.connector.grizzly.comet.CometContext;
import com.sun.enterprise.web.connector.grizzly.comet.CometEngine;
import com.sun.enterprise.web.connector.grizzly.comet.CometEvent;
import com.sun.enterprise.web.connector.grizzly.comet.CometHandler;

/**
 * This class provdes static methods that call the MWEBS2C methods on the actual
 * MwebServlet. It is provided as a convenience and code cleanliness option for
 * other Servlets wishing to use the Mweb services.
 * 
 * This class only exists to hold static methods and may not be instantiated.
 * 
 * @author jeffpk
 */
public class MWeb {
	static final Logger logger = LoggerFactory.getLogger(MWeb.class);
	static final String MWEBPREFIX = "__MWEB_";
	static final String MWEBSERVLETURI = "/MWEB";
	static boolean initialized = false;
	static CometContext context;
	static Object initLock = new Object();

	private MWeb() {
		// makes a non-instanceable class
	}

	// utilities, might belong elsewhere

	public static CometContext getCometContext() {
		synchronized (initLock) {
			if (!initialized) { // initialize
				CometEngine engine = CometEngine.getEngine();
				context = engine.register("/MWEB/cometcontext");
				context.setBlockingNotification(true);
				initialized = true;
			}
			return context;
		}
	}

	public static ServletContext getMWEBServletContext(HttpSession session) {
		return session.getServletContext().getContext(MWEBSERVLETURI);
	}

	// API begins

	public static void addUserToChannel(String userName, String channelName)
			throws IOException {
		doNotification("addUserToChannel", "userName", userName, "channelName",
				channelName);
	}

	public static void removeUserFromChannel(String userName, String channelName)
			throws IOException {
		doNotification("removeUserFromChannel", "userName", userName,
				"channelName", channelName);
	}

	public static void addDataFilter(String userName, Class filterClass)
			throws IOException {
		Class[] interfaces = filterClass.getInterfaces();
		for (Class inter : interfaces) {
			if (inter == MWEBDataFilter.class) { // is a valid filter
				doNotification("addDataFilter", "filterClass", filterClass
						.getName());
			}
		}
		logger
				.error("Tried to add data filter that does not implement MWEBDataFilter: "
						+ filterClass.getName());
	}

	public static void removeDataFilter(String userName, Class filterClass)
			throws IOException {
		Class[] interfaces = filterClass.getInterfaces();
		for (Class inter : interfaces) {
			if (inter == MWEBDataFilter.class) { // is a valid filter
				doNotification("removeDataFilter", "filterClass", filterClass
						.getName());
			}
		}
		logger
				.error("Tried to remove data filter that does not implement MWEBDataFilter: "
						+ filterClass.getName());
	}

	public static void sendConnectedMessage(String userName) throws IOException {
		doNotification("connected", "userName", userName);
	}

	/**
	 * @throws IOException
	 * @see MWEBS2C#sendPrivatePacket(long, String)
	 */
	public static void sendPrivatePacket(String from, String to, String data)
			throws IOException {
		Properties props = new Properties();
		props.put("packetType", "private");
		props.put("userName", to);
		props.put("data", data);
		transmit(from, props);
	}

	public static void sendChannelPacket(String from, String chanName,
			String data) throws IOException {
		Properties props = new Properties();
		props.put("packetType", "channel");
		props.put("channelName", chanName);
		props.put("data", data);
		transmit(from, props);
	}

	private static void doNotification(String notificationType,
			String... properties) throws IOException {
		Properties props = new Properties();
		props.put("notificationType", notificationType);
		for (int i = 0; i < properties.length; i += 2) {
			props.put(properties[i], properties[i + 1]);
		}
		getCometContext().notify(props, CometEvent.NOTIFY);
	}

	private static void transmit(String from, Properties props)
			throws IOException {
		props.put("from", from);
		getCometContext().notify(props, CometEvent.READ);
	}

}
