package jp.sf.amateras.functions.filter;

import java.io.IOException;
import java.util.Properties;

import javax.servlet.Filter;
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 javax.servlet.http.HttpServletResponse;

import jp.sf.amateras.functions.utils.DateUtils;
import jp.sf.amateras.functions.utils.FunctionsProperties;
import jp.sf.amateras.functions.utils.RequestUtils;
import jp.sf.amateras.functions.utils.ResponseUtils;
import jp.sf.amateras.functions.utils.StringUtils;

/**
 * Java Standard EL Functionsを使用する場合はこのフィルタを<tt>web.xml</tt>に登録する必要があります。
 * <p>
 * web.xmlでの設定例を以下に示します。
 * <pre> &lt;filter&gt;
 *   &lt;filter-name&gt;functionsFilter&lt;/filter-name&gt;
 *   &lt;filter-class&gt;jp.sf.amateras.functions.filter.FunctionsFilter&lt;/filter-class&gt;
 * &lt;/filter&gt;
 *
 * &lt;filter-mapping&gt;
 *   &lt;filter-name&gt;functionsFilter&lt;/filter-name&gt;
 *   &lt;url-pattern&gt;*&lt;/url-pattern&gt;
 *   &lt;dispatcher&gt;REQUEST&lt;/dispatcher&gt;
 * &lt;/filter-mapping&gt; </pre>
 * 
 * このフィルタは以下の処理を行います。
 * <ul>
 *   <li>
 *     <tt>functions.properties</tt>を読み込み、設定内容を各種ユーティリティに反映します。
 *   </li>
 *   <li>
 *     リクエストごとに<code>HttpServletRequest</code>、<code>HttpServletResponse</code>を<code>ThreadLocal</code>オブジェクトに保持します。
 *     （実際にはこれらのオブジェクトは{@link RequestUtils}、{@link ResponseUtils}が保持します）
 *   </li>
 *   <li>
 *     リクエストごとにJava Standard EL Functionsが提供する暗黙変数を<code>HttpServletRequest</code>の属性にセットします。
 *   </li>
 * </ul>
 * 
 * このフィルタによって設定される暗黙変数は以下の通りです。
 * <table border="1">
 *   <tr><th>変数名</th><th>説明</th></tr>
 *   <tr>
 *     <td>context</td>
 *     <td>アプリケーションのコンテキストパス（pageContext.request.contextPathと等価です）</td>
 *   </tr>
 * </table>
 * 
 * @author Naoki Takezoe
 */
public class FunctionsFilter implements Filter {
	
	private static final String DATE_PATTERN = "datePattern";
	
	private static final String DATETIME_PATTERN = "datetimePattern";
	
	private static final String TIME_PATTERN = "timePattern";
	
	private static final String DEFAULT_ENCODING = "defaultEncoding";
	
	public void destroy() {
	}
	
	/**
	 * <tt>functions.properties</tt>を読み込み、設定内容を反映します。
	 */
	public void init(FilterConfig filterConfig) throws ServletException {
		Properties properties = FunctionsProperties.getProperties();

		if(properties != null){
			DateUtils.setDatePattern(properties.getProperty(DATE_PATTERN));
			DateUtils.setDatetimePattern(properties.getProperty(DATETIME_PATTERN));
			DateUtils.setTimePattern(properties.getProperty(TIME_PATTERN));
			StringUtils.setDefaultEncoding(properties.getProperty(DEFAULT_ENCODING));
		}
	}

	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
		
		RequestUtils.setRequest((HttpServletRequest) request);
		ResponseUtils.setResponse((HttpServletResponse) response);
		
		// コンテキストパスを$contextという変数名でセット
		request.setAttribute("context", ((HttpServletRequest) request).getContextPath());
		
		try {
			chain.doFilter(request, response);
		} finally {
			RequestUtils.removeRequest();
			ResponseUtils.removeResponse();
		}
	}

}
