/* 
 * E-XML Library:  For XML, XML-RPC, HTTP, and related.
 * Copyright (C) 2002-2008  Elias Ross
 * 
 * genman@noderunner.net
 * http://noderunner.net/~genman
 * 
 * 1025 NE 73RD ST
 * SEATTLE WA 98115
 * USA
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * $Id$
 */

package net.noderunner.http.servlet;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.Writer;
import java.util.Date;
import java.util.Locale;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;

import net.noderunner.http.ByteArrayDataPoster;
import net.noderunner.http.ContentType;
import net.noderunner.http.DataPoster;
import net.noderunner.http.MessageHeader;
import net.noderunner.http.MessageHeaders;
import net.noderunner.http.ServerResponse;
import net.noderunner.http.StatusLine;

/**
 * Internal implementation.
 * Currently does not support streaming. 
 * 
 * @author Elias Ross
 */
public class HttpServletResponseImpl implements HttpServletResponse {
	
	private MessageHeaders headers;
	private ByteArrayOutputStream baos;
	private int statusCode;
	private String statusReason;
	private String encoding = "ISO-8859-1";
	private Locale locale = Locale.getDefault();
	private PrintWriter pw;
	private ServletOutputStream sos;
	
    public HttpServletResponseImpl() {
    	reset();
    }

	public void addCookie(Cookie c) {
		throw new UnsupportedOperationException();
	}

	public void addDateHeader(String name, long d) {
		String string = new HttpDateFormat().format(new Date(d));
		headers.add(name, string);
	}

	public void addHeader(String name, String value) {
		headers.add(name, value);
	}

	public void addIntHeader(String name, int value) {
		headers.add(name, String.valueOf(value));
	}

	public boolean containsHeader(String name) {
		return headers.getNames().contains(name);
	}

	public String encodeRedirectURL(String url) {
		return url;
	}

	public String encodeRedirectUrl(String url) {
		return url;
	}

	public String encodeURL(String url) {
		return url;
	}

	public String encodeUrl(String url) {
		return url;
	}

	public void sendError(int error) throws IOException {
		statusCode = error;
	}

	public void sendError(int error, String reason) throws IOException {
		statusCode = error;
		statusReason = reason;
	}

	public void sendRedirect(String arg0) throws IOException {
		throw new UnsupportedOperationException();
	}

	public void setDateHeader(String name, long value) {
		headers.remove(name);
		addDateHeader(name, value);
	}

	public void setHeader(String name, String value) {
		headers.remove(name);
		addHeader(name, value);
	}

	public void setIntHeader(String name, int value) {
		headers.remove(name);
		addIntHeader(name, value);
	}

	public void setStatus(int error) {
		statusCode = error;
	}

	public void setStatus(int error, String reason) {
		statusCode = error;
		statusReason = reason;
	}

	public void flushBuffer() throws IOException {
		if (pw != null)
    		pw.flush();
	}

	public int getBufferSize() {
		return baos.size();
	}

	public String getCharacterEncoding() {
		return encoding;
	}

	public String getContentType() {
		return getHeader(MessageHeader.FN_CONTENT_TYPE);
	}

	private String getHeader(String header) {
		return headers.getFieldContent(header);
	}

	public Locale getLocale() {
		return locale;
	}

	public ServletOutputStream getOutputStream() throws IOException {
		if (sos != null)
			return sos;
		
		return sos = new ServletOutputStream() {

			@Override
			public void write(int c) throws IOException {
				baos.write(c);
			}

			@Override
			public void write(byte[] b, int off, int len) throws IOException {
				baos.write(b, off, len);
			}
			
		};
	}

	public PrintWriter getWriter() throws IOException {
		if (pw != null)
			return pw;
		Writer w = new OutputStreamWriter(baos, encoding);
		pw = new PrintWriter(w);
		return pw;
	}

	public boolean isCommitted() {
		return false;
	}

	public void reset() {
		baos = new ByteArrayOutputStream();
    	headers = new MessageHeaders();
    	statusCode = StatusLine.HTTP11_200_OK.getStatusCode();
    	statusReason = StatusLine.HTTP11_200_OK.getReasonPhrase();
	}

	public void resetBuffer() {
		baos.reset();
	}

	public void setBufferSize(int size) {
	}

	public void setCharacterEncoding(String encoding) {
		if (encoding == null)
			throw new IllegalArgumentException();
		this.encoding = encoding;
	}

	public void setContentLength(int len) {
		setIntHeader(MessageHeader.FN_CONTENT_LENGTH, len);
	}

	public void setContentType(String type) {
		if (type == null)
			throw new NullPointerException();
		String enc = ContentType.parse(type).getParameterValue("encoding");
		if (enc != null)
			setCharacterEncoding(enc);
		setHeader(MessageHeader.FN_CONTENT_TYPE, type);
	}

	public void setLocale(Locale locale) {
		this.locale = locale;
	}

	ServerResponse createServerResponse() throws IOException {
		flushBuffer();
		if (pw != null)
    		pw.close();
		setContentLength(baos.size());
		StatusLine sl = new StatusLine(statusCode, statusReason);
		DataPoster dp = new ByteArrayDataPoster(baos.toByteArray());
		ServerResponse sr = new ServerResponse(sl, headers, dp);
		return sr;
	}

}
