// ServletCommand.java
// $Id: ServletCommand.java,v 1.4 1997/07/30 14:01:13 ylafon Exp $  
// (c) COPYRIGHT MIT and INRIA, 1997.
// Please first read the full copyright statement in file COPYRIGHT.html

package w3c.jigsaw.ssi.servlets;

import java.util.*;
import java.net.*;

import w3c.www.http.*;
import w3c.jigsaw.http.*;
import w3c.jigsaw.resources.*;
import w3c.jigsaw.servlet.*;
import w3c.util.*;
import w3c.jigsaw.ssi.*;

/**
 * Implementation of the SSI <code>servlet</code> command.
 * Servlet can be executed 
 * simply by providing a url path to a servlet class.
 * @author Benoit Mahe <bmahe@sophia.inria.fr> 
 */
public class ServletCommand implements Command {
  private final static String  NAME  = "servlet";
  private final static boolean debug = true;
    
  private static final String keys[] = {
    "code",
    "param",
    "value",
    "name"
  };

  protected static Hashtable wrappers = null; // <classname , wrapper>

  static {
    wrappers = new Hashtable(10);
  }

  protected void addParam(Dictionary d, String name, 
			  String param, String value) 
  {
    Hashtable params = (Hashtable)d.get(getClass().getName()+"."+name);
    if (params == null) {
      params = new Hashtable(5);
      params.put(param,value);
    } else {
      Object ovalue = params.get(param);
      if (ovalue == null) {
	params.put(param,value);
      } else  if (ovalue instanceof String[]) {
	String oldValues [] = (String[])ovalue;
	String newValues [] = new String[oldValues.length+1];
	System.arraycopy(oldValues,0,newValues,0,oldValues.length);
	newValues[oldValues.length] = value;
	params.put(param,newValues); 
      } else {
	String newValues [] = new String[2];
	newValues[0] = (String)ovalue;
	newValues[1] = value;
	params.put(param,newValues);
      }
    }
    d.put(getClass().getName()+"."+name, params);
  }

  protected Hashtable getParams(Dictionary d, String name) {
    return (Hashtable) d.get(getClass().getName()+"."+name);
  }

  public String getName() {
    return NAME;
  }

  public String getValue(Dictionary variables, String var) {
    return null;
  }

  protected boolean isRemote(String code) {
    try {
      URL url = new URL(code);
    } catch (MalformedURLException ex) {
      return false;
    }
    return true;
  }

  public Reply execute(SSIResource resource
		       , Request request
		       , ArrayDictionary parameters
		       , Dictionary variables) {
    Object values[] = parameters.getMany(keys);
    String code     = (String) values[0];
    String param    = (String) values[1];
    String value    = (String) values[2];
    String name     = (String) values[3];

    if (name != null) {
      if ((param != null) && (value != null)) {
	//store a new param for servlet "name"
	addParam(variables,name,param,value);
      }
      if (code != null) { // remote or not ??
	ServletWrapper wrapper = (ServletWrapper)wrappers.get(code);
	if (wrapper == null) { //lookup for wrapper
	  httpd server = resource.getServer();
	  HTTPResource root = server.root;
	  try {
	    LookupState ls = new LookupState(code);
	    LookupResult lr = new LookupResult(root);
	    HTTPResource wrap = null;
	    if (root.lookup(ls,lr))
	      wrap = lr.getTarget();
	    if ((wrap != null) && (wrap instanceof ServletWrapper)) {
	      wrapper = (ServletWrapper)wrap;
	      wrappers.put(code,wrapper);
	    }
	  } catch (HTTPException ex) {
	    ex.printStackTrace();
	    wrapper = null;
	  }
	}
	if (wrapper != null) {
	  //initialize the wrapper (params)
	  Hashtable params = getParams(variables, name);
	  request.setState(JigsawHttpServletRequest.STATE_PARAMETERS,params);
	  //perform the request
	  try {
	    Request req = (Request)request.getClone();
	    req.setState(JigsawHttpServletResponse.REMOVE_HEADER, 
			 Boolean.TRUE);
	    return wrapper.perform(req);
	  } catch (HTTPException ex) {
	    ex.printStackTrace();
	    // return default reply
	  }
	}
      }
    }
    // We are NOT doing notMod hack here (tricky and useless ?)
    Reply reply = resource.createCommandReply(request, HTTP.OK);
    return reply;
	
  }
}
