package org.springframework.site.web.configuration;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.http.MediaType;
import org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor;
import org.springframework.site.web.ApplicationDialect;
import org.springframework.site.web.NavSection;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.GenericFilterBean;
import org.springframework.web.filter.HiddenHttpMethodFilter;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import org.thymeleaf.spring3.SpringTemplateEngine;

import javax.annotation.PostConstruct;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

@Configuration
public class DefaultViewControllerConfiguration extends WebMvcConfigurerAdapter {

	@Autowired
	private ResourcePatternResolver resourceResolver;

	@Autowired
	private SpringTemplateEngine templateEngine;

	private Map<String, MediaType> mimeTypes = new HashMap<String, MediaType>();

	{
		this.mimeTypes.put("css", MediaType.valueOf("text/css"));
		this.mimeTypes.put("js", MediaType.valueOf("text/javascript"));
		this.mimeTypes.put("ico", MediaType.APPLICATION_OCTET_STREAM);
		this.mimeTypes.put("png", MediaType.IMAGE_PNG);
		this.mimeTypes.put("jpg", MediaType.IMAGE_JPEG);
		this.mimeTypes.put("woff", MediaType.valueOf("application/font-woff"));
	}

	@PostConstruct
	public void addCustomDialect() {
		templateEngine.addDialect(new ApplicationDialect());
	}

	@Override
	public void addViewControllers(ViewControllerRegistry registry) {
		try {
			Resource baseResource = this.resourceResolver
					.getResource("classpath:/templates/pages");
			String basePath = baseResource.getURL().getPath();
			Resource[] resources = this.resourceResolver
					.getResources("classpath:/templates/pages/**/*.html");
			for (Resource resource : resources) {
				String filePath = relativeFilePath(basePath, resource);
				registry.addViewController(buildRequestMapping(filePath)).setViewName(
						"pages" + filePath);
			}
		} catch (IOException e) {
			throw new RuntimeException(
					"Unable to locate static pages: " + e.getMessage(), e);
		}
	}

	// FIXME: would like to use a HandlerInterceptor, but the css is served by a Handler
	// that @EnableWebMvc does not add interceptors to, so we use a Filter instead. We
	// would like this to be fixed in Spring (but open to suggestion) -
	// https://jira.springsource.org/browse/SPR-10655.
	@Bean
	public Filter cssMimeTypeFilter() {
		return new GenericFilterBean() {

			@Override
			public void doFilter(ServletRequest request, ServletResponse response,
					FilterChain chain) throws IOException, ServletException {
				String uri = ((HttpServletRequest) request).getRequestURI();
				String extension = StringUtils.getFilenameExtension(uri);
				if (DefaultViewControllerConfiguration.this.mimeTypes
						.containsKey(extension)) {
					response.setContentType(DefaultViewControllerConfiguration.this.mimeTypes
							.get(extension).toString());
				} else {
					this.logger.warn("No media type found for request: " + uri);
				}
				chain.doFilter(request, response);
			}
		};
	}

	@Override
	public void addInterceptors(InterceptorRegistry registry) {
		registry.addInterceptor( new HandlerInterceptorAdapter() {
			@Override
			public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
				if (handler instanceof HandlerMethod) {
					HandlerMethod handlerMethod = (HandlerMethod) handler;
					NavSection navSection = handlerMethod.getBean().getClass().getAnnotation(NavSection.class);
					if (navSection != null) {
						modelAndView.addObject("navSection", navSection.value());
					}
				}
			}
		});
		registry.addWebRequestInterceptor(interceptor());
	}

	private String relativeFilePath(String basePath, Resource resource)
			throws IOException {
		return resource.getURL().getPath().substring(basePath.length())
				.replace(".html", "");
	}

	private String buildRequestMapping(String filePath) {
		String requestMapping = filePath;
		if (requestMapping.endsWith("/index")) {
			requestMapping = requestMapping.replace("/index", "");
			if (requestMapping.equals("")) {
				requestMapping = "/";
			}
		}
		return requestMapping;
	}

	@Bean
	public OpenEntityManagerInViewInterceptor interceptor() {
		return new OpenEntityManagerInViewInterceptor();
	}

}

@@ -382,87 +382,8 @@
 pe;%0A
-import org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor;%0A
 impo
@@ -588,70 +588,8 @@
 an;%0A
-import org.springframework.web.filter.HiddenHttpMethodFilter;%0A
 impo
@@ -1121,162 +1121,9 @@
 let.
-Filter;%0Aimport javax.servlet.FilterChain;%0Aimport javax.servlet.ServletException;%0Aimport javax.servlet.ServletRequest;%0Aimport javax.servlet.ServletResponse
+*
 ;%0Aim
@@ -4362,60 +4362,8 @@
 %7D);%0A
-%09%09registry.addWebRequestInterceptor(interceptor());%0A
 %09%7D%0A%0A
@@ -4848,127 +4848,6 @@
 %09%7D%0A%0A
-%09@Bean%0A%09public OpenEntityManagerInViewInterceptor interceptor() %7B%0A%09%09return new OpenEntityManagerInViewInterceptor();%0A%09%7D%0A%0A
 %7D%0A

Revert "re-adding the OpenEntityManagerInViewInterceptor"