package org.diagbot.pub.jdbc;

import org.apache.commons.lang3.StringUtils;

import java.io.IOException;
import java.sql.*;
import java.util.*;

/**
 * Created by Administrator on 2018/6/8/008.
 */
public class MysqlJdbc {
    private String driver = "com.mysql.jdbc.Driver";

    private String user;
    private String password;
    private String url;

    private String default_file_path = "/jdbc.properties";

    public MysqlJdbc() {
        this.initProperties(default_file_path);
    }

    public MysqlJdbc(String user, String password, String url) {
        this.user = user;
        this.password = password;
        this.url = url;
    }

    public MysqlJdbc(String property_file_path) {
        this.initProperties(property_file_path);
    }

    private void initProperties(String property_file_path) {
        Properties prop = new Properties();
        try {
            prop.load(this.getClass().getResourceAsStream("/jdbc.properties"));
            this.user = prop.getProperty("jdbc.username");
            this.password = prop.getProperty("jdbc.password");
            this.url = prop.getProperty("jdbc.url");
            this.driver = prop.getProperty("jdbc.driverClassName");
        } catch (IOException ioe) {
            ioe.printStackTrace();
        }
    }

    public Connection connect() {
        Connection conn = null;
        try {
            Class.forName(this.driver);
            conn = DriverManager.getConnection(url, this.user, this.password);
        } catch (SQLException e) {
            System.out.println("MySQL操作错误");
            e.printStackTrace();
        } catch (ClassNotFoundException cnfe) {
            System.out.println("未找到驱动");
            cnfe.printStackTrace();
        }
        return conn;
    }

    public void close(ResultSet rs, Statement st, Connection conn) {
        try {
            if (rs != null) rs.close();
            if (st != null) st.close();
            if (conn != null) conn.close();
        } catch (SQLException sqle) {
            sqle.printStackTrace();
        }
    }

    public List<Map<String, String>> query(String table, String[] columns) {
        return query(table, columns, "");
    }

    public List<Map<String, String>> query(String table, String[] columns, String where) {
        Connection conn = connect();
        if (conn == null) return null;
        Statement st = null;
        ResultSet rs = null;
        List<Map<String, String>> list = new ArrayList<>();
        ResultSetMetaData rsmd;

        try {

            String sql = "SELECT ";
            if (columns.length == 0) {
                sql += " * ";
            }
            else {
               sql += StringUtils.join(columns, ",");
            }

            sql +=  " FROM " + table + " " + where;
            st = conn.createStatement();
            rs = st.executeQuery(sql);

            rsmd = rs.getMetaData();

            while (rs.next()) {
                Map<String, String> map = new HashMap<>(10, 0.5f);

                for (int i = 1; i <= rsmd.getColumnCount(); i++) {
                    String column = rsmd.getColumnLabel(i);
                    String val = rs.getString(i);
                    map.put(column, val);
                }

//                for (String column : columns) {
//                    map.put(column, String.valueOf(rs.getObject(column)));
//                }
                list.add(map);
            }
        } catch (SQLException sqle) {
            sqle.printStackTrace();
        } finally {
            this.close(rs, st, conn);
        }
        return list;
    }

    public void insert(List<Map<String, Object>> data, String table, String[] columns) {
        Connection conn = connect();
        if (conn == null) return;
        Statement st = null;
        try {
            conn.setAutoCommit(false);
            st = conn.createStatement();
            String sql = joinInsetSql(table, columns);
            StringBuffer sb = new StringBuffer();

            int first_index = 0;
            String val = "";
            for (int cursor = 0; cursor < data.size(); cursor ++) {
                if (first_index > 0) {
                    sb.append(",");
                }
                sb.append("(");
                for (int i = 0; i < columns.length; i++) {
                    if (i > 0) {
                        sb.append(",");
                    }
                    if (data.get(cursor).get(columns[i]) != null) {
                        sb.append("'");
                        val = data.get(cursor).get(columns[i]).toString();
                        if (val.indexOf("'") > -1) {
                            val = val.replace("'", "\\'");
                        }
                        sb.append(val);
                        sb.append("'");
                    } else {
                        sb.append("''");
                    }
                }
                sb.append(")");
                first_index++;

                if ((cursor + 1) % 1000 == 0) {
                    st.executeUpdate(sql + sb.toString());
                    sb = new StringBuffer();
                    first_index = 0;
                }
            }
            if (data.size() % 1000 != 0) {
                st.executeUpdate(sql + sb.toString());
            }
            conn.commit();
        } catch (SQLException sqle) {
            sqle.printStackTrace();
        }
        this.close(null, st, conn);
    }

    public int[] insertBatch(List<Map<String, Object>> data, String table, String[] columns) {
        Connection conn = connect();
        if (conn == null) return null;
        Statement st = null;
        ResultSet rs = null;
        int[] keys = new int[data.size()];
        try {
            conn.setAutoCommit(false);
            st = conn.createStatement();
            int batchIndex = 0;
            String val = "";
            for (int cursor = 0; cursor < data.size(); cursor ++) {
                String sql = joinInsetSql(table, columns);
                sql += "(";
                for (int i = 0; i < columns.length; i++) {
                    if (i > 0) {
                        sql += ",";
                    }
                    if (data.get(cursor).get(columns[i]) != null) {
                        sql += "'";
                        val = data.get(cursor).get(columns[i]).toString();
                        if (val.indexOf("'") > -1) {
                            val = val.replace("'", "\\'");
                        }
                        sql += val;
                        sql += "'";
                    } else {
                        sql += null;
                    }
                }
                sql += ")";
                st.addBatch(sql);
                if ((cursor + 1) % 1000 == 0) {
                    st.executeBatch();
                    rs = st.getGeneratedKeys();
                    int[] rtn = new int[1000];
                    int index = 0;
                    while (rs.next()) {
                        rtn[index] = rs.getInt(1);
                        index++;
                    }
                    System.arraycopy(rtn, 0, keys, batchIndex * 1000, 1000);
                    batchIndex++;
                }
            }
            if (data.size() % 1000 != 0) {
                st.executeBatch();
                rs = st.getGeneratedKeys();
                int[] rtn = new int[data.size() - batchIndex * 1000];
                int index = 0;
                while (rs.next()) {
                    rtn[index] = rs.getInt(1);
                    index++;
                }
                System.arraycopy(rtn, 0, keys, batchIndex * 1000, data.size() - batchIndex * 1000);
            }
            conn.commit();
        } catch (SQLException sqle) {
            sqle.printStackTrace();
        }
        this.close(rs, st, conn);
        return keys;
    }

    public void update(String table, List<Map<String, Object>> data, List<Map<String, Object>> wheres) {
        Connection conn = connect();
        if (conn == null) return;
        Statement st = null;
        try {
            conn.setAutoCommit(false);
            st = conn.createStatement();
            String sql = "";
            for (int cursor = 0; cursor < data.size(); cursor ++) {
                int i = 0;
                sql = "update " + table + " set ";
                for (Map.Entry<String, Object> entry  : data.get(cursor).entrySet()) {
                    if(i == 0) {
                        sql = sql + entry.getKey() + " = " + (entry.getValue()==null ? null : ("'" + entry.getValue() + "'"));
                    } else {
                        sql = sql + "," + entry.getKey() + " = " + (entry.getValue()==null ? null : ("'" + entry.getValue() + "'"));
                    }
                    i++;
                }
                i = 0;
                for (Map.Entry<String, Object> entry  : wheres.get(cursor).entrySet()) {
                    if(i == 0) {
                        sql = sql + " where " + entry.getKey() + " = " + (entry.getValue()==null ? null : ("'" + entry.getValue() + "'"));
                    } else {
                        sql = sql + " and " + entry.getKey() + " = " + (entry.getValue()==null ? null : ("'" + entry.getValue() + "'"));
                    }
                }
                st.executeUpdate(sql);
            }
            conn.commit();
            st.close();
        } catch (SQLException sqle) {
            sqle.printStackTrace();
        }
        this.close(null, null, conn);
    }

    public void update(String sql) {
        Connection conn = connect();
        if (conn == null) return;
        Statement st = null;
        try {
            conn.setAutoCommit(false);
            st = conn.createStatement();
            st.executeUpdate(sql);
            conn.commit();
            st.close();
        } catch (SQLException sqle) {
            sqle.printStackTrace();
        }
        this.close(null, null, conn);
    }

    public void update(List<String> sqls) {
        Connection conn = connect();
        if (conn == null) return;
        Statement st = null;
        try {
            conn.setAutoCommit(false);
            st = conn.createStatement();
            for (String sql : sqls) {
                st.executeUpdate(sql);
            }
            conn.commit();
            st.close();
        } catch (SQLException sqle) {
            sqle.printStackTrace();
        }
        this.close(null, null, conn);
    }

    private String joinInsetSql(String table, String[] columns) {
        String sql = "insert into " + table + "(";
        for (int i = 0; i < columns.length; i++) {
            if (i == 0) {
                sql = sql + columns[i];
            } else {
                sql = sql + "," + columns[i];
            }
        }
        sql = sql + ") values ";
        return sql;
    }
}
