package com.sunshine.common.repository;


import com.alibaba.fastjson.JSON;
import java.io.Serializable;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.sql.DataSource;
import org.apache.commons.collections4.map.CaseInsensitiveMap;
import org.apache.commons.lang.reflect.MethodUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.smartframework.common.DataObject;
import org.smartframework.common.DataRepository;
import org.smartframework.common.ExArrayList;
import org.smartframework.common.GlobalConfig;
import org.smartframework.common.NamedQuery;
import org.smartframework.common.OperationException;
import org.smartframework.common.TableColumn;

import org.smartframework.common.utils.ExDateUtils;
import org.smartframework.common.utils.ExSQLUtils;
import org.smartframework.common.utils.ExStringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataRetrievalFailureException;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.ResultSetExtractor;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.jdbc.support.GeneratedKeyHolder;

public class DataRepositoryJDBC implements DataRepository {
    protected final Logger log = LoggerFactory.getLogger(this.getClass());
    @Autowired
    @Qualifier("dataSource")
    protected DataSource dataSource;
    @Autowired
    @Qualifier("jdbcTemplate")
    protected JdbcTemplate jdbcTemp;
    protected Map columnValueListMap = new CaseInsensitiveMap();
    protected String masterTable;
    protected String masterTablePK;
    protected String loginUserId;
    protected String orderBy;
    protected String databaseType;
    protected String valueListName;
    protected boolean isAutoKey = true;
    private List<NamedQuery> namedQuerys = new ArrayList();

    public DataRepositoryJDBC() {
    }

    public DataRepositoryJDBC(int clientId, String loginUserId) {
        this.loginUserId = loginUserId;
    }

    public DataSource getDataSource() {
        return this.dataSource;
    }

    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
        this.getJdbcTemplate().setDataSource(dataSource);
    }

    public JdbcTemplate getJdbcTemplate() {
        return this.jdbcTemp;
    }

    protected String[] getTableColumnNames() {
        List<TableColumn> columnList = this.loadTableColumns();
        String[] columnNames = new String[columnList.size()];

        for(int i = 0; i < columnList.size(); ++i) {
            columnNames[i] = ((TableColumn)columnList.get(i)).getColumnName();
        }

        return columnNames;
    }

    protected List<TableColumn> loadTableColumns() {
        String sql = " select * from " + this.masterTable + " where 1 = 0";
        List<TableColumn> columnList = (List)this.getJdbcTemplate().query(sql, new ResultSetExtractor<List>() {
            public List extractData(ResultSet rs) throws SQLException, DataAccessException {
                int count = rs.getMetaData().getColumnCount();
                List<TableColumn> columnList = new ArrayList();

                for(int i = 0; i < count; ++i) {
                    TableColumn tableColumn = new TableColumn();
                    tableColumn.setColumnDisplaySize(rs.getMetaData().getColumnDisplaySize(i + 1));
                    tableColumn.setColumnLabel(rs.getMetaData().getColumnLabel(i + 1));
                    tableColumn.setColumnName(rs.getMetaData().getColumnName(i + 1));
                    tableColumn.setColumnType(rs.getMetaData().getColumnTypeName(i + 1));
                    columnList.add(tableColumn);
                }

                return columnList;
            }
        });
        return columnList;
    }

    protected String getDatabaseType() {
        if(this.databaseType != null) {
            return this.databaseType;
        } else {
            Connection conn = null;

            try {
                conn = this.getJdbcTemplate().getDataSource().getConnection();
                String driverName = conn.getMetaData().getDriverName();
                if(driverName != null) {
                    if(driverName.toLowerCase().indexOf("oracle") >= 0) {
                        this.databaseType = "oracle";
                    } else if(driverName.toLowerCase().indexOf("mysql") >= 0) {
                        this.databaseType = "mysql";
                    } else if(driverName.toLowerCase().indexOf("sqlserver") < 0 && driverName.toLowerCase().indexOf("microsoft") < 0) {
                        if(driverName.toLowerCase().indexOf("postgresql") >= 0) {
                            this.databaseType = "postgresql";
                        } else {
                            this.databaseType = "mysql";
                        }
                    } else {
                        this.databaseType = "mssql";
                    }
                }
            } catch (SQLException var11) {
                this.log.error(var11.getMessage(), var11);
            } finally {
                if(conn != null) {
                    try {
                        conn.close();
                    } catch (SQLException var10) {
                        throw new OperationException(var10);
                    }
                }

            }

            return this.databaseType;
        }
    }

    public String getMasterTablePK() {
        return this.masterTablePK;
    }

    public void setMasterTablePK(String masterTablePK) {
        this.masterTablePK = masterTablePK;
    }

    public String getMasterTable() {
        return this.masterTable;
    }

    public void setMasterTable(String masterTable) {
        this.masterTable = masterTable;
    }

    public void setCaller(String setCaller) {
        this.loginUserId = setCaller;
    }

    public void setLoginUserId(String loginUserId) {
        this.loginUserId = loginUserId;
    }

    public String getLoginUserId() {
        return this.loginUserId;
    }

    public String getOrderBy() {
        return this.orderBy;
    }

    public void setOrderBy(String orderBy) {
        this.orderBy = orderBy;
    }

    public String getSelectSQL() {
        String sql = "select * from " + this.masterTable + " where 1=1 ";
        return sql;
    }

    public List queryDataBySQL(String sql, Object[] parameters) {
        this.log.debug("查询SQL=" + sql);
        List dataList = this.getJdbcTemplate().queryForList(sql, parameters);
        List resultList = new ArrayList();
        Iterator var5 = dataList.iterator();

        while(var5.hasNext()) {
            Object item = var5.next();
            Map itemMap = (Map)item;
            Map rowMap = new CaseInsensitiveMap();
            rowMap.putAll(itemMap);
            resultList.add(rowMap);
        }

        return resultList;
    }

    public List queryData(String filter, Map paramMap, int pageIndex, int pageSize) {
        StringBuilder whereClause = new StringBuilder();
        Object[] paramObjs = null;
        NamedQuery namedQuery = this.findNamedQuery(filter);
        if(namedQuery != null) {
            if(namedQuery.isInvokeMethod()) {
                if("all".equalsIgnoreCase(filter)) {
                    filter = "queryAll";
                }

                return (List)this.invokeCommandMethod(filter, paramMap);
            }

            whereClause.append(namedQuery.getWhere());
            paramObjs = namedQuery.buildParamValues(paramMap);
        } else if("none".equalsIgnoreCase(filter)) {
            whereClause.append("1 = 0");
        } else if(filter != null && filter.startsWith("{") && filter.endsWith("}")) {
            filter = filter.replace("{", "");
            filter = filter.replace("}", "");
            String[] tmpValues = ExStringUtils.split(filter, "|");
            whereClause.append(tmpValues[0] + " = '" + tmpValues[1] + "'");
        }

        String command = (String)paramMap.get("command");
        if("search".equalsIgnoreCase(command) && namedQuery == null) {
            paramObjs = ExSQLUtils.buildWhere(whereClause, paramMap);
        }

        String aOrderBy = this.getOrderBy();
        if(paramMap.containsKey("sort")) {
            aOrderBy = paramMap.get("sort") + " " + paramMap.get("order");
        }

        List resultList = this.queryDataByPage(whereClause.toString(), aOrderBy, pageIndex, pageSize, paramObjs);
        return resultList;
    }

    public List queryDataByPage(String whereClause, String aOrderBy, int pageIndex, int pageSize, Object[] parameters) {
        String sql = this.getSelectSQL();
        if(ExStringUtils.isNotBlank(whereClause)) {
            sql = sql + " and " + whereClause;
        }

        if(ExStringUtils.isBlank(aOrderBy)) {
            sql = sql + " order by " + this.masterTablePK + " desc ";
        } else {
            sql = sql + " order by " + aOrderBy;
        }

        return this.queryDataByPage(sql, pageIndex, pageSize, parameters);
    }

    public List queryDataByPage(String sql, int pageIndex, int pageSize, Object[] parameters) {
        String rowCountSQL = ExSQLUtils.buildRowCountSQL(this.getDatabaseType(), sql);
        if(pageSize > 0) {
            sql = ExSQLUtils.buildPageableSQL(this.getDatabaseType(), sql, pageSize, pageIndex);
        }

        this.log.debug("查询SQL=" + sql);
        List dataList = this.getJdbcTemplate().queryForList(sql, parameters);
        ExArrayList resultList = new ExArrayList();
        Iterator var8 = dataList.iterator();

        while(var8.hasNext()) {
            Object item = var8.next();
            Map itemMap = (Map)item;
            Map rowMap = new CaseInsensitiveMap();
            rowMap.putAll(itemMap);
            resultList.add(rowMap);
        }

        resultList.setTotal(this.getRowCount(rowCountSQL, parameters));
        return resultList;
    }

    public List queryData(String whereClause, String aOrderBy, Object[] parameters) {
        return this.queryDataByPage(whereClause, aOrderBy, 0, 0, parameters);
    }

    private int getRowCount(String sql, Object[] parameters) {
        if(sql == null) {
            this.log.error("SQL IS NULL");
            return 0;
        } else {
            Map rowData = this.getJdbcTemplate().queryForMap(sql, parameters);
            Object value = rowData.get("COUNT(*)");
            if(value == null) {
                value = rowData.get("");
            }

            return value == null?0:ExStringUtils.getIntValue(value).intValue();
        }
    }

    public Map findOneBySQL(String sql, Object[] parameters) {
        this.log.debug("查询SQL=" + sql);

        try {
            Map dataMap = this.getJdbcTemplate().queryForMap(sql, parameters);
            return new CaseInsensitiveMap(dataMap);
        } catch (EmptyResultDataAccessException var4) {
            return new HashMap();
        }
    }

    public Map findOne(String whereClause, Object[] parameters) {
        String sql = this.getSelectSQL();
        if(ExStringUtils.isNotBlank(whereClause)) {
            sql = sql + " and " + whereClause;
        }

        return this.findOneBySQL(sql, parameters);
    }

    public Map findOne(Map paramMap) {
        StringBuilder whereClause = new StringBuilder();
        Object[] paramObjs = ExSQLUtils.buildWhere(whereClause, paramMap);
        return this.findOne(whereClause.toString(), paramObjs);
    }

    public void clearRowMetaData(Map dataMap) {
    }

    public DataObject doLoad(Serializable rowId) {
        String sql = "select * from " + this.masterTable + " where  " + this.masterTablePK + " = ? ";
        this.log.debug("查询SQL=" + sql);
        Object dataMap = new HashMap();

        try {
            Map tmpdataMap = this.getJdbcTemplate().queryForMap(sql, new Object[]{rowId});
            dataMap = new CaseInsensitiveMap(tmpdataMap);
        } catch (EmptyResultDataAccessException var5) {
            ;
        }

        return new DataObject((Map)dataMap);
    }

    public int doDelete(Serializable rowId) {
        String sql = "delete from " + this.masterTable + " where  " + this.masterTablePK + " = ? ";
        int result = this.getJdbcTemplate().update(sql, new Object[]{rowId});
        this.log.debug("删除SQL=" + sql + ", 执行结果=" + result);
        return result;
    }

    public Map createNewRow() {
        Map dataMap = new DataObject();
        dataMap.put("created", new Date());
        return dataMap;
    }

    public int[] doBatchInsert(List<Map> dataList) {
        List<TableColumn> tableColumns = this.loadTableColumns();
        String[] tableColumnNames = this.getTableColumnNames();
        String insertSQL = null;
        int index = 0;
        SqlParameterSource[] batchArgs = new SqlParameterSource[dataList.size()];
        Iterator var7 = dataList.iterator();

        label56:
        while(var7.hasNext()) {
            Map rowData = (Map)var7.next();
            Object createdTime = rowData.get("created");
            if(createdTime == null || "".equalsIgnoreCase(createdTime.toString())) {
                rowData.put("created", new Date());
            }

            rowData.put("createdBy", this.loginUserId);
            Iterator var10 = tableColumns.iterator();

            while(true) {
                TableColumn tableColumn;
                Object value;
                String columnType;
                do {
                    do {
                        if(!var10.hasNext()) {
                            batchArgs[index++] = new MapSqlParameterSource(new CaseInsensitiveMap(rowData));
                            if(insertSQL == null) {
                                insertSQL = ExSQLUtils.buildInsertSQL(this.masterTable, tableColumnNames, rowData);
                            }
                            continue label56;
                        }

                        tableColumn = (TableColumn)var10.next();
                        value = rowData.get(tableColumn);
                        columnType = tableColumn.getColumnType();
                    } while(value == null);
                } while(!"Date".equalsIgnoreCase(columnType) && !"DateTime".equalsIgnoreCase(columnType) && !"Timestamp".equalsIgnoreCase(columnType));

                Date date = null;
                if(value instanceof String) {
                    date = ExDateUtils.parseDate((String)value);
                } else if(value instanceof Long) {
                    date = ExDateUtils.parseDate(((Long)value).longValue());
                }

                if(date != null) {
                    rowData.put(tableColumn.getColumnName(), date);
                }
            }
        }

        NamedParameterJdbcTemplate namedJdbcTemp = new NamedParameterJdbcTemplate(this.getDataSource());
        int[] results = namedJdbcTemp.batchUpdate(insertSQL, batchArgs);
        return results;
    }

    public Serializable doInsert(Map dataMap) {
        List<TableColumn> tableColumns = this.loadTableColumns();
        String[] tableColumnNames = this.getTableColumnNames();
        Object createdTime = dataMap.get("created");
        if(createdTime == null || "".equalsIgnoreCase(createdTime.toString())) {
            dataMap.put("created", new Date());
        }

        dataMap.put("createdBy", this.loginUserId);
        String insertSQL = ExSQLUtils.buildInsertSQL(this.masterTable, tableColumnNames, dataMap);
        Iterator var6 = tableColumns.iterator();

        while(true) {
            TableColumn tableColumn;
            Object value;
            String columnType;
            do {
                do {
                    if(!var6.hasNext()) {
                        this.log.debug("SQL:" + insertSQL + ", params = " + dataMap);
                        NamedParameterJdbcTemplate namedJdbcTemp = new NamedParameterJdbcTemplate(this.getDataSource());
                        SqlParameterSource sqlParameterSource = new MapSqlParameterSource(new CaseInsensitiveMap(dataMap));
                        GeneratedKeyHolder keyHolder = new GeneratedKeyHolder();

                        try {
                            int result = -1;
                            if(this.isAutoKey && ExStringUtils.isNotBlank(this.masterTablePK)) {
                                result = namedJdbcTemp.update(insertSQL, sqlParameterSource, keyHolder, new String[]{this.masterTablePK});
                                Number rowKey = keyHolder.getKey();
                                if(rowKey != null && rowKey instanceof Number) {
                                    return Long.valueOf(rowKey.longValue());
                                }
                            } else {
                                result = namedJdbcTemp.update(insertSQL, sqlParameterSource);
                            }

                            return Long.valueOf((long)result);
                        } catch (DataRetrievalFailureException var11) {
                            this.log.error(var11.getMessage());
                            return null;
                        } catch (Exception var12) {
                            throw new OperationException(var12);
                        }
                    }

                    tableColumn = (TableColumn)var6.next();
                    value = dataMap.get(tableColumn.getColumnName());
                    columnType = tableColumn.getColumnType();
                } while(value == null);
            } while(!"Date".equalsIgnoreCase(columnType) && !"DateTime".equalsIgnoreCase(columnType) && !"Timestamp".equalsIgnoreCase(columnType));

            Date date = null;
            if(value instanceof String) {
                date = ExDateUtils.parseDate((String)value);
            } else if(value instanceof Long) {
                date = ExDateUtils.parseDate(((Long)value).longValue());
            }

            if(date != null) {
                dataMap.put(tableColumn.getColumnName(), date);
            }
        }
    }

    public int doUpdate(String sql, Object... args) {
        return this.getJdbcTemplate().update(sql, args);
    }

    public int doUpdate(Serializable rowId, Map dataMap) {
        List<TableColumn> tableColumns = this.loadTableColumns();
        String[] tableColumnNames = this.getTableColumnNames();
        dataMap.put(this.masterTablePK, rowId);
        dataMap.remove("created");
        Map oldDataMap = this.doLoad(rowId);
        String updateSQL = ExSQLUtils.buildUpdateSQL(this.masterTable, this.masterTablePK, tableColumnNames, dataMap, oldDataMap);
        this.log.debug("SQL:" + updateSQL + ", params = " + dataMap);
        if(ExStringUtils.isBlank(updateSQL)) {
            return 0;
        } else {
            Iterator var7 = tableColumns.iterator();

            while(true) {
                TableColumn tableColumn;
                Object value;
                String columnType;
                do {
                    do {
                        if(!var7.hasNext()) {
                            NamedParameterJdbcTemplate namedJdbcTemp = new NamedParameterJdbcTemplate(this.getDataSource());
                            SqlParameterSource sqlParameterSource = new MapSqlParameterSource(new CaseInsensitiveMap(dataMap));
                            int result = namedJdbcTemp.update(updateSQL, sqlParameterSource);
                            return result;
                        }

                        tableColumn = (TableColumn)var7.next();
                        value = dataMap.get(tableColumn.getColumnName());
                        columnType = tableColumn.getColumnType();
                    } while(value == null);
                } while(!"Date".equalsIgnoreCase(columnType) && !"DateTime".equalsIgnoreCase(columnType) && !"Timestamp".equalsIgnoreCase(columnType));

                Date date = null;
                if(value instanceof String) {
                    date = ExDateUtils.parseDate((String)value);
                } else if(value instanceof Long) {
                    date = ExDateUtils.parseDate(((Long)value).longValue());
                }

                if(date != null) {
                    dataMap.put(tableColumn.getColumnName(), date);
                }
            }
        }
    }

    public String doAction(String oId, Map parameters) throws OperationException {
        String command = (String)parameters.get("command");
        String methodName;
        if(!"batchDelete".equalsIgnoreCase(command)) {
            if(ExStringUtils.isNotBlank(command)) {
                methodName = "do" + command;
                Object cmdResult = this.invokeCommandMethod(methodName, parameters);
                return cmdResult instanceof String?(String)cmdResult:JSON.toJSONString(cmdResult);
            } else {
                return "未实现的指令";
            }
        } else {
            methodName = (String)parameters.get("rowIds");
            String[] rowIdArray = ExStringUtils.split(methodName, ",");
            int deleteRows = 0;
            String[] var7 = rowIdArray;
            int var8 = rowIdArray.length;

            for(int var9 = 0; var9 < var8; ++var9) {
                String rowId = var7[var9];
                int result = this.doDelete(rowId);
                deleteRows += result;
            }

            return "删除成功";
        }
    }

    public NamedQuery findNamedQuery(String name) {
        NamedQuery query = null;

        for(int i = 0; i < this.namedQuerys.size(); ++i) {
            query = (NamedQuery)this.namedQuerys.get(i);
            if(name != null && name.equalsIgnoreCase(query.getName())) {
                return query;
            }
        }

        return null;
    }

    public Map getColumnValueListMap() {
        return this.columnValueListMap;
    }

    protected void setUpTableColumns() {
    }

    public void addNamedQuery(NamedQuery namedQuery) {
        this.namedQuerys.add(namedQuery);
    }

    public String reName(String table) {
        return table;
    }

    public int doSave(Map dataMap) {
        return 0;
    }

    public String getValueListName() {
        return this.valueListName;
    }
//
//    public void linkColumnToValueList() {
//        String cacheName = "DataDictCache";
//        String valuelistTable = GlobalConfig.getConfigValue("sysconfig.valuelistTable", "b_valuelist");
//        String sql = "select * from b_valuelisttable where valueListName = ?";
//        Iterator iter = this.columnValueListMap.keySet().iterator();
//
//        while(true) {
//            String value;
//            Map valueListMap = new HashMap();
//            do {
//                if(!iter.hasNext()) {
//                    return;
//                }
//
//                value = (String)this.columnValueListMap.get(iter.next());
//                valueListMap = (Map)ExCacheUtils.getData(cacheName, value);
//            } while(valueListMap != null && !valueListMap.isEmpty());
//
//            List dataList = null;
//            if(value != null && value.startsWith("TableValueList.")) {
//                Map rowMap = this.getJdbcTemplate().queryForMap(sql, new Object[]{value});
//                String valueSql = (String)rowMap.get("SQLTPL");
//                dataList = this.getJdbcTemplate().queryForList(valueSql);
//            } else if(value != null && value.startsWith("ValueList.")) {
//                dataList = this.getJdbcTemplate().queryForList("select keyName as optValue, valueText as optLabel from " + valuelistTable + " where typename = ?", new Object[]{value.substring(10)});
//            }
//
//            Map valueListMap = new DataObject();
//            if(dataList != null) {
//                Iterator var12 = dataList.iterator();
//
//                while(var12.hasNext()) {
//                    Object item = var12.next();
//                    Map row = (Map)item;
//                    valueListMap.put(String.valueOf(row.get("optValue")), String.valueOf(row.get("optLabel")));
//                }
//            }
//
//            ExCacheUtils.cacheData(cacheName, value, valueListMap);
//        }
//    }

    private Object invokeCommandMethod(String methodName, Map paramMap) {
        try {
            Object invokeResult = MethodUtils.invokeExactMethod(this, methodName, new Object[]{paramMap}, new Class[]{Map.class});
            if(invokeResult != null) {
                return invokeResult;
            }
        } catch (NoSuchMethodException var4) {
            this.log.error(var4.getMessage(), var4);
        } catch (Exception var5) {
            this.log.error(var5.getMessage(), var5);
        }

        return null;
    }

//    protected Map getLoginUserData() {
//        Map userData = null;
//        String token = (String)ExCacheUtils.getData("UserTokenCache", "Session-" + this.loginUserId);
//        Map tokenData = (Map)ExCacheUtils.getData("UserTokenCache", token);
//        if(tokenData != null) {
//            userData = (Map)tokenData.get("extraData");
//        }
//
//        if(userData == null) {
//            userData = new HashMap();
//        }
//
//        return (Map)userData;
//    }
}
