package com.starcharge;

import java.util.Arrays;
import java.util.EventListener;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.Banner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.util.IntrospectorCleanupListener;

import com.ihidea.component.api.v2.annotation.EnableApiV2;
import com.ihidea.core.support.SpringContextLoader;
import com.ihidea.core.support.orm.mybatis3.interceptor.dialect.DialectInterceptor;
import com.ihidea.core.support.pageLimit.PageLimitHolderFilter;
import com.ihidea.core.support.servlet.ServletHolderFilter;
import com.ihidea.core.util.SystemUtilsEx;
import com.starcharge.component.datastore.FileServlet;
import com.starcharge.wios.auth.filter.LoginFilter;

/**
 * 基于springboot2.2.8框架搭建,mvc还是基于servlet,未使用webflux是为了更好支持frame.core<br>
 * 框架基于前后端分离的架构搭建,放弃了session过滤器及velocity相关配置<br>
 * 框架屏蔽了大部分frame.core里的servlet和controller,采用按需加载模式
 * 
 * @author lilin
 * @version [版本号, 2020年4月30日]
 */
@SpringBootApplication(scanBasePackages = {"com.starcharge"})
@MapperScan({"com.starcharge.**.dao", "com.starcharge.**.daoex", "com.starcharge.**.daoEx"})
@EnableScheduling
@EnableAspectJAutoProxy
@EnableApiV2
@EnableFeignClients
@EnableAsync
public class Application {
    
    // @Value("${cat.app.name}")
    // private String catAppName;
    //
    // @Value("${cat.server.ip}")
    // private String catServerIp;
    
    /**
     * 程序入口
     *
     * @param args 参数
     */
    public static void main(String[] args) {
        SystemUtilsEx.initJCE();
        SpringApplication app = new SpringApplication(Application.class);
        app.setBannerMode(Banner.Mode.OFF);
        app.run(args);
        System.out.println("启动成功");
    }
    
    /**
     * 注册OpenAPIJsonServlet,实现@OpenAPI、@OpenAPIMethod方式的接口访问
     *
     * @return Servlet
     */
    // @Bean
    // public ServletRegistrationBean<OpenAPIJsonServlet> openAPIJsonServlet() {
    // ServletRegistrationBean<OpenAPIJsonServlet> bean = new ServletRegistrationBean<>(new OpenAPIJsonServlet(),
    // "/api/*");
    // Map<String, String> params = new HashMap<String, String>();
    // params.put("ipRanges", "58.216.219.86,10.0.0.0/8");
    // bean.setInitParameters(params);
    // return bean;
    // }
    
    /**
     * 注册LoginFilter,实现登录权限校验
     * 
     * @param ignoreUrls 忽略校验的url
     * @param ignoreUrlPath 忽略校验的路径
     * @return Filter
     */
    @Bean
    public FilterRegistrationBean<LoginFilter> loginFilter(@Value("${auth.ignoreUrls}") String ignoreUrls,
        @Value("${auth.ignoreUrlPath}") String ignoreUrlPath) {
        FilterRegistrationBean<LoginFilter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(new LoginFilter());
        Map<String, String> params = new HashMap<>();
        params.put("ignoreUrls", ignoreUrls);
        params.put("ignoreUrlPath", ignoreUrlPath);
        registrationBean.setInitParameters(params);
        // registrationBean.setUrlPatterns(Arrays.asList(new String[]{"/api/*", "/export.do"}));
        registrationBean.setUrlPatterns(Arrays.asList(new String[]{"/api/*"}));
        registrationBean.setOrder(10);
        return registrationBean;
    }
    
    /**
     * 允许跨域的filter
     *
     * @return Filter
     */
    @Bean
    public FilterRegistrationBean<CorsFilter> corsFilter() {
        FilterRegistrationBean<CorsFilter> registrationBean = new FilterRegistrationBean<>();
        CorsConfigurationSource configSource = new CorsConfigurationSource() {

            @Override
            public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {
                CorsConfiguration config = new CorsConfiguration();
                config.setAllowCredentials(true);
                config.addAllowedOrigin("*");
                config.addAllowedHeader("*");
                config.addAllowedMethod("*");
                return config;
            }
        };

        registrationBean.setFilter(new CorsFilter(configSource));
        // registrationBean.setUrlPatterns(Arrays.asList("/api/*", "/uploadFile.do"));
        registrationBean.setUrlPatterns(Arrays.asList("*"));
        registrationBean.setOrder(0); // 支持cors跨域的filter必须放第一个
        return registrationBean;
    }
    
    /**
     * 注册FileServlet,实现文件下载接口,适用于本地文件存储
     *
     * @return Servlet
     */
    @Bean
    public ServletRegistrationBean<FileServlet> fileServlet() {
        ServletRegistrationBean<FileServlet> bean = new ServletRegistrationBean<>(new FileServlet(), "/download/*");
        bean.setOrder(20);
        return bean;
    }
    
    /**
     * 注册ServletHolderFilter,实现在请求线程的任何代码模块都能获得request和response(不推荐)
     *
     * @return Filter
     */
    @Bean
    public FilterRegistrationBean<ServletHolderFilter> servletHolderFilter() {
        FilterRegistrationBean<ServletHolderFilter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(new ServletHolderFilter());
        registrationBean.setUrlPatterns(Arrays.asList(new String[]{"*.do", "/api/*"}));
        registrationBean.setOrder(40);
        return registrationBean;
    }
    
    /**
     * 注册PageLimitHolderFilter,实现自动化分页
     *
     * @return Filter
     */
    @Bean
    public FilterRegistrationBean<PageLimitHolderFilter> pageLimitFilter() {
        FilterRegistrationBean<PageLimitHolderFilter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(new PageLimitHolderFilter());
        registrationBean.setUrlPatterns(Arrays.asList(new String[]{"*.do", "/api/*"}));
        registrationBean.setOrder(50);
        return registrationBean;
    }
    
    /**
     * 此监听器主要用于解决java.beans.Introspector导致的内存泄漏的问题,如果使用Quartz需注册
     *
     * @return Listener
     */
    @Bean
    public ServletListenerRegistrationBean<EventListener> springIntrospectorCleanupListener() {
        ServletListenerRegistrationBean<EventListener> registrationBean = new ServletListenerRegistrationBean<EventListener>();
        registrationBean.setListener(new IntrospectorCleanupListener());
        return registrationBean;
    }
    
    /**
     * 注册spring上下文监听器
     *
     * @return Listener
     */
    @Bean
    public ServletListenerRegistrationBean<EventListener> springContextLoaderListener() {
        ServletListenerRegistrationBean<EventListener> registrationBean = new ServletListenerRegistrationBean<EventListener>();
        registrationBean.setListener(new SpringContextLoader());
        return registrationBean;
    }
    
    /**
     * 注册mybatis分页插件
     *
     * @return bean
     */
    @Bean
    public DialectInterceptor mybatisPageLimit() {
        DialectInterceptor.getDialect();
        return new DialectInterceptor();
    }
    
    /**
     * 注册cat URL过滤器
     *
     * @return Filter
     */
    // @Bean
    // public FilterRegistrationBean<CatFilter> catFilter() {
    // FilterRegistrationBean<CatFilter> registration = new FilterRegistrationBean<>();
    // registration.setFilter(new CatFilter());
    // registration.addUrlPatterns("/*");
    // registration.setName("cat-filter");
    // registration.setOrder(2);
    // return registration;
    // }
    
    /**
     * 注册cat SQL拦截器
     *
     * @return bean
     */
    // @Bean
    // public CatMybatisPlugin maybatisPlugin() {
    // return new CatMybatisPlugin();
    // }
    
    /**
     * cat系统参数初始化
     */
    // @PostConstruct
    // @Order(1)
    // public void catInit() {
    // System.setProperty("cat.app.name", catAppName);
    // System.setProperty("cat.server.ip", catServerIp);
    // }
}