/*
 * Copyright 2006-2007 Queplix Corp.
 *
 * Licensed under the Queplix Public License, Version 1.1.1 (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.queplix.com/solutions/commercial-open-source/queplix-public-license/
 *
 * 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 com.queplix.core.utils.www;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.CharArrayWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;

/**
 * <p>Implementation of http servlet response wrapper</p>
 *
 * @author [ALB] Baranov Andrey
 * @version $Revision: 1.1.1.1 $ $Date: 2005/09/12 15:31:24 $
 */

public class HSRWImpl
        extends HttpServletResponseWrapper {

    public static final int BUFFER_SIZE = 3
            * 1024; // Value got from Reflective report.

    // constructor parameter
    private OutputStream os;

    // print writer
    private PrintWriter pw;
    private CharArrayWriter caw;

    // output stream
    private ServletOutputStream sos;
    private ByteArrayOutputStream baos;

    protected int contentLength;
    protected String contentType;
    protected String encoding;

    /**
     * Constructor.
     *
     * @param response Servlet response
     */
    public HSRWImpl(HttpServletResponse response) {
        this(response, null);
    }

    /**
     * Constructor.
     *
     * @param response HttpServletResponse
     * @param os       ServletOutputStream
     */
    public HSRWImpl(HttpServletResponse response, OutputStream os) {

        super(response);

        this.encoding = "UTF-8";
        this.os = os;
    }

    /**
     * Returns value of property Writer
     *
     * @return value of property Writer
     * @throws IOException General input/output exception
     */
    public PrintWriter getWriter()
            throws IOException {

        if(pw == null) {
            if(os != null) {
                OutputStreamWriter osw = new OutputStreamWriter(os, encoding);
                pw = new PrintWriter(new BufferedWriter(osw));
            } else {
                caw = new CharArrayWriter(BUFFER_SIZE);
                pw = new PrintWriter(caw);
            }
        }
        return pw;
    }

    /**
     * Returns value of property OutputStream
     *
     * @return value of property OutputStream
     * @throws IOException General input/output exception
     */
    public ServletOutputStream getOutputStream()
            throws IOException {

        if(sos == null) {
            if(os == null) {
                baos = new ByteArrayOutputStream(BUFFER_SIZE);
                sos = new ServletOutputStreamImpl(baos);
            } else {
                sos = new ServletOutputStreamImpl(os);
            }
        }
        return sos;
    }

    /**
     * Sets value of property ContentType
     *
     * @param s content type
     */
    public void setContentType(String s) {
        super.setContentType(s);
        contentType = s;
    }

    /**
     * Returns value of property ContentType
     *
     * @return value of property ContentType
     */
    public String getContentType() {
        return contentType;
    }

    /**
     * Sets value of property ContentLength
     *
     * @param len length
     */
    public void setContentLength(int len) {
        contentLength = len;
    }

    /**
     * Returns value of property ContentLength
     *
     * @return value of property ContentLength
     */
    public int getContentLength() {
        return contentLength;
    }

    /**
     * Returns value of property Data
     *
     * @return value of property Data
     * @throws IOException
     */
    public byte[] getData()
            throws IOException {

        try {
            if(sos != null) {
                if(baos == null) {
                    throw new IllegalStateException(
                            "ByteArrayOutputStream not initialized");
                }
                return baos.toByteArray();
            } else {
                if(caw == null) {
                    throw new IllegalStateException(
                            "CharArrayWriter not initialized");
                }
                return caw.toString().getBytes(encoding);
            }

        } catch (UnsupportedEncodingException ex) {
            throw new IllegalStateException(ex.getMessage());
        }
    }

    /**
     * Returns value of property Data
     *
     * @return value of property Data
     */
    public String getString() {
        try {
            if(sos != null) {
                if(baos == null) {
                    throw new IllegalStateException(
                            "ByteArrayOutputStream not initialized");
                }
                return baos.toString(encoding);
            } else {
                if(caw == null) {
                    throw new IllegalStateException(
                            "CharArrayWriter not initialized");
                }
                return caw.toString();
            }
        } catch (UnsupportedEncodingException ex) {
            throw new IllegalStateException(ex.getMessage());
        }
    }

    /**
     * Flushes output buffers.
     *
     * @throws IOException
     */
    public void flush()
            throws IOException {

        if(sos != null) {
            sos.flush();
        } else if(pw != null) {
            pw.flush();
        }
    }

    // ----------------------------------------------------------------- inner class

    //
    // ServletOutputStream implementation
    //

    protected static class ServletOutputStreamImpl
            extends ServletOutputStream {

        OutputStream os;

        public ServletOutputStreamImpl(OutputStream os) {
            this.os = os;
        }

        public void write(int i)
                throws IOException {

            os.write(i);
        }

    } // end ServletOutputStreamImpl
}
