/*
 * Copyright (c) 2003, Morpho Project.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 * 3. Neither the name of the Morpho Project nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */
package jp.morpho.webapp.servlet;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.logging.Logger;

import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

import jp.morpho.util.ConversionMap;
import jp.morpho.webapp.servlet.http.HttpActionRequest;
import jp.morpho.webapp.servlet.http.impl.HttpActionRequestImpl;

/**
 * <P>
 * フィルタに指定された文字エンコーディングを使用して、フォームデータをエンコードします。
 * </P>
 * @author Kumiko Hiroi
 */
public class CharacterEncodingFilter
	extends AbstractFilter
{
	/** ロガー */
	private Logger log = Logger.getLogger("jp.morpho");

	/** 文字エンコーディング ISO 8859-1、ラテンアルファベット No. 1 */
	private static final String DEFAULT_CHARACTERENCODING_FROM = "ISO8859_1";

	/** 文字エンコーディング Windows 日本語 */
	private static final String DEFAULT_CHARACTERENCODING_TO = "Windows-31J";

	/** 初期化パラメータ 文字エンコーディング */
	private static final String INITPARAM_CHARACTERENCODING = "characterEncoding";

	/**
	 * <P>
	 * CharacterEncodingFilter を構築します。
	 * </P>
	 */
	public CharacterEncodingFilter()
	{
		super();
	}

	/**
	 * <P>
	 * super.init(filterConfig) を呼び出した後、フィルタに指定された文字エンコーディングをサーブレットコンテキストに格納します。
	 * フィルタに文字エンコーディングが指定されていない場合は、デフォルトの文字エンコーディングが使用されます。
	 * デフォルトの文字エンコーディングは、Windows-31J です。
	 * </P>
	 * @param filterConfig サーブレットコンテナによって使用されるフィルタ設定のためのオブジェクト
	 * @exception ServletException フィルタを初期化できなかった場合
	 * @see javax.servlet.Filter#init(FilterConfig)
	 */
	public void init(FilterConfig filterConfig) throws ServletException
	{
		super.init(filterConfig);

		//文字エンコーディングを取得します
		ConversionMap parameters = ConversionMap.valueOf(this.getInitParameterMap());
		String characterEncoding = parameters.getString(INITPARAM_CHARACTERENCODING);
		if (characterEncoding == null || characterEncoding.trim().length() == 0)
		{
			characterEncoding = DEFAULT_CHARACTERENCODING_TO;
		}

		//文字エンコーディングを ServletContext に格納します
		filterConfig.getServletContext().setAttribute(ServletContextAttributeNames.characterEncoding, characterEncoding);
	}

	/**
	 * <P>
	 * フィルタに指定された文字エンコーディングを使用して、フォームデータをエンコードします。
	 * </P>
	 * @param request クライアントがサーブレットに行う要求を含む ServletRequest オブジェクト
	 * @param response サーブレットがクライアントに送信する応答を含む ServletResponse オブジェクト
	 * @param chain フィルタチェーン
	 * @exception IOException フィルタが要求を処理するときに、入出力エラーが検出された場合
	 * @exception ServletException 要求を処理できなかった場合
	 * @see javax.servlet.Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
	 */
	public void doFilter(
		ServletRequest request,
		ServletResponse response,
		FilterChain chain)
		throws IOException, ServletException
	{
		log.fine("doFilter");
		String contentType = request.getContentType();
		int contentLength = request.getContentLength();

		HttpActionRequest actioinRequest = new HttpActionRequestImpl((HttpServletRequest)request);

		ConversionMap formValues = (ConversionMap)actioinRequest.getParameterMap();

		Object[] keyNames = formValues.keySet().toArray();
		for (int i = 0; i < keyNames.length; i++)
		{
			String keyName = keyNames[i].toString();

			if (formValues.isArray(keyName))
			{
				Object[] values = (Object[])formValues.getObject(keyName);
				for (int j = 0; j < values.length; j++)
				{
					if (values[j] instanceof String)
					{
						values[j] = encode((String)values[j]);
					}
				}
				formValues.putObject(keyName, values);
			}
			else if (formValues.getObject(keyName) instanceof String)
			{
				formValues.putString(keyName, encode(formValues.getString(keyName)));
			}
		}
		chain.doFilter(request, response);
	}

	/**
	 * <P>
	 * フィルタに指定された文字エンコーディングを使用して、指定された文字列をエンコーディングします。
	 * フィルタに文字エンコーディングが指定されていない場合は、デフォルトの文字エンコーディングが使用されます。
	 * </P>
	 * @param value エンコーディングされる文字列
	 * @exception UnsupportedEncodingException フィルタに指定された文字エンコーディングがサポートされていない場合
	 * @return エンコーディングされた文字列
	 */
	private String encode(String value) throws UnsupportedEncodingException
	{
		String encodingValue = null;

		//フィルタに指定された文字エンコーディングを使用して、文字列をエンコードします
		encodingValue = (value == null) ? null : new String(value.getBytes(DEFAULT_CHARACTERENCODING_FROM), (String)getServletContext().getAttribute(ServletContextAttributeNames.characterEncoding));

		return encodingValue;
	}

}
