package online.jaxrs.filter;

import java.io.IOException;
import java.util.Objects;
import java.util.Optional;
import java.util.regex.Pattern;

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;

/**
 * サーブレットパス・パスインフォ正規表現チェックフィルタ
 *
 * @author Tadashi Nakayama
 */
public class RegExServletPathInfoFilter implements Filter {

    /** ServletPath用 */
    private Pattern servletPattern = null;
    /** PathInfo用 */
    private Pattern pathPattern = null;

    /**
     * @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
     */
    @Override
    public void init(final FilterConfig filterConfig) {
        final var path = filterConfig.getInitParameter("servletPath");
        if (!Objects.toString(path, "").isEmpty()) {
            this.servletPattern = Pattern.compile(path);
        }

        final var info = filterConfig.getInitParameter("pathInfo");
        if (!Objects.toString(info, "").isEmpty()) {
            this.pathPattern = Pattern.compile(info);
        }
    }

    /**
     * @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)
                && HttpServletResponse.class.isInstance(svResponse)) {
            final var request = HttpServletRequest.class.cast(svRequest);
            final var response = HttpServletResponse.class.cast(svResponse);

            if (!isValidPath(request.getServletPath(), this.servletPattern)
                    || !isValidPath(request.getPathInfo(), this.pathPattern)) {
                response.sendError(HttpServletResponse.SC_NOT_FOUND);
                response.flushBuffer();
                return;
            }
        }
        chain.doFilter(svRequest, svResponse);
    }

    /**
     * Pathチェック
     *
     * @param path パス
     * @param pattern チェックパターン
     * @return OKの場合 true を返す。
     */
    private boolean isValidPath(final String path, final Pattern pattern) {
        return Optional.ofNullable(pattern).map(p -> p.matcher(path).find()).orElse(true);
    }
}
