/*
 * $Header: /home/cvspublic/jakarta-slide/src/webdav/server/org/apache/slide/webdav/logger/XHttpServletResponseFacade.java,v 1.6 2004/07/28 09:32:35 ib Exp $
 * $Revision: 1.6 $
 * $Date: 2004/07/28 09:32:35 $
 *
 * ====================================================================
 *
 * Copyright 1999-2002 The Apache Software Foundation 
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */


package org.apache.slide.webdav.logger;

import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.Writer;
import java.util.Enumeration;
import java.util.Vector;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

import org.apache.slide.common.Domain;

/**
 * This class supports additional set-methods and a re-readable
 * inputstream to the interface javax.servlet.http.HttpServletResponse.
 *
 *            Christopher Lenz (cmlenz at apache.org)
 *
 * @version   0.1
 *
 * @invariant (inputStream != null)
 *
 * @see       javax.servlet.http.HttpServletResponse
 *
 */
public class XHttpServletResponseFacade extends HttpServletResponseWrapper
{

    
    public static final String DEFAULT_CHAR_ENCODING = "8859_1";

    
    // default implementation will just append everything here
    StringBuffer body=null;

    protected HttpServletRequest request;

    private int statusCode = -1;
    private String statusText = "";
    
    public void setRequest(HttpServletRequest request) {
        this.request = request;
    }

    public HttpServletRequest getRequest() {
        return request;
    }
    
    /**
     * true - if outputstream can write using a stream; false otherwise.
     */
    private boolean usingStream = false;
    
    /**
     * true - if outputstream can write using a writer; false otherwise.
     */
    private boolean usingWriter = false;

    /**
     * output stream used for building the writer.
     *
     * @see javax.servlet.ServletOutputStream
     */
    XServletOutputStreamFacade osFacade = null;
    
    /**
     * writer which uses the output stream.
     *
     * @see java.io.PrintWriter
     */
    PrintWriter writer = null;

    /**
     * response headers
     */
    Vector responseHeaders = new Vector();
    public Enumeration getResponseHeaders() {
        return responseHeaders.elements();
    }
    
    
    /**
     * This constructor creates an re-writable HttpServletResüpmse.
     *
     * @pre        (response != null)
     * @post
     *
     * @param      response   HttpServletResponse
     *
     * @time
     * @space
     */
    public XHttpServletResponseFacade(HttpServletResponse response) {
        super(response);
        Domain.debug("Create XHttpServletResponseFacade");
    }


    // -------------------- Public methods --------------------

    /**
     * Adds the specified cookie to the response.
     *
     * @param      cookie - the Cookie to return to the client
     *
     * @return     none
     */
    public void addCookie(javax.servlet.http.Cookie cookie) {
        responseHeaders.add(
            new XResponseHeader(
                "Cookie",
                cookie.getName() + " " +
                cookie.getValue() + " " +
                cookie.getDomain()
                )
            );
        super.addCookie(cookie);
    }
    
    /**
     * Returns a ServletOutputStream suitable for writing binary data in the response.
     *
     * @return     a ServletOutputStream for writing binary data
     */
    public ServletOutputStream getOutputStream()
        throws IOException {
        Domain.debug("ENTER: XHttpServletResponseFacade:getOutputStream()");
        if ( usingWriter ) {
            throw new IllegalStateException("Writer is already being used for this response");
        }
        usingStream = true;

        if( osFacade == null ) {
            osFacade = new XServletOutputStreamFacade(
                super.getOutputStream(),
                super.getCharacterEncoding());
        }
            
        Domain.debug("LEAVE: XHttpServletResponseFacade:getOutputStream()");
        return osFacade;
    }

    /**
     * Returns a PrintWriter object that can send character text to the client.
     *
     * @return     a PrintWriter object that can return character data to the client
     */
    public PrintWriter getWriter() throws IOException {
        Domain.debug("ENTER: XHttpServletResponseFacade:getWriter()");
        if (usingStream) {
            throw new IllegalStateException("OutputStream is already being used for this response");
        }
        usingWriter= true ;

        if( writer == null ) {
            writer = new XServletWriterFacade( super.getWriter() );
        }

        Domain.debug("LEAVE: XHttpServletResponseFacade:getWriter()");
        return writer;
    }

    public PrintWriter getWriter(ServletOutputStream outs) throws IOException {
        Domain.debug("ENTER: XHttpServletResponseFacade:getWriter(ServletOutputStream)");
        if(writer!=null) return writer;
        // it already did all the checkings
    
        //hak started = true;
        usingWriter = true;
    
        //  writer = new XServletWriterFacade( getConverter(outs), this);
        Domain.debug("LEAVE: XHttpServletResponseFacade:getWriter(ServletOutputStream)");
        return writer;
    }

    public Writer getConverter( ServletOutputStream outs ) throws IOException {
        String encoding = getCharacterEncoding();
        OutputStreamWriter osWriter;
        if (encoding == null) {
            // use default platform encoding - is this correct ?
            osWriter = new OutputStreamWriter(outs);
        } else {
            try {
                osWriter = new OutputStreamWriter(outs, encoding);
            } catch (java.io.UnsupportedEncodingException ex) {
                // XXX log it
                System.out.println("Unsuported encoding: " + encoding );
                return new OutputStreamWriter(outs);
            }
        }
        return osWriter;
    }

    /**
     * Sets a response header with the given name and date-value.
     *
     * @param      name - the name of the header to set
     *            value - the assigned date value
     */
    public void setDateHeader(String name, long date) {
        responseHeaders.add(new XResponseHeader(name, String.valueOf(date)));
        super.setDateHeader(name, date);
    }

    /**
     * Adds a response header with the given name and date-value.
     *
     * @param      name - the name of the header to set
     *            value - the additional date value
     */
    public void addDateHeader(String name, long date) {
        responseHeaders.add(new XResponseHeader(name, String.valueOf(date)));
        super.addDateHeader(name, date);
    }

    /**
     * Sets a response header with the given name and value.
     *
     * @param      name - the name of the header
     *            value - the header value
     */
    public void setHeader(String name, String value) {
        responseHeaders.add(new XResponseHeader(name, value));
        super.setHeader(name, value);
    }

    /**
     * Adds a response header with the given name and value.
     *
     * @param      name - the name of the header
     *            value - the header value
     */
    public void addHeader(String name, String value) {
        responseHeaders.add(new XResponseHeader(name, value));
        super.addHeader(name, value);
    }

    /**
     * Sets a response header with the given name and integer value.
     *
     * @param      name - the name of the header
     *            value - the assigned integer value
     */
    public void setIntHeader(String name, int value) {
        responseHeaders.add(new XResponseHeader(name, String.valueOf(value)));
        super.setHeader(name, Integer.toString(value));
    }

    /**
     * Adds a response header with the given name and integer value.
     *
     * @param      name - the name of the header
     *            value - the assigned integer value
     */
    public void addIntHeader(String name, int value) {
        responseHeaders.add(new XResponseHeader(name, String.valueOf(value)));
        super.addHeader(name, Integer.toString(value));
    }

    public int getStatus() {
        return statusCode;
    }
    public String getStatusText() {
        return statusText;
    }
    public void setStatus(int sc) {
        statusCode = sc;
        super.setStatus(sc);
    }
    public void setStatus(int sc, String msg) {
        statusCode = sc;
        statusText = msg;
        super.setStatus(sc, msg);
    }
    public void sendError( int sc ) throws IOException {
        statusCode = sc;
        super.sendError(sc);
    }
    public void sendError( int sc, String msg ) throws IOException {
        statusCode = sc;
        statusText = msg;
        super.sendError(sc, msg);
    }

    /**
     * Returns the content of the buffered output stream.
     *
     * @return      copy of outputstream as string.
     */
    public String getResponseBody() throws IOException {
        if ( usingStream ) {
            Domain.debug("XHttpServletResponseFacade:getResponseBody() - usingStream");
            return osFacade.getOutputBuffer();
        } else if ( usingWriter ) {
            Domain.debug("XHttpServletResponseFacade:getResponseBody() - usingWriter");
            return (( XServletWriterFacade )writer).getOutputBuffer();
        } else {
            Domain.debug("XHttpServletResponseFacade:getResponseBody() - nor writer nor stream - osFacade = " + osFacade + " writer = " + writer);
            return "";
        }
    }


}
