package org.opengroupware.jope.servlets;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Enumeration;
import java.util.HashMap;

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

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.opengroupware.jope.appserver.WOCookie;
import org.opengroupware.jope.appserver.WORequest;

/*
 * We need to track the servlet response because the Servlet API service()
 * method already has the pointer to the response. Which in turn is needed
 * for content streaming.
 */

public class WOServletRequest extends WORequest {
  private static final Log servLog = LogFactory.getLog("WOServletAdaptor");

  HttpServletRequest  sRequest;
  HttpServletResponse sResponse;
  
  public WOServletRequest(HttpServletRequest _rq, HttpServletResponse _r) {
    super();
    this.init(_rq, _r);
  }
  
  protected void init(HttpServletRequest _rq, HttpServletResponse _r) {
    this.init(_rq.getMethod(), _rq.getRequestURI(), _rq.getProtocol(),
        null /* headers  */,
        null /* contents */,
        null /* userInfo */);

    this.sRequest  = _rq;
    this.sResponse = _r;

    this.loadHeadersFromServletRequest(_rq);
    this.loadCookies();
    
    /* Note: we need to load form values first, because when we load the
     *       content, we need to process them on our own.
     */
    this.loadFormValuesFromRequest(_rq);
    this.loadContentFromRequest(_rq);
  }
  
  /* loading WORequest data from the Servlet */
  
  protected void loadHeadersFromServletRequest(HttpServletRequest _rq) {
    Enumeration e = _rq.getHeaderNames();
    while (e.hasMoreElements()) {
      String name = (String)e.nextElement();
      
      Enumeration ve = _rq.getHeaders(name);
      name = name.toLowerCase();
      while (ve.hasMoreElements()) {
        String v = (String)ve.nextElement();
        this.appendHeader(v, name);
      }
    }
  }
  
  protected void loadCookieFromHeaderString(String _v) {
    WOCookie cookie = WOCookie.parseCookieString(_v);
    if (cookie == null) {
      servLog.error("could not parse cookie: '" + _v + "'");
      return;
    }
    
    this.addCookie(cookie);
  }
  
  protected void loadCookies() {
    for (String v: this.headersForKey("cookie"))
      this.loadCookieFromHeaderString(v);
  }
  
  protected IOException loadContentFromStream(int len, InputStream _in) {
    // TODO: process content-length
    // TODO: directly load into contents buffer w/o copying
    // TODO: deal with requests which have no content-length?
    // TODO: add support for streamed input?
    
    if (len < 1)
      return null; /* no content, no error */
    
    try {
      byte[] buffer = new byte[4096];
      int gotlen, pos = 0;
      
      this.contents = new byte[len];
      
      while ((gotlen = _in.read(buffer, pos, len - pos)) != -1)
        pos += gotlen;
    }
    catch (IOException ioe) {      
      // TODO: what to do with failed requests?
      return ioe;
    }
    
    return null; /* everything allright */
  }
  
  protected void loadFormValuesFromRequest(HttpServletRequest _rq) {
    servLog.debug("loading form values from Servlet request ...");
    
    this.formValues = new HashMap<String, Object[]>(16);
    
    Enumeration e = _rq.getParameterNames();
    while (e.hasMoreElements()) {
      String   name = (String)e.nextElement();
      String[] vals = _rq.getParameterValues(name);
      this.formValues.put(name, vals);
    }
  }
  
  protected void loadContentFromRequest(HttpServletRequest _rq) {
    servLog.debug("loading content from Servlet request ...");
    
    InputStream is = null;
    
    try {
      is = _rq.getInputStream();
    }
    catch (IOException ioe) {
      // TODO: could be a real exception? we might need to compare content-len?
    }
    
    if (is != null)
      this.loadContentFromStream(_rq.getIntHeader("content-length"), is);
  }
  
  /* accessors */
  
  public HttpServletRequest servletRequest() {
    return this.sRequest;
  }
  public HttpServletResponse servletResponse() {
    return this.sResponse;
  }
  
  /* streaming support */
  
  public OutputStream outputStream() {
    if (this.sResponse == null)
      return null;
    
    try {
      return this.sResponse.getOutputStream();
    }
    catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
      return null;
    }
  }
}
