package com.usoftchina.bi.core.jdbc;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.stereotype.Component;

import javax.sql.DataSource;
import java.sql.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * @Description 注册动态数据源,初始化数据源和提供了执行动态切换数据源的工具类,EnvironmentAware（获取配置文件配置的属性值）
 * @Date 2018-06-23
 */
@Component
public class DynamicDataSourceRegister implements ImportBeanDefinitionRegistrar, EnvironmentAware {

    //指定默认数据源(springboot2.0默认数据源是hikari如何想使用其他数据源可以自己配置)
    private static final String DATASOURCE_TYPE_DEFAULT = "com.alibaba.druid.pool.DruidDataSource";
    //默认数据源
    private DataSource defaultDataSource;
    //用户自定义数据源
    private Map<Object, DataSource> slaveDataSources = new HashMap<>();

    private static final Logger LOGGER = LoggerFactory.getLogger(DynamicDataSourceRegister.class);

    Map<Object, Object> targetDataSources = new HashMap<Object, Object>();

    public DataSource getDefaultDataSource() {
        return defaultDataSource;
    }

    public void setDefaultDataSource(DataSource defaultDataSource) {
        this.defaultDataSource = defaultDataSource;
    }

    public Map<Object, DataSource> getSlaveDataSources() {
        return slaveDataSources;
    }

    public void setSlaveDataSources(Map<Object, DataSource> slaveDataSources) {
        this.slaveDataSources = slaveDataSources;
    }

    public Map<Object, Object> getTargetDataSources() {
        return targetDataSources;
    }

    public void setTargetDataSources(Map<Object, Object> targetDataSources) {
        this.targetDataSources = targetDataSources;
    }

    // 读取主数据源
    Map<String, Object> dsDeMap = new HashMap<>();

    @Override
    public void setEnvironment(Environment environment) {
        initDefaultDataSource(environment);
        initslaveDataSources();
    }

    private void initDefaultDataSource(Environment env) {
        // 读取主数据源
        dsDeMap = new HashMap<>();
        dsDeMap.put("driver", env.getProperty("spring.datasource.driver-class-name"));
        dsDeMap.put("url", env.getProperty("spring.datasource.url"));
        dsDeMap.put("username", env.getProperty("spring.datasource.username"));
        dsDeMap.put("password", env.getProperty("spring.datasource.password"));
        LOGGER.info("主数据源:" + dsDeMap);
        defaultDataSource = buildDataSource(dsDeMap);
    }

    private void initslaveDataSources(){
        String driver = String.valueOf(dsDeMap.get("driver"));
        String url = String.valueOf(dsDeMap.get("url"));
        String userName = String.valueOf(dsDeMap.get("username"));
        String passWord = String.valueOf(dsDeMap.get("password"));
        String sql = "select id, bases_name, addrass, port, database_type, data_name, user_name, pass_word from bi_databases";
        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;//定义存放查询结果的结果集
        try {
            Class.forName(driver);
            conn = DriverManager.getConnection(url, userName, passWord);
            pstmt = conn.prepareStatement(sql);
            rs = pstmt.executeQuery();//运行查询操作
            while(rs.next()){
                // 多个数据源
                Map<String, Object> dsMap = new HashMap<>();
                String dei = rs.getString("database_type");
                dsMap.put("driver", "oracle.jdbc.driver.OracleDriver");
                dsMap.put("url", "jdbc:" + "oracle" + ":thin:@"+ rs.getString("addrass") + ":"
                        + rs.getString("port") + ":" + rs.getString("data_name"));
                dsMap.put("username", rs.getString("user_name"));
                dsMap.put("password", rs.getString("pass_word"));
                DataSource ds = buildDataSource(dsMap);
                slaveDataSources.put(rs.getInt("id"), ds);
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            try {
            	rs.close();
            	pstmt.close();
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }


    @Override
    public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
        //添加默认数据源
        targetDataSources.put("dataSource", this.defaultDataSource);
        Set<Object> dataSourceIds = DynamicDataSourceContextHolder.getDataSourceIds();
        dataSourceIds.add(String.valueOf(dataSourceIds));
        DynamicDataSourceContextHolder.setDataSourceIds(dataSourceIds);
        //添加其他数据源
        targetDataSources.putAll(slaveDataSources);
        Set<Object> dataSourceIdSet = DynamicDataSourceContextHolder.getDataSourceIds();
        for (Object key : slaveDataSources.keySet()) {
            dataSourceIdSet.add(key);
        }
        DynamicDataSourceContextHolder.setDataSourceIds(dataSourceIdSet);
        //创建DynamicDataSource
        GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
        beanDefinition.setBeanClass(DynamicDataSource.class);
        beanDefinition.setSynthetic(true);
        MutablePropertyValues mpv = beanDefinition.getPropertyValues();
        mpv.addPropertyValue("defaultTargetDataSource", defaultDataSource);
        mpv.addPropertyValue("targetDataSources", targetDataSources);
        //注册 - BeanDefinitionRegistry
        beanDefinitionRegistry.registerBeanDefinition("dataSource", beanDefinition);
    }

    public DataSource buildDataSource(Map<String, Object> dataSourceMap) {
        try {
            dataSourceMap.put("testWhileIdle", "true");
            DruidDataSource factory = (DruidDataSource) DruidDataSourceFactory.createDataSource(dataSourceMap);
            return factory;
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}
