package com.bcxin.ins.supply.owner;

import com.bcxin.ins.supply.SupplyType;
import com.bcxin.ins.vo.ConstProp;

import java.io.File;
import java.lang.annotation.Annotation;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;

/**
 * 供应商策略工厂
 * @author hzp
 * @date 2018/06/12
 */
public class SupplyStragegyFactory {
    /**
     * 这里是一个常量，表示我们扫描策略的包
     */
    private static final String SCAN_STRAGEGY_PACKAGE = "com.bcxin.ins.supply.owner.impl";
    /**
     * 策略列表
     */
    private List<Class<? extends SupplyStrategy>> supplyStrategyList;
    private ClassLoader classLoader = getClass().getClassLoader();

    /**
     *  单例
     */
    private SupplyStragegyFactory() {
        init();
    }
    public static SupplyStragegyFactory getInstance() {
        return SupplyFactoryInstance.instance;
    }
    private static class SupplyFactoryInstance {
        private static SupplyStragegyFactory instance = new SupplyStragegyFactory();
    }

    /**
     * 在工厂初始化时要初始化策略列表
     */
    private void init() {
        supplyStrategyList = new ArrayList<Class<? extends SupplyStrategy>>();
        //获取到包下所有的class文件
        List<File> resources = getResources();
        Class<SupplyStrategy> supplyStrategyClazz = null;
        try {
            //使用相同的加载器加载策略接口
            supplyStrategyClazz = (Class<SupplyStrategy>) classLoader.loadClass(SupplyStrategy.class.getName());
        } catch (ClassNotFoundException e1) {
            throw new RuntimeException("未找到策略接口");
        }
        for (int i = 0; i < resources.size(); i++) {
            try {
                //载入包下的类
                Class<?> clazz = classLoader.loadClass(SCAN_STRAGEGY_PACKAGE + "." + resources.get(i).getName().replace(".class", ""));
                //判断是否是CalPrice的实现类并且不是CalPrice它本身，满足的话加入到策略列表
                if (SupplyStrategy.class.isAssignableFrom(clazz) && clazz != supplyStrategyClazz) {
                    supplyStrategyList.add((Class<? extends SupplyStrategy>) clazz);
                }
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 获取扫描的包下面所有的class文件
     */
    private List<File> getResources() {
        try {
            File file = new File(classLoader.getResource(SCAN_STRAGEGY_PACKAGE.replace(ConstProp.DOT, ConstProp.SLASH)).toURI());
            File [] fileList=file.listFiles();
            List<File> resultList=new ArrayList<File>();
            for(int i=0;i<fileList.length;i++){
                File f=fileList[i];
                if(f.isFile()){
                    resultList.add(f);
                }else if(f.isDirectory()){
                    //这里只支持1级，后续扩展
                    File [] subFile=f.listFiles();
                    for (File subF : subFile){
                        resultList.add(subF);
                    }
                }
            }
            return resultList;
//            return file.listFiles(new FileFilter() {
//                @Override
//                public boolean accept(File pathname) {
//                    //我们只扫描class文件
//                    if (pathname.getName().endsWith(".class")) {
//                        return true;
//                    }else if(pathname.isDirectory()){
//                        File [] file1=pathname.listFiles();
//                        return false;
//                    }
//                    return false;
//                }
//            });
        } catch (URISyntaxException e) {
            throw new RuntimeException("未找到策略资源");
        }
    }

    /**
     * 根据传入的供应商类别获取对应的策略
     * @param supplyType
     * @return
     */
    public SupplyStrategy createSupplyStrategy(String supplyType) {
        //在策略列表查找策略
        for (Class<? extends SupplyStrategy> clazz : supplyStrategyList) {
            //获取该策略的注解
            SupplyType supplyTypeAnno = handleAnnotation(clazz);
            //根据类别判断是否该注解
            if (supplyType.equalsIgnoreCase(supplyTypeAnno.type().getKey())) {
                try {
                    //是的话我们返回一个当前策略的实例
                    return clazz.newInstance();
                } catch (Exception e) {
                    throw new RuntimeException("策略获得失败");
                }
            }
        }
        throw new RuntimeException("策略获得失败");
    }

    /**
     * 处理注解，我们传入一个策略类，返回它的注解
     */
    private SupplyType handleAnnotation(Class<? extends SupplyStrategy> clazz) {
        Annotation[] annotations = clazz.getDeclaredAnnotations();
        if (annotations == null || annotations.length == 0) {
            return null;
        }
        for (int i = 0; i < annotations.length; i++) {
            if (annotations[i] instanceof SupplyType) {
                return (SupplyType) annotations[i];
            }
        }
        return null;
    }
}
