/*
 * This file is part of Nuts Framework.
 * Copyright(C) 2009-2012 Nuts Develop Team.
 *
 * Nuts Framework is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License any later version.
 * 
 * Nuts Framework 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Nuts Framework. If not, see <http://www.gnu.org/licenses/>.
 */
package nuts.core.servlet;

import nuts.core.io.Files;
import nuts.core.io.Streams;
import nuts.core.lang.Chars;
import nuts.core.lang.Strings;
import nuts.core.lang.i18n.Charsets;
import nuts.core.net.http.HttpHeader;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

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


/**
 */
public class HttpServletSupport {

	private HttpServletRequest request;
	private HttpServletResponse response;
	
	private String charset;
	private String fileName;
	private Integer contentLength;
	private String contentType;
	private boolean attachment;
	private boolean noCache;
	private boolean bom;
	
	private byte[] data;
	private InputStream stream;
	
	public HttpServletSupport(HttpServletResponse res) {
		response = res;
	}

	public HttpServletSupport(HttpServletRequest req, HttpServletResponse res) {
		request = req;
		response = res;
	}

	/**
	 * @return the response
	 */
	public HttpServletResponse getResponse() {
		return response;
	}

	/**
	 * @param response the response to set
	 */
	public void setResponse(HttpServletResponse response) {
		this.response = response;
	}

	/**
	 * @return the charset
	 */
	public String getCharset() {
		return charset;
	}

	/**
	 * @param charset the charset to set
	 */
	public void setCharset(String charset) {
		this.charset = charset;
	}

	/**
	 * @return the fileName
	 */
	public String getFileName() {
		return fileName;
	}

	/**
	 * @param fileName the fileName to set
	 */
	public void setFileName(String fileName) {
		this.fileName = fileName;
	}

	/**
	 * @return the contentLength
	 */
	public Integer getContentLength() {
		return contentLength;
	}

	/**
	 * @param contentLength the contentLength to set
	 */
	public void setContentLength(Integer contentLength) {
		this.contentLength = contentLength;
	}

	/**
	 * @return the contentType
	 */
	public String getContentType() {
		return contentType;
	}

	/**
	 * @param contentType the contentType to set
	 */
	public void setContentType(String contentType) {
		this.contentType = contentType;
	}

	/**
	 * @return the attachment
	 */
	public boolean isAttachment() {
		return attachment;
	}

	/**
	 * @param attachment the attachment to set
	 */
	public void setAttachment(boolean attachment) {
		this.attachment = attachment;
	}

	/**
	 * @return the noCache
	 */
	public boolean isNoCache() {
		return noCache;
	}

	/**
	 * @param noCache the noCache to set
	 */
	public void setNoCache(boolean noCache) {
		this.noCache = noCache;
	}

	/**
	 * @return the bom
	 */
	public boolean isBom() {
		return bom;
	}

	/**
	 * @param bom the bom to set
	 */
	public void setBom(boolean bom) {
		this.bom = bom;
	}

	/**
	 * @return the data
	 */
	public byte[] getData() {
		return data;
	}

	/**
	 * @param data the data to set
	 */
	public void setData(byte[] data) {
		this.data = data;
	}

	/**
	 * @return the stream
	 */
	public InputStream getStream() {
		return stream;
	}

	/**
	 * @param stream the stream to set
	 */
	public void setStream(InputStream stream) {
		this.stream = stream;
	}
	
	/**
	 * write response header
	 * @throws IOException if an I/O error occurs
	 */
	public void writeResponseHeader() throws IOException {
		if (Strings.isNotEmpty(charset)) {
			response.setCharacterEncoding(charset);
		}

		if (Strings.isEmpty(contentType)
				&& Strings.isNotEmpty(fileName)) {
			contentType = Files.getContentTypeFor(fileName);
		}

		if (Strings.isNotEmpty(contentType)) {
			if (Strings.isNotEmpty(charset)) {
				contentType += "; charset=" + charset;
			}
			response.setContentType(contentType);
		}

		if (contentLength != null) {
			response.setContentLength(contentLength);
		}

		if (Strings.isNotEmpty(fileName)) {
			String fn = HttpServletUtils.EncodeFileName(request, fileName);
			response.setHeader(HttpHeader.CONTENT_DISPOSITION, 
					(attachment ? "attachment" : "inline") + "; filename=\"" + fn + "\"");
			
			if (request != null) {
				UserAgent b = new UserAgent(request);
				noCache = !b.isMsie();
			}
			else {
				noCache = false;
			}
		}

		if (noCache) {
			HttpServletUtils.setResponseNoCache(response);
		}
		
		if (bom && Charsets.isUnicodeCharset(charset)) {
			writeResponseBom();
		}
	}

	public void writeResponseBom() throws IOException {
		response.getWriter().write(Chars.BOM);
	}

	public void writeResponseText(String text) throws IOException {
		response.getWriter().write(text);
	}

	public void writeResponseData(byte[] data) throws IOException {
		response.getOutputStream().write(data);
	}

	public void writeResponseData(InputStream is) throws IOException {
		writeResponseData(is, 4096);
	}
	
	public void writeResponseData(InputStream is, int bufferSize) throws IOException {
		OutputStream os = null;

		try {
			// Get the outputstream
			os = response.getOutputStream();

			// Copy input to output
			byte[] buf = new byte[bufferSize];
			int sz;
			while (-1 != (sz = is.read(buf))) {
				os.write(buf, 0, sz);
			}

			// Flush
			os.flush();
		}
		finally {
			Streams.safeClose(is);
			Streams.safeClose(os);
		}
	}
}
