// RelocateFrame.java
// $Id: RelocateFrame.java,v 1.12 1999/02/22 10:49:01 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.jigsaw.html.HtmlGenerator;
import org.w3c.www.http.*;

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

/**
 * 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;
    /**
     * Attribute index - Is the relocation permanent?
     */
    protected static int ATTR_PERMANENT_REDIRECT = -1;
    /**
     * Attribute index - SHould we use the ambiguous 302?
     */
    protected static int ATTR_USE_302 = -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);
	// the permanent redirection attribute
	a = new BooleanAttribute("permanent-redirect"
				 , Boolean.FALSE
				 , Attribute.EDITABLE);
	ATTR_PERMANENT_REDIRECT = AttributeRegistry.registerAttribute(c, a);
	// should we use the ambiguous 302 response code?
	a = new BooleanAttribute("use-usual-response"
				 , Boolean.TRUE
				 , Attribute.EDITABLE);
	ATTR_USE_302 = AttributeRegistry.registerAttribute(c, a);
    }

    /**
     * Get the location for the relocation
     * @return a string, containing the relative path.
     */

    public String getLocation() {
	return (String) getValue(ATTR_LOCATION, null) ;
    }
    /**
     * Get the path info value
     * @return a boolean
     */
    public boolean checkHandlePathInfo() {
	return getBoolean(ATTR_HANDLE_PATHINFO, true);
    }
    /**
     * Get the permanent redirect flag
     * @return a boolean
     */
    public boolean checkPermanentRedirect() {
	return getBoolean(ATTR_PERMANENT_REDIRECT, false);
    }
     /**
     * Get the "use ambigous 302 response code" flag
     * @return a boolean
     */
    public boolean checkUse302() {
	return getBoolean(ATTR_USE_302, true);
    }   

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

    /**
     * Lookup the target resource when associated with an unknown resource.
     * @param ls The current lookup state
     * @param lr The result
     * @return true if lookup is done.
     * @exception ProtocolException If an error relative to the protocol occurs
     */
    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 = null;
	    URL    loc      = null;
	    if (checkUse302()) 
		reply = request.makeReply(HTTP.FOUND) ;
	    else {
		if (checkPermanentRedirect()) 
		    reply = request.makeReply(HTTP.MOVED_PERMANENTLY) ;
		else
		    reply = request.makeReply(HTTP.TEMPORARY_REDIRECT) ;
	    }
	    try {
		httpd  server = (httpd) getServer();
		String   host = request.getHost(); 
		if (host == null)
		    loc = new URL(server.getURL(), location);
		else {
		    loc = new URL(new URL(server.getURL().getProtocol(),
					  host,server.getURL().getFile()),
				  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);
	    HtmlGenerator g = new HtmlGenerator("Moved");
	    g.append("<P>This resources has moved, click on the link if your"
		     + " browser doesn't support automatic redirection<BR>"+
		     "<A HREF=\""+loc.toExternalForm()+"\">"+
		     loc.toExternalForm()+"</A>");
	    reply.setStream(g);
	    return reply ;
	}
    }

}
