// Reply.java
// $Id: Reply.java,v 1.15 1997/02/05 21:44:28 abaird Exp $
// (c) COPYRIGHT MIT and INRIA, 1996.
// Please first read the full copyright statement in file COPYRIGHT.html

package w3c.jigsaw.http ;

import java.io.* ;

import w3c.www.mime.*;
import w3c.www.http.*;

public class Reply extends HttpReplyMessage {
    protected static HttpMimeType  DEFAULT_TYPE = null;
    protected static HttpTokenList CONNECTION   = null;

    static {
	String connection[] = { "Keep-Alive" };
	CONNECTION   = HttpFactory.makeStringList(connection);
	DEFAULT_TYPE = HttpFactory.makeMimeType(MimeType.TEXT_HTML);
    }

    InputStream is     = null;
    Client      client = null;
    boolean     keep   = true;

    public void setStatus(Integer status) {
	setStatus(status.intValue());
    }

    public boolean hasContentLength() {
	return hasHeader(H_CONTENT_LENGTH);
    }

    public boolean hasContentType() {
	return hasHeader(H_CONTENT_TYPE);
    }

    public void setKeepAlive(String value) {
	setValue("Keep-Alive", value);
    }

    public void setProxyConnection(String value) {
	setValue("Proxy-Connection", value);
    }

    public boolean keepProxyConnection() {
	throw new RuntimeException("keepProxyConnection: not implemented!");
    }

    /**
     * @deprecated
     */

    public FileDescriptor getInputFileDescriptor() {
	return null;
    }
    
    public void setKeepConnection(boolean onoff) {
	this.keep = onoff;
    }

    public boolean tryKeepConnection() {
	if ( ! keep ) {
	    if ((major >= 1) && (minor >= 1))
		addConnection("close");
	    return false;
	} else if ( major >= 1 ) {
	    if ( minor >= 1 )
		return true;
	    if ( hasContentLength() || (is == null)) {
		if ( is_proxy )
		    setHeaderValue(H_PROXY_CONNECTION, CONNECTION);
		else
		    setHeaderValue(H_CONNECTION, CONNECTION);
		return true;
	    }
	}
	return false;
    }

    /**
     * Is this reply a proxy reply.
     */
    protected boolean is_proxy = false;

    /**
     * Mark this reply as being a proxy reply.
     */

    public void setProxy (boolean onoff) {
	is_proxy = onoff;
    }

    /**
     * Sets the reply stream to the given HtmlGenerator stream.
     * @param g The HtmlGenerator whose output is to be used as the reply body.
     */

    public void setStream (w3c.jigsaw.html.HtmlGenerator g) {
	g.close() ;
	setContentLength (g.length()) ;
	setContentType (g.getMimeType()) ;
	setStream (g.getInputStream()) ;
    }

    /**
     * Open this reply body stream.
     * This is used to send the reply body back to the client.
     * @return An InputStream containing the reply body, which is dumped
     *    back to the client.
     */

    public InputStream openStream () {
	return is ;
    }

    public void setStream(InputStream is) {
	this.is = is;
    }

    /**
     * Should this reply be chunked ?
     * @return If so, the reply should prepare itself to send back the
     *     appropriate transfer encoding header, and return 
     *     <strong>true</strong>, otherwise it should just return
     *     <strong>false</strong>.
     */

    protected Boolean chunkable = null ;
    // FIXME should be an HttpTokenList
    protected static String chunked[] = { "chunked" };

    public boolean canChunkTransfer() {
	// Have we already compute this ?
	if ( chunkable == null ) {
	    // Compute wether we can chunk the reply:
	    if ( hasContentLength() || (is == null)) {
		chunkable = Boolean.FALSE ;
	    } else if ((major >= 1) && (minor >= 1)) {
		setTransferEncoding(chunked);
		chunkable = Boolean.TRUE ;
	    } else {
		chunkable = Boolean.FALSE ;
	    }
	}
	return (chunkable == Boolean.TRUE) ;
    }

    /**
     * Set this reply content.
     * This method allows to set the reply content to a simple String instance.
     * @param msg The reply content.
     */

    public void setContent (String msg) {
	if ( ! hasContentType() )
	    setHeaderValue(H_CONTENT_TYPE, DEFAULT_TYPE) ;
	setContentLength (msg.length()) ;
	is = new StringBufferInputStream (msg) ;
    }

    /**
     * Create a new Reply instance for the given client.
     * @param client The client to who this reply  is directed.
     */

    public Reply (Client client) {
	this.client = client ;
    }

    /**
     * Create a new reply for the given client.
     * @param client The client ot who the reply is directed.
     * @reply status The reply status code.
     */

    public Reply (Client client, short major, short minor, int status) {
	this (client) ;
	this.major = major;
	this.minor = minor;
	this.keep  = true;
	this.setServer((client != null) 
		       ? client.getServer().getSoftware()
		       : null);
	this.setStatus (status);
    }
}
