package com.org.hktshop.base;


import java.sql.Connection;
import java.sql.SQLException;
import java.util.*;
import java.util.Map.Entry;

import org.springframework.context.annotation.Import;

import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
import com.org.hktshop.utils.DateUtil;
import com.org.hktshop.utils.SpringContextUtils;

/***
 * 连接池管�?
 * @author mxk
 *
 */
@Import(value = {SpringContextUtils.class})
public class MySQLPool {
    private static volatile MySQLPool pool;
    private MysqlDataSource ds;
    private Map<Connection, Boolean> map;

    private Map<Connection, Long> timeMap = new HashMap<>();

    String url = SpringContextUtils.getProperty("db.url");
    String username = SpringContextUtils.getProperty("db.username");
    String password = SpringContextUtils.getProperty("db.password");

    private int initPoolSize = 10;//初始化连接数
    private int maxPoolSize = 150;//�?大连接数
    private int waitTime = 100;//没有空闲连接,等待的时�?


    /**
     * @return 初始连接池中可获得的连接数量
     */
    private MySQLPool() {
        init();
    }

    /***
     * 单例
     * @return
     */
    public static MySQLPool getInstance() {
        if (pool == null) {
            synchronized (MySQLPool.class) {
                if (pool == null) {
                    pool = new MySQLPool();
                }
            }
        }

        return pool;
    }

    private void init() {
        try {
            ds = new MysqlDataSource();
            ds.setUrl(url);
            ds.setUser(username);
            ds.setPassword(password);
            ds.setCacheCallableStmts(true);
            ds.setConnectTimeout(1000);
            ds.setLoginTimeout(2000);
            ds.setUseUnicode(true);
            ds.setEncoding("UTF-8");
            ds.setZeroDateTimeBehavior("convertToNull");
            ds.setMaxReconnects(5);
            ds.setAutoReconnect(true);
            map = new HashMap<Connection, Boolean>();
            for (int i = 0; i < initPoolSize; i++) {
                Connection conn = getNewConnection();
                map.put(conn, true);
                timeMap.put(conn, new Date().getTime());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 创建�?个新的数据库连接并返回它
     *
     * @return 返回�?个新创建的数据库连接
     */
    public Connection getNewConnection() {
        try {
            return ds.getConnection();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 通过调用 getNewConnection() 函数返回�?个可用的数据库连�? , 如果当前没有可用的数据库连接，并且更多的数据库连接不能创
     * 建（如连接池大小的限制），此函数等待�?会再尝试获取�?
     *
     * @return 返回�?个可用的数据库连接对�?
     */
    public synchronized Connection getConnection() {

        //TODO 增加�?大等待时间，超过时间,抛出异常
        Connection conn = null;
        try {

            for (Entry<Connection, Boolean> entry : map.entrySet()) {
                if (entry.getValue()) {
                    conn = entry.getKey();

                    //判断空闲时间是否大于8给小�?
                    if (DateUtil.getTimeBetween(timeMap.get(conn)) >= 2) {
                        //从连接池中移除原有连�?
                        try {
                            if (!conn.isClosed()) {
                                conn.close();
                            }
                        } catch (Exception e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        } finally {
                            map.remove(conn);
                            //重新获取新的连接
                            conn = getConnection();
                        }
                    }

                    map.put(conn, false);
                    break;
                }
            }
            if (conn == null) {
                if (map.size() < maxPoolSize) {
                    conn = getNewConnection();
                    map.put(conn, false);
                } else {
                    //TODO 等待次数
                    wait(waitTime);
                    System.out.println("连接数：" + map.size());
                    conn = getConnection();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return conn;
    }

    /**
     * 关闭连接，并清空连接池�??
     */
    public void releaseConnection(Connection conn) {
        if (conn == null) {
            return;
        }
        try {
            if (map.containsKey(conn)) {
                if (conn.isClosed()) {
                    map.remove(conn);
                } else {
                    if (!conn.getAutoCommit()) {
                        conn.setAutoCommit(true);
                    }
                    map.put(conn, true);
                    //記錄�?後一次使用時�?
                    timeMap.put(conn, new Date().getTime());
                }
            } else {
                conn.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}
