// RelocateFrame.java
// $Id: RelocateFrame.html,v 1.3 1999/10/27 22:10:36 ylafon 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;

/**
 * Emit a HTTP redirect.
 */
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);
    }

    protected 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.
     */

    protected 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.toExternalForm()+pathinfo);
			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 ;
	}
    }

}