package online.filter;

import java.io.IOException;

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.HttpSession;

import online.listener.SessionMutexListener;

/**
 * アクションカウントフィルタ
 *
 * @author Tadashi Nakayama
 */
public class ActionCountFilter implements Filter {

	/** キー */
	private static final String CLAZZ = ActionCountFilter.class.getName();

	/**
	 * @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
	 */
	@Override
	public void init(final FilterConfig arg0) {
		return;
	}

	/**
	 * @see javax.servlet.Filter#destroy()
	 */
	@Override
	public void destroy() {
		return;
	}

	/**
	 * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest,
	 * javax.servlet.ServletResponse, javax.servlet.FilterChain)
	 */
	@Override
	public void doFilter(final ServletRequest svRequest, final ServletResponse svResponse,
			final FilterChain chain) throws IOException, ServletException {

		if (HttpServletRequest.class.isInstance(svRequest)) {
			final var request = HttpServletRequest.class.cast(svRequest);

			if (request.getAttribute(CLAZZ) == null) {
				// アクションカウンタ設定
				final var session = request.getSession(false);
				if (session != null) {
					request.setAttribute(CLAZZ, actionCountUp(session));
				}
			}
		}

		// サーブレット実行
		chain.doFilter(svRequest, svResponse);
	}

	/**
	 * カウントをAttributeから取得
	 *
	 * @param request リクエストオブジェクト
	 * @return カウント
	 */
	public static Number getActionCount(final HttpServletRequest request) {
		return Number.class.cast(request.getAttribute(CLAZZ));
	}

	/**
	 * カウントアップ
	 *
	 * @param session セション
	 * @return カウントアップされたカウンタ
	 */
	private Long actionCountUp(final HttpSession session) {
		synchronized (SessionMutexListener.getMutex(session)) {
			var count = Long.class.cast(session.getAttribute(CLAZZ));
			try {
				if (count == null || 100000000000L < count) {
					count = 1L;
				} else {
					count = count + 1L;
				}
				return count;
			} finally {
				session.setAttribute(CLAZZ, count);
			}
		}
	}
}
