// JigsawHttpServletRequest.java
// $Id: JigsawHttpServletRequest.java,v 1.12 1997/07/25 14:27:57 bmahe Exp $
// (c) COPYRIGHT MIT and INRIA, 1996.
// Please first read the full copyright statement in file COPYRIGHT.html

package w3c.jigsaw.servlet;

import java.io.*;
import java.util.*;

import javax.servlet.*;
import javax.servlet.http.*;

import w3c.util.*;
import w3c.jigsaw.http.*;
import w3c.jigsaw.forms.*;
import w3c.www.http.*;
import w3c.www.mime.*;
import w3c.jigsaw.auth.AuthFilter; // for auth infos access

class HeaderNames implements Enumeration {
    // The HeaderDescription enumeration
    Enumeration e = null;

    public boolean hasMoreElements() {
	return e.hasMoreElements();
    }

    public Object nextElement() {
	HeaderDescription d = (HeaderDescription) e.nextElement();
	return d.getName();
    }

    HeaderNames(Enumeration e) {
	this.e = e ;
    }

}

/**
 *  @author Alexandre Rafalovitch <alex@access.com.au>
 *  @author Anselm Baird-Smith <abaird@w3.org>
 *  @author Benoit Mahe <bmahe@sophia.inria.fr>
 */

public class JigsawHttpServletRequest implements HttpServletRequest {

    public final static 
    String STATE_PARAMETERS = "w3c.jigsaw.servlet.stateParam";

    private static MimeType type = MimeType.APPLICATION_X_WWW_FORM_URLENCODED ;
    /** 
     * The initial request.
     */
    private Request request = null;
    /**
     * The attached servlet.
     */
    private Servlet servlet = null;
    /**
     * The lazyly computed queryParameters hashtable.
     */
    private Hashtable queryParameters = null;

    private synchronized void prepareQueryParameters()
    {
	if( queryParameters != null )
	    return;
	// What kinf of parameters are we expecting ?
	if ( request.getMethod().equals("POST") ) {
	    // POSTed parameters, check content type:
	    if ((! request.hasContentType())
		|| (type.match(request.getContentType()) < 0) ) 
		return;
	    // Get and decode the request entity:
	    URLDecoder dec = null;
	    try {
		InputStream in = request.getInputStream() ;
		// Notify the client that we are willing to continue
		Client client = request.getClient();
		if ( client != null ) 
		    client.sendContinue();
		//		dec = new URLDecoder (in, true);
		dec = new URLDecoder (in, false);
		queryParameters = dec.parse () ;
	    } catch (URLDecoderException e) {
		queryParameters = null;
	    } catch (IOException ex) {
		queryParameters = null;
	    }
	} else {
	    // URL encoded parameters:
	    String query = request.getQueryString();
	    if (query != null) {
	      InputStream qis = new StringBufferInputStream(query);
	      try {
		queryParameters = new URLDecoder(qis, false).parse();
	      } catch (Exception ex) {
		throw new RuntimeException("Java implementation bug.");
	      }
	    }
	}
	// state parameters
	Hashtable param = (Hashtable)request.getState(STATE_PARAMETERS);
	if (param != null) {
	  if (queryParameters == null)
	    queryParameters = param;
	  else {
	    Enumeration e= param.keys();
	    while (e.hasMoreElements()) {
	      String name = (String)e.nextElement();
	      Object value = queryParameters.get(name);
	      if (value == null)
		queryParameters.put(name,param.get(name));
	      else  if (value instanceof String[]) {
		String oldValues [] = (String[])value;
		String newValues [] = new String[oldValues.length+1];
		System.arraycopy(oldValues,0,newValues,0,oldValues.length);
		newValues[oldValues.length] = (String)param.get(name);
		queryParameters.put(name,newValues);
	      } else {
		String newValues [] = new String[2];
		newValues[0] = (String)param.get(name);
		newValues[1] = (String)value;
		queryParameters.put(name,newValues);
	      }
	    }
	  }
	}
    }

    /**
     * ServletRequest implementation - Get the length of request data.
     * @return An int, or <strong>-1</strong>.
     */

    public int getContentLength()
    {
	return request.getContentLength();
    }

    /**
     * ServletRequest implementation - Get the type of the request's body.
     * @return A String encoded mime type, or <strong>null</strong>.
     */

    public String getContentType()
    {
	w3c.www.mime.MimeType t = request.getContentType();
	return (t == null) ? null : t.toString();
    }

    /**
     * ServletRequest implementation - Get the protocol of that request.
     * @return A String encoded version of the protocol.
     */

    public String getProtocol()
    {
	return request.getVersion();
    }
    
    /**
     * ServletRequest implementation - Get the name of queried server.
     * @return Name of server, as a String.
     */

    public String getServerName()
    {
	return request.getClient().getServer().getHost();
    }
    
    /**
     * ServletRequest implementation - Get the port of queried server.
     * @return A port number (int).
     */

    public int getServerPort()
    {
	return request.getClient().getServer().getLocalPort();
    }

    /**
     * ServletRequest implementation - Get the IP address of requests's sender.
     * @return Numeric IP address, as a String.
     */

    public String getRemoteAddr()
    {
	return request.getClient().getInetAddress().getHostAddress();
    }

    /**
     * ServletRequest implementation - FQDN of request's sender.
     * @return Name of client's machine (FQDN).
     */

    public String getRemoteHost()
    {
	return request.getClient().getInetAddress().getHostName();
    }

    /**
     * ServletRequest implementation - Get real path.
     * Jigsaw realy has no notion of <em>translation</em> stricto
     * sensu (it has much better in fact ;-). This is a pain here.
     * @return Always <strong>null</strong>.
     */

    public String getRealPath(String name) {
	return null;
    }

    /**
     * ServletRequest interface - Get the input stream to read data.
     * @return An input stream instance (may be <strong>null</strong>).
     */
    
    protected ServletInputStream is = null;
    public ServletInputStream getInputStream()
	throws IOException
    {
	// If alredy computed return:
	if ( is != null )
	    return is;
	// Built it:
	InputStream stream = null;
	if ((stream = request.getInputStream()) == null)
	    stream = new ContentLengthInputStream(null, 0);
	return is = new JigsawServletInputStream(stream);
    }
    
    /**
     * ServletRequest implementation - Get a parameter value.
     * @return The String encoded value for the parameter.
     */

    public String getParameter(String name)
    {
	prepareQueryParameters();
	if ( queryParameters != null ) {
	  Object value = queryParameters.get(name);
	  if (value instanceof String[])
	    return ((String[])value)[0];
	  else return (String)value;
	}
	else
	    return null;
    }

     /**
     * ServletRequest implementation - Get the parameters value.
     * @return The String array encoded value for the parameter.
     */

    public String[] getParameterValues(String parameter) {
      Vector V = new Vector(23);
      prepareQueryParameters();
      if (queryParameters == null) 
	return null;
      Object value = queryParameters.get(parameter);
      if (value == null) return null;
      if (value instanceof String[])
	return (String[])value;
      else {
	String [] parameterValues = new String[1];
	parameterValues[0] = (String)value;
	return parameterValues;
      }
    }

    /**
     * ServletRequest implementation - List available parameters.
     * @return An enumeration of parameter names.
     */

    public Enumeration getParameterNames()
    {
	prepareQueryParameters();
	return ((queryParameters == null)
		? new EmptyEnumeration()
		: queryParameters.keys());
    }
    
    /**
     * ServletRequest implementation - Get an attribute of the request.
     * This closely match Jigsaw's notion of request state.
     * @param name The name of the attribute.
     * @return An object that gives the value of the attribute.
     */

    public Object getAttribute(String name) {
	return request.getState(name);
    }

    /**
     * HttpServletRequest implementation - Get the request's method.
     * @return A String instance.
     */

    public  String getMethod()
    {
	return request.getMethod();
    }
    
    /**
     * HttpServletRequest implementation - Get the request's path info.
     * @return A String instance or <strong>null</strong>.
     */

    public  String getPathInfo()
    {
	return (String) request.getState(ServletWrapper.STATE_EXTRA_PATH);
    }
    
    /**
     * HttpServletRequest implementation - Get the request's path translated.
     * @return A String instance or <strong>null</strong>.
     */

    public  String getPathTranslated()
    {
	String pathinfo = getPathInfo();
	if ( pathinfo != null ) 
	    // FIXME
	    return null;
	return null;
    }
    
    /**
     * HttpServletRequest implementation - Get the request's query string.
     * @return A String instance or <strong>null</strong>.
     */

    public  String getQueryString()
    {
	return request.getQueryString();
    }
    
    /**
     * HttpServletRequest implementation - Get the request's user (if any).
     * @return A String instance or <strong>null</strong>.
     */

    public String getRemoteUser()
    {
	return (String) request.getState(AuthFilter.STATE_AUTHUSER);
    }
    
    /**
     * HttpServletRequest implementation - Get the request's auth method.
     * @return A String instance or <strong>null</strong>.
     */

    public String getAuthType() {
	return (String) request.getState(AuthFilter.STATE_AUTHTYPE);
    }

    /**
     * HttpServletRequest implementation - Get a request header as a String.
     * @return A String instance or <strong>null</strong>.
     */

    public String getHeader(String name) {
	return request.getValue(name);
    }

    /**
     * HttpServletRequest implementation - Get a request header as an int.
     * @return An int, or <strong>-1</strong>.
     */

    public int getIntHeader(String name) {
	HeaderValue v = request.getHeaderValue(name);
	if ( v != null ) {
	    Object o = v.getValue();
	    if ((o != null) && (o instanceof Integer))
		return ((Integer) o).intValue();
	}
	return -1;
    }

    /**
     * HttpServletRequest implementation - Get a request header as an date.
     * @return An long (as a number of milliseconds), or <strong>-1</strong>.
     */

    public long getDateHeader(String name) {
	HeaderValue v = request.getHeaderValue(name, null);
	if ( v != null ) {
	    Object o = v.getValue();
	    if ((o != null) && (o instanceof Long)) 
		return ((Long) o).longValue();
	}
	return (long) -1;
    }

    /**
     * HttpServletRequest implementation - Get a all header names.
     * @return An enumeration.
     */

    public Enumeration getHeaderNames() {
	return new HeaderNames(request.enumerateHeaderDescriptions());
    }

    public  String getRequestURI()
    {
	return request.getURL().toExternalForm();
    }
    
    public  String getRequestPath()
    {
	return request.getURLPath();
    }
    
    public  String getServletPath()
    {
	return request.getTargetResource().getURLPath();
    }
    
    JigsawHttpServletRequest(Servlet servlet, Request request) {
	this.servlet = servlet;
	this.request = request;
    }

  // method added 

  public String getScheme() {
    return request.getURL().getProtocol();
  }
  
}


