package ru.yandex.qe.dispenser.ws.intercept;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.Servlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

import org.jetbrains.annotations.NotNull;
import org.springframework.util.Assert;

public class FilterController implements Filter {
    @NotNull
    private final Filter[] filters;

    public FilterController(@NotNull final Filter... filters) {
        this.filters = filters;
    }

    @Override
    public void init(@NotNull final FilterConfig filterConfig) throws ServletException {
        for (final Filter filter : filters) {
            filter.init(filterConfig);
        }
    }

    @Override
    public void doFilter(@NotNull final ServletRequest request,
                         @NotNull final ServletResponse response,
                         @NotNull final FilterChain chain) throws IOException, ServletException {
        if (filters.length != 0) {
            PassThroughFilterChain newChain = new PassThroughFilterChain(filters[filters.length - 1], chain);
            for (int i = filters.length - 2; i >= 0; i--) {
                newChain = new PassThroughFilterChain(filters[i], newChain);
            }
            newChain.doFilter(request, response);
        } else {
            chain.doFilter(request, response);
        }
    }

    @Override
    public void destroy() {
        for (int i = filters.length - 1; i >= 0; i--) {
            filters[i].destroy();
        }
    }

    private static class PassThroughFilterChain implements FilterChain {
        private Filter filter;
        private FilterChain nextFilterChain;
        private Servlet servlet;

        private PassThroughFilterChain(final Filter filter, final FilterChain nextFilterChain) {
            Assert.notNull(filter, "Filter must not be null");
            Assert.notNull(nextFilterChain, "\'FilterChain must not be null");
            this.filter = filter;
            this.nextFilterChain = nextFilterChain;
        }

        private PassThroughFilterChain(final Servlet servlet) {
            Assert.notNull(servlet, "Servlet must not be null");
            this.servlet = servlet;
        }

        @Override
        public void doFilter(final ServletRequest request, final ServletResponse response) throws ServletException, IOException {
            if (this.filter != null) {
                this.filter.doFilter(request, response, this.nextFilterChain);
            } else {
                this.servlet.service(request, response);
            }

        }
    }
}
