// RelocateFrame.java
// $Id: RelocateFrame.java,v 1.2 1998/01/26 13:21:39 bmahe Exp $
// (c) COPYRIGHT MIT and INRIA, 1996.
// Please first read the full copyright statement in file COPYRIGHT.html

package org.w3c.jigsaw.frames;

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

import org.w3c.tools.resources.*;
import org.w3c.jigsaw.http.*;
import org.w3c.www.http.*;

import org.w3c.tools.resources.ProtocolException;
import org.w3c.tools.resources.NotAProtocolException;

public class RelocateFrame extends HTTPFrame {

  /**
   * Name of the state to hold the PATH_INFO in the request.
   */
  public final static 
  String PATH_INFO = "org.w3c.jigsaw.resources.RelocateResource.PathInfo";

  /**
   * Attribute index - The relocation location.
   */
  protected static int ATTR_LOCATION = -1 ;
  /**
   * Attribute index - Should we also handle extra path infos ?
   */
  protected static int ATTR_HANDLE_PATHINFO = -1;

  static {
    Attribute a = null ;
    Class     c = null ;

    try {
      c = Class.forName("org.w3c.jigsaw.frames.RelocateFrame");
    } catch (Exception ex) {
      ex.printStackTrace() ;
      System.exit(1) ;
    }
    // The location attribute
    a = new StringAttribute("location"
			    , null
			    , Attribute.EDITABLE|Attribute.MANDATORY) ;
    ATTR_LOCATION = AttributeRegistry.registerAttribute(c, a) ;
    // The handle path info attribute
    a = new BooleanAttribute("handle-pathinfo"
			     , Boolean.TRUE
			     , Attribute.EDITABLE);
    ATTR_HANDLE_PATHINFO = AttributeRegistry.registerAttribute(c, a);
  }

  /**
   * Get the location for the relocation
   */

  public String getLocation() {
    return (String) getValue(ATTR_LOCATION, null) ;
  }

  public boolean checkHandlePathInfo() {
    return getBoolean(ATTR_HANDLE_PATHINFO, true);
  }

  public void registerResource(FramedResource resource) {
    super.registerOtherResource(resource);
  }

  public boolean lookupOther(LookupState ls, LookupResult lr) 
    throws ProtocolException
  {
    // Perform our super-class lookup strategy:
    if ( super.lookupOther(ls, lr) ) {
      return true;
    } else if ( ! checkHandlePathInfo() ) {
      return false;
    }
    // Compute PATH INFO, store it as a piece of state in the request:
    StringBuffer pathinfo = new StringBuffer();
    while ( ls.hasMoreComponents() ) {
      pathinfo.append('/');
      pathinfo.append(ls.getNextComponent());
    }
    if (ls.hasRequest() ) {
      Request request = (Request) ls.getRequest();
      request.setState(PATH_INFO, pathinfo.toString());
    }
    lr.setTarget(resource.getResourceReference());
    return true;
  }

  /**
   * Emit a redirect.
   * All GET requests are redirected toward the target location.
   * @param client The client issuing the request.
   * @param request The request to handle.
   * @exception ProtocolException If the request couldn't be handled.
   */

  public Reply getOtherResource (Request request)
    throws ProtocolException
  {
    String location = getLocation() ;
    if ( location == null ) {
      Reply error = request.makeReply(HTTP.INTERNAL_SERVER_ERROR) ;
      error.setContent("The target RelocateResource doesn't define the"
		       + " relocation location. The server is "
		       + " misconfigured.") ;
      throw new HTTPException(error) ;
    } else {
      Reply  reply    = request.makeReply(HTTP.MOVED_TEMPORARILY) ;
      URL    loc      = null;
      try {
	loc = new URL(getURL(request), location);
	if (checkHandlePathInfo()) {
	  String pathinfo = (String) request.getState(PATH_INFO);
	  // Given the way pathinfo is computed, it starts with a /
	  try {
	    if (pathinfo != null)
	      loc = new URL(loc, pathinfo.substring(1));
	    else 
	      resource.getServer().errlog(resource, 
					  "This resource handle Pathinfo "+
					  "but the request has no "+
					  "PATH_INFO state.");
	  } catch (MalformedURLException ex) {
	    resource.getServer().errlog(resource, 
					"This resource handle Pathinfo "+
					"but the request has an invalid "+
					"PATH_INFO state.");
	  }
	}
      } catch (Exception ex) {
	ex.printStackTrace();
      }
      reply.setLocation(loc);
      return reply ;
    }
  }

}
