package com.apobates.forum.trident;

import java.util.List;
import com.apobates.forum.member.storage.ehcache.EhcacheMemberStorageCondition;
import com.apobates.forum.member.storage.ehcache.OnlineMemberEhcacheStorage;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.http.MediaType;
import org.springframework.lang.Nullable;
import org.springframework.mobile.device.DeviceHandlerMethodArgumentResolver;
import org.springframework.mobile.device.DeviceResolverHandlerInterceptor;
import org.springframework.mobile.device.view.LiteDeviceDelegatingViewResolver;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.multipart.MultipartResolver;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.view.BeanNameViewResolver;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Conditional;
import com.apobates.forum.core.api.ImageIOMetaConfig;
import com.apobates.forum.member.storage.OnlineMemberStorage;
import com.apobates.forum.member.storage.cookie.CookieMetaConfig;
import com.apobates.forum.trident.controller.helper.AdminIdentityInterceptor;
import com.apobates.forum.trident.controller.helper.AuthenticationInterceptor;
import com.apobates.forum.trident.controller.helper.MemberInviteCodeInterceptorAdapter;
import com.apobates.forum.trident.controller.helper.OnlineDescriptorAspect;
import com.apobates.forum.trident.controller.helper.RegisteChannelInterceptor;
import com.apobates.forum.trident.controller.helper.StrategyCondition;
import com.apobates.forum.trident.controller.helper.StrategyInterceptorAdapter;
import com.apobates.forum.trident.fileupload.ImageStorageExecutor;
import com.apobates.forum.trident.rss.TopicRssView;
import com.apobates.forum.trident.smiley.SmileyStorage;
/**
 * 前端Spring MVC配置类
 * @{project}-servlet.xml
 * @author xiaofanku
 * @since 20200302
 */
@Configuration
@PropertySource(value="classpath:global.properties", ignoreResourceNotFound=true, encoding="UTF-8")
@EnableWebMvc
@EnableAspectJAutoProxy(proxyTargetClass=true)
@ComponentScan(
		basePackages={"com.apobates.forum.trident.controller"}, 
		useDefaultFilters=false, 
		includeFilters={
				@Filter(classes={org.springframework.stereotype.Controller.class}),
				@Filter(classes={org.springframework.stereotype.Component.class})})
@Import(WebSocketConfig.class)
public class TridentFrontConfig implements WebMvcConfigurer{
	@Value("${img.bucket.max.byte}")
	private long maxBytes;
	@Value("${site.cookieSymbol}")
	private String cookieName;
	@Value("${site.cookieDomain}")
	private String cookieDomain;
	@Value("${site.cookiePath}")
	private String cookiePath;
	@Value("${site.domain}")
	private String siteDomain;
	@Value("${img.bucket.domain}")
	private String imageBucketDomain;
	@Value("${img.bucket.upload.direct}")
	private String uploadImageDirectName;
	@Value("${img.bucket.domain}${img.bucket.upload.uri}")
	private String imageBucketUploadURL;
	@Value("${img.bucket.upload.input}")
	private String imageBucketUploadInputFileName;
	@Value("${img.bucket.smile.direct}")
	private String smileyDirectName;
	@Value("${web.view.prefix}")
	private String jspPrefix;
	@Value("${web.view.suffix}")
	private String jspSuffix;
	
	//授权访问的拦截器
	@Bean
	public AuthenticationInterceptor getAuthInter(){
		return new com.apobates.forum.trident.controller.helper.AuthenticationInterceptor();
	}
	//注册通道检查拦截器
	@Bean
	public RegisteChannelInterceptor getRegisInter(){
		return new com.apobates.forum.trident.controller.helper.RegisteChannelInterceptor();
	}
	// 注册邀请码拦截器
	@Bean
	public MemberInviteCodeInterceptorAdapter getInviteCodeInter() {
		return new MemberInviteCodeInterceptorAdapter();
	}
	@Bean
	public AdminIdentityInterceptor getAdminIdenInter(){
		return new com.apobates.forum.trident.controller.helper.AdminIdentityInterceptor();
	}
	// 策略检测拦截器
	@Bean
	@Conditional(StrategyCondition.class)
	public StrategyInterceptorAdapter getStrategyInter() {
		return new StrategyInterceptorAdapter();
	}
	//RSS
	@Bean(name="topicRssView")
	public TopicRssView getRssView(){
		return new com.apobates.forum.trident.rss.TopicRssView();
	}
	/*
	 * 配置请求视图映射
	 *
	 * @return
	 *
	@Bean
	public InternalResourceViewResolver resourceViewResolver() {
		InternalResourceViewResolver internalResourceViewResolver = new InternalResourceViewResolver();
		//请求视图文件的前缀地址
		internalResourceViewResolver.setPrefix("/WEB-INF/layout/page/");
		//请求视图文件的后缀
		internalResourceViewResolver.setSuffix(".jsp");
		internalResourceViewResolver.setViewClass(JstlView.class);
		return internalResourceViewResolver;
	}*/
	//设备自定义模板
	@Bean
	public DeviceResolverHandlerInterceptor deviceResolverHandlerInterceptor() {
		return new DeviceResolverHandlerInterceptor();
	}
	@Bean
	public DeviceHandlerMethodArgumentResolver deviceHandlerMethodArgumentResolver() {
		return new DeviceHandlerMethodArgumentResolver();
	}
	@Bean
	public LiteDeviceDelegatingViewResolver liteDeviceAwareViewResolver() {
		InternalResourceViewResolver delegate = new InternalResourceViewResolver();
		delegate.setPrefix(jspPrefix);
		delegate.setSuffix(jspSuffix);
		delegate.setViewClass(JstlView.class);
		
		LiteDeviceDelegatingViewResolver resolver = new LiteDeviceDelegatingViewResolver(delegate);
		resolver.setMobilePrefix("mobile/");
		resolver.setTabletPrefix("tablet/");
		return resolver;
	}
	//静态资源映射
	@Override
	public void addResourceHandlers(ResourceHandlerRegistry registry) {
		registry.addResourceHandler("/static/**").addResourceLocations("/static/").setCachePeriod(31536000);
	}
	//定义无Controller的path<->view直接映射
	@Override
	public void addViewControllers(ViewControllerRegistry registry) {
		registry.addViewController("/").setViewName("redirect:/home");
	}
	//定义视图文件解析View resolvers
	@Override
	public void configureViewResolvers(ViewResolverRegistry registry) {
		BeanNameViewResolver beanResolver = new BeanNameViewResolver();
		beanResolver.setOrder(1);
		registry.viewResolver(beanResolver);
		//registry.viewResolver(resourceViewResolver());
		registry.viewResolver(liteDeviceAwareViewResolver());
		registry.enableContentNegotiation(getRssView());
	}
	//对静态资源文件的访问， 将无法mapping到Controller的path交给default servlet handler处理 
	@Override
	public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
		configurer.enable();
	}
	//注册媒体类型
	@Override
	public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
		configurer.ignoreAcceptHeader(false)
					.favorPathExtension(true)
					.mediaType("json", MediaType.APPLICATION_JSON)
					.mediaType("xml", MediaType.APPLICATION_XML)
					.mediaType("rss", MediaType.APPLICATION_RSS_XML);
	}
	//拦截器
	@Override
	public void addInterceptors(InterceptorRegistry registry) {
		// 授权访问的地址
		registry.addInterceptor(getAuthInter())
				.excludePathPatterns("/member/home/board/active/json", "/member/home/topic/publish/json", "/member/home/topic/reply/json")
				.addPathPatterns("/member/home/**", "/message/**", "/topic/create", "/posts/create", "/posts/reply", "/search/");
		//管理员访问的地址
		registry.addInterceptor(getAdminIdenInter())
				.excludePathPatterns("/admin/")
				.addPathPatterns("/admin/**");
		//注册通道
		registry.addInterceptor(getRegisInter()).addPathPatterns("/member/register");
		// 邀请码拦截器
		registry.addInterceptor(getInviteCodeInter()).addPathPatterns("/member/register");
		// Condition 返回false时不会创建Bean,所以无法找到定义
		try{
			// 策略检测拦截器
			registry.addInterceptor(getStrategyInter()).addPathPatterns("/board/**", "/posts/**", "/topic/**");
		}catch(org.springframework.beans.factory.NoSuchBeanDefinitionException e){}
		//设备
		registry.addInterceptor(deviceResolverHandlerInterceptor());
	}
	@Override
	public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
		argumentResolvers.add(deviceHandlerMethodArgumentResolver());
	}
	//https://www.jianshu.com/p/a3c7ff0de5ac
	//To resolve ${} in @Value
	@Bean
	public static PropertySourcesPlaceholderConfigurer propertySourceConfigurer() {
		PropertySourcesPlaceholderConfigurer pp = new PropertySourcesPlaceholderConfigurer();
		pp.setIgnoreUnresolvablePlaceholders(true);
		return pp;
	}
	//apache fileupload
	@Bean(name="multipartResolver")
	public MultipartResolver multipartResolver() {
		CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver();
		commonsMultipartResolver.setDefaultEncoding("utf-8");
		commonsMultipartResolver.setMaxUploadSize(maxBytes);
		commonsMultipartResolver.setResolveLazily(false);
		return commonsMultipartResolver;
	}
	//aspectJ 
	@Bean
	public OnlineDescriptorAspect getOnlineAspect(){
		return new com.apobates.forum.trident.controller.helper.OnlineDescriptorAspect();
	}
	//Cookie
	@Bean(name="cookieConfig")
	public CookieMetaConfig getCookieConfig(){
		CookieMetaConfig cnf = new com.apobates.forum.member.storage.cookie.CookieMetaConfig(cookieName, cookieDomain, cookiePath, siteDomain);
		return cnf;
	} 
	
	@Bean(name="onlineMemberStorage")
	public OnlineMemberStorage getMemberStorage(CookieMetaConfig cookieConfig, @Nullable OnlineMemberEhcacheStorage ehcacheMemberStorage){
		if(null == ehcacheMemberStorage) {
			return new com.apobates.forum.member.storage.cookie.HttpCookieProvider(cookieConfig);
		}
		return ehcacheMemberStorage;
	}

	@Bean(value = "ehcacheMemberStorage", initMethod = "init", destroyMethod = "destroy")
	@Conditional(EhcacheMemberStorageCondition.class)
	public OnlineMemberEhcacheStorage getMemberEhacheStorage(){
		//ehcache
		return new com.apobates.forum.member.storage.ehcache.OnlineMemberEhcacheStorage();
	}
	//图片存储
	@Bean(name="imageIOConfig")
	public ImageIOMetaConfig getIOMetaConfig(){
		return new com.apobates.forum.core.api.ImageIOMetaConfig(imageBucketDomain, uploadImageDirectName, smileyDirectName);
	}
	@Bean(name="imageStorageExecutor")
	public ImageStorageExecutor getImageStorage(){
		return new com.apobates.forum.trident.fileupload.OutsideImageStorage(imageBucketDomain, uploadImageDirectName, imageBucketUploadURL, imageBucketUploadInputFileName);
	}
	//表情图片
	@Bean(name="smileyStorage")
	public SmileyStorage getSmileyStorage(ImageIOMetaConfig imageIOConfig){
		return new com.apobates.forum.trident.smiley.OutsideSmileyStorage(imageIOConfig);
	}
}
