/**
 * The contents of this file are subject to the license and copyright
 * detailed in the LICENSE and NOTICE files at the root of the source
 * tree and available online at
 *
 * http://www.dspace.org/license/
 */
package org.dspace.rdf.negotiation;

import java.io.IOException;
import java.util.regex.Matcher;
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;

import org.apache.logging.log4j.Logger;
import org.dspace.rdf.RDFUtil;
import org.dspace.services.factory.DSpaceServicesFactory;

/**
 * @author Pascal-Nicolas Becker (dspace -at- pascal -hyphen- becker -dot- de)
 */
public class NegotiationFilter implements Filter {
    public static final String ACCEPT_HEADER_NAME = "Accept";

    private static final Logger log = org.apache.logging.log4j.LogManager.getLogger(NegotiationFilter.class);

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // nothing to todo here.
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
                         FilterChain chain)
        throws IOException, ServletException {
        try {
            if (!DSpaceServicesFactory.getInstance().getConfigurationService()
                                      .getBooleanProperty(RDFUtil.CONTENT_NEGOTIATION_KEY, false)) {
                chain.doFilter(request, response);
                return;
            }
        } catch (Exception ex) {
            log.warn("Will deliver HTML, as I cannot determine if content "
                         + "negotiation should be enabled or not:\n"
                         + ex.getMessage(), ex);
            chain.doFilter(request, response);
            return;
        }

        if (!(request instanceof HttpServletRequest)
            || !(response instanceof HttpServletResponse)) {
            // just pass request and response to the next filter, if we don't
            // have a HttpServletRequest.
            chain.doFilter(request, response);
            return;
        }
        // cast HttpServletRequest and HttpServletResponse
        HttpServletRequest hrequest = (HttpServletRequest) request;
        HttpServletResponse hresponse = (HttpServletResponse) response;

        String acceptHeader = hrequest.getHeader(ACCEPT_HEADER_NAME);

        String handle = null;
        String extraPathInfo = null;
        String path = hrequest.getPathInfo();
        // in JSPUI the pathInfo starts after /handle, in XMLUI it starts with /handle
        Pattern handleCheckPattern = Pattern.compile("^/*handle/(.*)$");
        Matcher handleCheckMatcher = handleCheckPattern.matcher(path);
        if (handleCheckMatcher.matches()) {
            // remove trailing /handle
            path = handleCheckMatcher.group(1);
        }
        // we expect the path to be in the form <prefix>/<suffix>/[<stuff>],
        // where <prefix> is a handle prefix, <suffix> is the handle suffix
        // and <stuff> may be further information.
        log.debug("PathInfo: " + path);
        if (path == null) {
            path = "";
        }
        Pattern pathPattern =
            Pattern.compile("^/*([^/]+)/+([^/]+)(?:/*||/+(.*))?$");
        Matcher pathMatcher = pathPattern.matcher(path);
        if (pathMatcher.matches()) {
            handle = pathMatcher.group(1) + "/" + pathMatcher.group(2);
            extraPathInfo = pathMatcher.group(3);
        }
        log.debug("handle: " + handle + "\n" + "extraPathInfo: " + extraPathInfo);

        int requestedContent = Negotiator.negotiate(acceptHeader);

        if (!Negotiator.sendRedirect(hresponse, handle, extraPathInfo,
                                     requestedContent, false)) {
            // as we do content negotiation, we should send a vary caching so
            // browsers can adopt their caching strategy
            // the method Negotiator.sendRedirect does this only if it actually
            // does the redirection itself.
            hresponse.setHeader("Vary", "Accept");

            // send html as default => no forwarding necessary
            chain.doFilter(request, response);
        }
    }

    @Override
    public void destroy() {
        // nothing to do here.
    }
}
