package jp.cssj.cti.servlet;

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

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import jp.cssj.cti.CTISession;
import jp.cssj.cti.helpers.ProgressAdapter;

/**
 * <p>
 * アクセスしたページの出力結果を変換するためのフィルタです。
 * <p>
 * sendResourceメソッドは、ウェブアプリケーションの指定したパスから吐き出されるデータをキャプチャしてCSSJサーバーに送ります。
 * テキストの内部エンコーディングはServlet/JSPで指定されるエンコーディングに関わらず常にUTF-8が使われるため、
 * これらのメソッドはエンコーディングを指定する必要がありません。
 * </p>
 * 
 * @author <a href="mailto:miyabe at gnn.co.jp">MIYABE Tatsuhiko </a>
 * @version $Id: AbstractCSSJFilter.java,v 1.4 2005/08/18 04:51:26 harumanx Exp $
 */
public abstract class AbstractCSSJFilter implements Filter {
	/**
	 * CSSJサーブレットからのリクエストであることを示すリクエスト属性のキーです。
	 */
	public static final String FROM_CSSJ = "jp.cssj.cti.servlet.FROM_CSSJ";

	private static final String CONTENT_TYPE = "application/pdf";

	public void doFilter(ServletRequest request,
			final ServletResponse response, FilterChain chain)
			throws ServletException, IOException {
		// 接続する
		CTISession session = this.createSession((HttpServletRequest) request,
				(HttpServletResponse) response);
		try {
			// Content-Typeヘッダを出力する
			response.setContentType(CONTENT_TYPE);

			// クライアントに結果を出力する
			session.setOutput(response.getOutputStream(), CONTENT_TYPE);

			// Content-Lengthヘッダを出力する(重要!)
			session.setProgressListener(new ProgressAdapter(true) {
				public void contentLength(long contentLength) {
					response.setContentLength((int) contentLength);
				}
			});

			this.prepare(session, (HttpServletRequest) request,
					(HttpServletResponse) response);

			String path = ((HttpServletRequest) request).getServletPath();

			OutputStream out = session.sendMain("resource:" + path, null,
					"UTF-8");
			CSSJHttpServletResponseWrapper responseWrapper = new CSSJHttpServletResponseWrapper(
					(HttpServletResponse) response, out, "UTF-8");
			try {
				request.setAttribute(FROM_CSSJ, Boolean.TRUE);
				chain.doFilter(request, responseWrapper);
				request.removeAttribute(FROM_CSSJ);
			} finally {
				responseWrapper.close();
			}
		} finally {
			// セッションを閉じる(忘れやすいので注意!)
			session.close();
		}
	}

	/**
	 * リソースを送信します。
	 * <p>
	 * 
	 * @param session
	 *            セッション
	 * @param request
	 *            サーブレットリクエスト
	 * @param response
	 *            サーブレットレスポンス
	 * @param path
	 *            Servlet/JSPのパス
	 * @param mimeType
	 *            MIME型(省略する場合はnull)
	 * 
	 * @throws ServletException
	 * @throws IOException
	 */
	protected void sendResource(CTISession session, HttpServletRequest request,
			HttpServletResponse response, String path, String mimeType)
			throws ServletException, IOException {
		OutputStream out = session.sendResource("resource:" + path, mimeType,
				"UTF-8");
		CSSJHttpServletResponseWrapper responseWrapper = new CSSJHttpServletResponseWrapper(
				response, out, "UTF-8");
		try {
			RequestDispatcher dispatcher = request.getRequestDispatcher(path);
			request.setAttribute(FROM_CSSJ, Boolean.TRUE);
			dispatcher.include(request, responseWrapper);
			request.removeAttribute(FROM_CSSJ);
		} finally {
			responseWrapper.close();
		}
	}

	/**
	 * セッションを作成するために、このメソッドを実装してください。
	 * 
	 * @param request
	 * @param response
	 * @return
	 * @throws ServletException
	 * @throws IOException
	 */
	protected abstract CTISession createSession(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException;

	/**
	 * プロパティの設定、リソースの送信のために、このメソッドを実装してください。
	 * 
	 * @param request
	 * @param response
	 * @return
	 * @throws ServletException
	 * @throws IOException
	 */
	protected abstract void prepare(CTISession session,
			HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException;
}