package com.elab.core.sql.config;

import com.alibaba.fastjson.JSON;
import com.elab.core.dao.params.NamedParameterUtils2;
import com.elab.core.utils.StreamHelper;
import com.elab.core.utils.StringUtils;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author liuhx on 2016/12/14 09:33
 * @version V1.0
 * @email liuhx@elab-plus.com
 */
public class SqlConfigurableFactory {

    private Logger log = LoggerFactory.getLogger(SqlConfigurableFactory.class);

    private Map<String, SqlItem> sqlMap = new ConcurrentHashMap<String, SqlItem>();
    private String sqlConfigLocations;

    public SqlConfigurableFactory(String sqlConfigurableLocations) {
        this.sqlConfigLocations = sqlConfigurableLocations;
    }

    /**
     * 初始化加载sql.xml后缀的配置文件
     */
    public void init() {
        sqlMap = new HashMap();
        String configPath = sqlConfigLocations + "/";
        log.debug("开始读取配置文件  文件位置 : " + configPath);
        // 读取配置中的sql文件
        List<SqlGroup> sqlGroupList = readJarFileList(configPath);
        if (sqlGroupList.size() == 0) {
            log.warn(" 项目中没有扫描到约定的配置文件配置 ... ");
            return;
        }
    }

    /**
     * 获取sql的值
     *
     * @param sqlId sql的编号
     * @return
     */
    public String getSql(String sqlId) {
        if (sqlMap == null) {
            throw new NullPointerException("SqlInXmlPlugin not start");
        } else {
            return sqlMap.get(sqlId).value;
        }
    }

    /**
     * 判断sqlid是否存在
     *
     * @param sqlId
     * @return
     */
    public boolean existSqlId(String sqlId) {
        if (sqlMap == null) {
            throw new NullPointerException("SqlInXmlPlugin not start");
        } else {
            return sqlMap.get(sqlId) != null;
        }
    }

    /**
     * 获取这个sql的类型
     *
     * @param groupNameAndsqlId sql的编号
     * @return
     */
    public SqlCommandType getSqlType(String groupNameAndsqlId) {
        if (sqlMap == null) {
            throw new NullPointerException("SqlInXmlPlugin not start");
        } else {
            SqlItem sqlItem = sqlMap.get(groupNameAndsqlId);
            if (sqlItem == null) {
                return null;
            }
            return sqlItem.sqlCommandType;
        }
    }

    public void clearSqlMap() {
        sqlMap.clear();
    }

    /**
     * 获取列表下面的文件
     *
     * @param list 文件集合
     * @param file 文件夹路径
     */
    public void getListFile(List<File> list, File file) {
        File[] files = file.listFiles();
        for (int i = 0; i < files.length; i++) {
            File file1 = files[i];
            if (file1.isDirectory()) {
                getListFile(list, file1);
            } else {
                list.add(file1);
            }
        }
    }


    private void loadSqlMap(SqlGroup group, String name) {
        Iterator var8 = group.sqlItems.iterator();

        while (var8.hasNext()) {
            SqlItem sqlItem = (SqlItem) var8.next();
            String value = sqlItem.value;
            //判断该sql的类型
            SqlCommandType sqlCommandType = NamedParameterUtils2.getSqlCommandType(value);
            sqlItem.sqlCommandType = sqlCommandType;
            sqlMap.put(name + "." + sqlItem.id, sqlItem);
        }
    }

    /**
     * 注册sql子节点
     *
     * @param sqlId sql的标识编号
     * @param sql   sql的内容
     */
    public void registerSqlMap(String sqlId, String sql) {
        if (existSqlId(sqlId)) {
            log.warn("===========sqlId存在重复创建 id : " + sqlId + " sql内容:" + sql);
            return;
        }
        SqlItem sqlItem = new SqlItem();
        sqlItem.id = sqlId;
        sqlItem.value = sql;
        sqlItem.sqlCommandType = NamedParameterUtils2.getSqlCommandType(sql);
        sqlMap.put(sqlId, sqlItem);
    }


    /**
     * 将file文件copy到指定位置之后,然后再返回 {@link #readJarFileList(String)}
     *
     * @param path
     * @return
     */
    @Deprecated
    public List<File> getJarFileList(String path) {
        List<File> list = new ArrayList<>();
        //获取容器资源解析器
        ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        File ttfFile = null;
        try {
            //获取所有匹配的文件
            Resource[] resources = resolver.getResources(path + "*.*");
            for (Resource resource : resources) {
                //获得文件流，因为在jar文件中，不能直接通过文件资源路径拿到文件，但是可以在jar包中拿到文件流
                InputStream stream = resource.getInputStream();
                log.debug(" 读取的文件流  [" + stream + "]");
                String targetFilePath = "/tmp/" + path + resource.getFilename();
                log.debug(" 放置位置  [" + targetFilePath + "]");
                ttfFile = new File(targetFilePath);
                FileUtils.copyInputStreamToFile(stream, ttfFile);
                list.add(ttfFile);
            }
        } catch (IOException e) {
            log.warn("读取文件流失败，写入本地库失败！ " + e);
        }
        return list;
    }

    /**
     * jar包类型的读取配置文件的方式
     *
     * @param path jar中的文件位置
     * @return
     */
    private List<SqlGroup> readJarFileList(String path) {
        List<SqlGroup> list = new ArrayList<>();
        //获取容器资源解析器
        ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        try {
            //获取所有匹配的文件
            Resource[] resources = resolver.getResources(path + "*.*");
            for (Resource resource : resources) {
                //获得文件流，因为在jar文件中，不能直接通过文件资源路径拿到文件，但是可以在jar包中拿到文件流
                InputStream stream = resource.getInputStream();
                String stringFromStream = StreamHelper.getStringFromStream(stream, "UTF-8");
                if (StringUtils.isNotEmpty(stringFromStream)) {
                    SqlGroup group = JaxbKit.unmarshal(stringFromStream, SqlGroup.class);
                    loadSqlMap(group, group.name);
                    list.add(group);
                } else {
                    log.warn("配置 : " + resource.getFilename() + " 读取内容为空...");
                }
            }
        } catch (IOException e) {
            log.warn("读取文件流失败，写入本地库失败！ " + e);
        }
        return list;
    }

    public static void main(String[] args) throws IOException, URISyntaxException {
//        String sql = sql("hello.list");
//        System.out.println(sql);
//        this.getClass().getResourceAsStream("/resource/C/D/E.xml");
        String path = "file:/D:/idea_work/git_work/elab-account-service/target/elab-account-service-1.0.0.jar!/BOOT-INF/classes!/sql/";
//        JarFile jarFile = new JarFile(path);
//        System.out.println("---");


//        String path = SqlConfigurableFactory.class.getClassLoader().getResource("").getPath() + "sql/";
        //获取容器资源解析器
        ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        File ttfFile = null;
        //获取所有匹配的文件
        Resource[] resources = resolver.getResources(path + "*.*");
        for (Resource resource : resources) {
            //获得文件流，因为在jar文件中，不能直接通过文件资源路径拿到文件，但是可以在jar包中拿到文件流
            InputStream stream = resource.getInputStream();
            String stringFromStream = StreamHelper.getStringFromStream(stream, "UTF-8");
            SqlGroup group = JaxbKit.unmarshal(stringFromStream, SqlGroup.class);
            System.out.println(resource.getFilename() + "-------------------" + JSON.toJSONString(group));
        }
    }
}
