package org.jboss.seam.remoting;

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

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.jboss.seam.contexts.Lifecycle;
import org.jboss.seam.contexts.ServletLifecycle;
import org.jboss.seam.core.Manager;
import org.jboss.seam.remoting.messaging.RemoteSubscriber;
import org.jboss.seam.remoting.messaging.SubscriptionRegistry;
import org.jboss.seam.remoting.messaging.SubscriptionRequest;
import org.jboss.seam.util.XML;
import org.jboss.seam.web.ServletContexts;

/**
 *
 * @author Shane Bryzak
 */
public class SubscriptionHandler extends BaseRequestHandler implements RequestHandler
{

  /**
   * The entry point for handling a request.
   *
   * @param request HttpServletRequest
   * @param response HttpServletResponse
   * @throws Exception
   */
  public void handle(HttpServletRequest request, HttpServletResponse response)
      throws Exception
  {
    // We're sending an XML response, so set the response content type to text/xml
    response.setContentType("text/xml");

    // Parse the incoming request as XML
    SAXReader xmlReader = XML.getSafeSaxReader();
    Document doc = xmlReader.read(request.getInputStream());
    Element env = doc.getRootElement();

    Element body = env.element("body");

    // First handle any new subscriptions
    List<SubscriptionRequest> requests = new ArrayList<SubscriptionRequest>();

    List<Element> elements = body.elements("subscribe");
    for (Element e : elements)
    {
      requests.add(new SubscriptionRequest(e.attributeValue("topic")));
    }

    ServletLifecycle.beginRequest(request);
    try
    {
      ServletContexts.instance().setRequest(request);

      Manager.instance().initializeTemporaryConversation();
      ServletLifecycle.resumeConversation(request);

      for (SubscriptionRequest req : requests)
      {
        req.subscribe();
      }

      // Then handle any unsubscriptions
      List<String> unsubscribeTokens = new ArrayList<String>();

      elements = body.elements("unsubscribe");
      for (Element e : elements) 
      {
        unsubscribeTokens.add(e.attributeValue("token"));
      }

      for (String token : unsubscribeTokens) 
      {
        RemoteSubscriber subscriber = SubscriptionRegistry.instance().
                                      getSubscription(token);
        if (subscriber != null)
        {
          subscriber.unsubscribe();
        }
      }
    }
    finally
    {
      Lifecycle.endRequest();
    }

    // Package up the response
    marshalResponse(requests, response.getOutputStream());
  }

  private void marshalResponse(List<SubscriptionRequest> requests, OutputStream out)
      throws IOException
  {
    out.write(ENVELOPE_TAG_OPEN);
    out.write(BODY_TAG_OPEN);

    for (SubscriptionRequest req : requests)
    {
      req.marshal(out);
    }

    out.write(BODY_TAG_CLOSE);
    out.write(ENVELOPE_TAG_CLOSE);
    out.flush();
  }

}
