package ${domain}.config;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.AssignableTypeFilter;
import org.springframework.core.type.filter.TypeFilter;
import ${domain}.frame.base.Control;
import ${domain}.frame.base.Screen;
import ${domain}.frame.utils.LogUtil;

import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 请求处理器配置类，Screen及Control
 * <p>
 * 注册扫描Screen处理器 {@link ActionConfig#registryScreen}
 * 注册扫描Control处理器 {@link ActionConfig#registryControl}
 *
 * @author wangbing
 * @version 0.0.1
 * @since 2017-01-01
 */
@Configuration
public class ActionConfig implements BeanDefinitionRegistryPostProcessor {

    public static String SCREEN_PREFIX = "/screen/";
    public static String CONTROL_PREFIX = "/control/";
    public static String AJAX_PREFIX = "/ajax/";
    public static String API_PREFIX = "/api/";

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
        String aPackage = this.getClass().getPackage().getName();
        Pattern compile = Pattern.compile("(.*)\\.config");
        Matcher matcher = compile.matcher(aPackage);
        if (matcher.find()) {
            String domain = matcher.group(1);
            registryScreen(domain + ".action.screen", beanDefinitionRegistry);
            registryControl(domain + ".action.control", beanDefinitionRegistry);
            registryAjax(domain + ".action.ajax", beanDefinitionRegistry);
            registryApi(domain + ".action.api", beanDefinitionRegistry);
        }
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {

    }

    private int registryScreen(String domain, BeanDefinitionRegistry beanDefinitionRegistry) {
        ClassPathBeanDefinitionScanner classPathBeanDefinitionScanner = new ClassPathBeanDefinitionScanner(beanDefinitionRegistry);
        classPathBeanDefinitionScanner.resetFilters(false);
        classPathBeanDefinitionScanner.addIncludeFilter(new AssignableTypeFilter(Screen.class));
        classPathBeanDefinitionScanner.setBeanNameGenerator(new BeanNameGenerator() {
            @Override
            public String generateBeanName(BeanDefinition beanDefinition, BeanDefinitionRegistry beanDefinitionRegistry) {
                String beanClassName = beanDefinition.getBeanClassName();
                String beamName = beanClassName.replaceAll(domain + ".", SCREEN_PREFIX).replaceAll("\\.","/").toLowerCase();
                LogUtil.i("registry screen " + beamName);
                return beamName;
            }
        });
        return classPathBeanDefinitionScanner.scan(domain);
    }

    private int registryControl(String domain, BeanDefinitionRegistry beanDefinitionRegistry) {
        ClassPathBeanDefinitionScanner classPathBeanDefinitionScanner = new ClassPathBeanDefinitionScanner(beanDefinitionRegistry);
        classPathBeanDefinitionScanner.resetFilters(false);
        classPathBeanDefinitionScanner.addIncludeFilter(new AssignableTypeFilter(Control.class));
        classPathBeanDefinitionScanner.setBeanNameGenerator(new BeanNameGenerator() {
            @Override
            public String generateBeanName(BeanDefinition beanDefinition, BeanDefinitionRegistry beanDefinitionRegistry) {
                String beanClassName = beanDefinition.getBeanClassName();
                String beamName = beanClassName.replaceAll(domain + ".", CONTROL_PREFIX).replaceAll("\\.","/").toLowerCase();
                LogUtil.i("registry control " + beamName);
                return beamName;
            }
        });
        return classPathBeanDefinitionScanner.scan(domain);
    }

    private int registryAjax(String domain, BeanDefinitionRegistry beanDefinitionRegistry) {
        ClassPathBeanDefinitionScanner classPathBeanDefinitionScanner = new ClassPathBeanDefinitionScanner(beanDefinitionRegistry);
        classPathBeanDefinitionScanner.resetFilters(false);
        classPathBeanDefinitionScanner.addIncludeFilter(new TypeFilter() {
            @Override
            public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
                return true;
            }
        });
        classPathBeanDefinitionScanner.setBeanNameGenerator(new BeanNameGenerator() {
            @Override
            public String generateBeanName(BeanDefinition beanDefinition, BeanDefinitionRegistry beanDefinitionRegistry) {
                String beanClassName = beanDefinition.getBeanClassName();
                if (beanClassName != null && beanClassName.endsWith("Ajax")) {
                    beanClassName = beanClassName.substring(0, beanClassName.length() - 4);
                }
                String beamName = beanClassName.replaceAll(domain + ".", AJAX_PREFIX).replaceAll("\\.","/").toLowerCase();
                LogUtil.i("registry ajax " + beamName);
                return beamName;
            }
        });
        return classPathBeanDefinitionScanner.scan(domain);
    }

    private int registryApi(String domain, BeanDefinitionRegistry beanDefinitionRegistry) {
        ClassPathBeanDefinitionScanner classPathBeanDefinitionScanner = new ClassPathBeanDefinitionScanner(beanDefinitionRegistry);
        classPathBeanDefinitionScanner.addIncludeFilter(new TypeFilter() {
            @Override
            public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
                return true;
            }
        });
        classPathBeanDefinitionScanner.setBeanNameGenerator(new BeanNameGenerator() {
            @Override
            public String generateBeanName(BeanDefinition beanDefinition, BeanDefinitionRegistry beanDefinitionRegistry) {
                String beanClassName = beanDefinition.getBeanClassName();
                if (beanClassName != null && beanClassName.endsWith("Api")) {
                    beanClassName = beanClassName.substring(0, beanClassName.length() - 3);
                }
                String beamName = beanClassName.replaceAll(domain + ".", API_PREFIX).replaceAll("\\.","/").toLowerCase();
                LogUtil.i("registry api " + beamName);
                return beamName;
            }
        });
        return classPathBeanDefinitionScanner.scan(domain);
    }
}
