package com.yihu.hos.web.framework.dao;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.JsonNodeType;
import com.yihu.hos.core.datatype.CollectionUtil;
import com.yihu.hos.core.datatype.NumberUtil;
import com.yihu.hos.core.datatype.StringUtil;
import com.yihu.hos.core.log.Logger;
import com.yihu.hos.core.log.LoggerFactory;
import com.yihu.hos.web.framework.model.DataGridResult;
import com.yihu.hos.web.framework.util.sql.SqlCreator;
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.hibernate.jdbc.Work;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.orm.hibernate4.HibernateTemplate;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.IOException;
import java.io.Serializable;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

//import org.springframework.jdbc.core.BeanPropertyRowMapper;
//import org.springframework.jdbc.core.JdbcTemplate;
//import org.springframework.jdbc.core.RowMapper;
//import org.springframework.orm.hibernate4.HibernateTemplate;

/**
 * @author HZY
 * @vsrsion 1.0
 * Created at 2016/8/8.
 */
@Transactional
@Repository("sqlGeneralDAO")
public class SQLGeneralDAO implements XSQLGeneralDAO {
    static private final Logger logger = LoggerFactory.getLogger(SQLGeneralDAO.class);

    @Autowired
    protected ObjectMapper objectMapper;

    @Resource(
            name = "jdbcTemplate"
    )
    protected JdbcTemplate jdbcTemplate;
    @Resource(
            name = "hibernateTemplate"
    )
    protected HibernateTemplate hibernateTemplate;

    public SQLGeneralDAO() {
    }

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

    public HibernateTemplate getHibernateTemplate() {
        return this.hibernateTemplate;
    }

    public DataGridResult getDataGridResult(String hql, Integer page, Integer rows) {
        DataGridResult dataGridResult = new DataGridResult();
        Query query = this.hibernateTemplate.getSessionFactory().getCurrentSession().createQuery(hql);
        if (page != null && rows != null) {
            dataGridResult.setPageSize(rows.intValue());
            dataGridResult.setCurrPage(page.intValue());
            dataGridResult.setTotalCount(query.list().size());
            query.setMaxResults(rows.intValue());
            query.setFirstResult((page.intValue() - 1) * rows.intValue());
            dataGridResult.setDetailModelList(query.list());
        } else {
            List list = query.list();
            dataGridResult.setDetailModelList(list);
            dataGridResult.setTotalCount(list.size());
        }

        return dataGridResult;
    }

    public DataGridResult getDataGridResult( Query query , Integer page, Integer rows) {
        DataGridResult dataGridResult = new DataGridResult();
        if (page != null && rows != null) {
            dataGridResult.setPageSize(rows.intValue());
            dataGridResult.setCurrPage(page.intValue());
            dataGridResult.setTotalCount(query.list().size());
            query.setMaxResults(rows.intValue());
            query.setFirstResult((page.intValue() - 1) * rows.intValue());
            dataGridResult.setDetailModelList(query.list());
        } else {
            List list = query.list();
            dataGridResult.setDetailModelList(list);
            dataGridResult.setTotalCount(list.size());
        }

        return dataGridResult;
    }

    public void beginTransaction() throws Exception {
        this.hibernateTemplate.getSessionFactory().getCurrentSession().getTransaction().begin();
    }

    public void commitTransaction() throws Exception {
        this.hibernateTemplate.getSessionFactory().getCurrentSession().getTransaction().commit();
    }

    public void saveEntity(Object entity) throws Exception {
        if (entity != null) {
            this.hibernateTemplate.save(entity);
        }
    }

    public void updateEntity(Object entity) throws Exception {
        if (entity != null) {
            this.hibernateTemplate.update(entity);
        }
    }

    public void saveOrUpdateEntity(Object entity) throws Exception {
        if (entity != null) {
            this.hibernateTemplate.saveOrUpdate(entity);
        }
    }

    public void mergeEntity(Object entity) throws Exception {
        if (entity != null) {
            this.hibernateTemplate.merge(entity);
        }
    }

    public void deleteEntity(Object entity) throws Exception {
        if (entity != null) {
            this.hibernateTemplate.delete(entity);
        }
    }

    public <T> void deleteEntity(Class<T> cls, Serializable id) throws Exception {
        Object obj = this.hibernateTemplate.load(cls, id);
        this.hibernateTemplate.delete(obj);
    }

    public <T> T getEntity(Class<T> cls, Serializable id) throws Exception {
        return this.hibernateTemplate.get(cls, id);
    }

    public List<Map<String, Object>> queryListBySql(String sql) throws Exception {
        List result = this.jdbcTemplate.queryForList(sql);
        return result;
    }

    public List<Map<String, Object>> queryListBySql(String sql, List params) throws Exception {
        List result = this.jdbcTemplate.queryForList(sql, params.toArray());
        return result;
    }

    public <T> List<T> queryListBySql(String sql, Class obj) throws Exception {
        RowMapper<T> rowMapper = BeanPropertyRowMapper.newInstance(obj);
        List result = this.jdbcTemplate.query(sql, rowMapper);
        return result;
    }

    public <T> List<T> queryListBySql(String sql, List params, Class obj) throws Exception {
        RowMapper<T> rowMapper = BeanPropertyRowMapper.newInstance(obj);
        List result = this.jdbcTemplate.query(sql, params.toArray(), rowMapper);
        return result;
    }

    public <T> T queryObjBySql(String sql, List params, Class obj) throws Exception {
        RowMapper<T> rowMapper = BeanPropertyRowMapper.newInstance(obj);
        T result = this.jdbcTemplate.queryForObject(sql, params.toArray(), rowMapper);
        return result;
    }

    public <T> T queryObjBySql(String sql, Class obj) throws Exception {
        RowMapper<T> rowMapper = BeanPropertyRowMapper.newInstance(obj);
        T result = this.jdbcTemplate.queryForObject(sql, rowMapper);
        return result;
    }

    public <T> T scalarBySql(String sql, Class cls) throws Exception {
        T result = (T) this.jdbcTemplate.queryForObject(sql, cls);
        return result;
    }

    public void execute(String sql) throws Exception {
        this.jdbcTemplate.execute(sql);
    }

    public <T> List getEntityList(Class<T> cls, String hql) {
        Query query = this.getCurrentSession().createQuery(hql);
        return query.list();
    }

    public <T> List getEntityList(Class<T> cls, String condition, String order, Integer limit, Integer offset) throws IOException {
        Session session = this.getCurrentSession();
        Criteria criteria = session.createCriteria(cls);
        ObjectMapper objectMapper = new ObjectMapper();
        JsonNode jsonNode;
        Iterator fieldNames;
        String fieldName;
        if (!StringUtil.isEmpty(condition)) {
            jsonNode = objectMapper.readTree(condition);
            fieldNames = jsonNode.fieldNames();

            while (fieldNames.hasNext()) {
                fieldName = (String) fieldNames.next();
                if (jsonNode.get(fieldName).isInt()) {
                    criteria.add(Restrictions.eq(fieldName, Integer.valueOf(jsonNode.get(fieldName).asInt())));
                } else {
                    criteria.add(Restrictions.eq(fieldName, jsonNode.get(fieldName).asText()));
                }
            }
        }

        if (!StringUtil.isEmpty(order)) {
            jsonNode = objectMapper.readTree(order);
            fieldNames = jsonNode.fieldNames();

            while (fieldNames.hasNext()) {
                fieldName = (String) fieldNames.next();
                String value = jsonNode.get(fieldName).asText().toUpperCase();
                if (value.equals("ASC")) {
                    criteria.addOrder(Order.asc(fieldName));
                } else if (value.equals("DESC")) {
                    criteria.addOrder(Order.desc(fieldName));
                }
            }
        }

        if (limit != null) {
            criteria.setMaxResults(limit.intValue());
            if (offset != null) {
                criteria.setFirstResult((offset.intValue() - 1) * limit.intValue());
            }
        }

        return criteria.list();
    }

    public <T> List getEntityListByParentId(Class<T> cls, String parentFiledName, Integer patentId, String condition, String order, Integer limit, Integer offset) throws IOException {
        Session session = this.getCurrentSession();
        Criteria criteria = session.createCriteria(cls);
        criteria.add(Restrictions.eq(parentFiledName, patentId));
        ObjectMapper objectMapper = new ObjectMapper();
        JsonNode jsonNode;
        Iterator fieldNames;
        String fieldName;
        if (!StringUtil.isEmpty(condition)) {
            jsonNode = objectMapper.readTree(condition);
            fieldNames = jsonNode.fieldNames();

            while (fieldNames.hasNext()) {
                fieldName = (String) fieldNames.next();
                if (jsonNode.get(fieldName).isInt()) {
                    criteria.add(Restrictions.eq(fieldName, Integer.valueOf(jsonNode.get(fieldName).asInt())));
                } else {
                    criteria.add(Restrictions.eq(fieldName, jsonNode.get(fieldName).asText()));
                }
            }
        }

        if (!StringUtil.isEmpty(order)) {
            jsonNode = objectMapper.readTree(order);
            fieldNames = jsonNode.fieldNames();

            while (fieldNames.hasNext()) {
                fieldName = (String) fieldNames.next();
                String value = jsonNode.get(fieldName).asText().toUpperCase();
                if (value.equals("ASC")) {
                    criteria.addOrder(Order.asc(fieldName));
                } else if (value.equals("DESC")) {
                    criteria.addOrder(Order.desc(fieldName));
                }
            }
        }

        if (limit != null) {
            criteria.setMaxResults(limit.intValue());
            if (offset != null) {
                criteria.setFirstResult((offset.intValue() - 1) * limit.intValue());
            }
        }

        return criteria.list();
    }

    public List getList(Class tClass, String tableName, String condition, String order, Integer limit, Integer offset) {
        SqlCreator sqlCreator = new SqlCreator(tClass);
        ObjectMapper objectMapper = new ObjectMapper();

        try {
            JsonNode sql;
            Iterator query;
            String fieldName;
            String value;
            if (!StringUtil.isEmpty(condition)) {
                sql = objectMapper.readTree(condition);
                query = sql.fieldNames();

                while (query.hasNext()) {
                    fieldName = (String) query.next();
                    value = sql.get(fieldName).asText();
                    if (sql.get(fieldName).getNodeType().equals(JsonNodeType.NUMBER)) {
                        sqlCreator.equalCondition(fieldName, Integer.valueOf(Integer.parseInt(value)));
                    } else {
                        sqlCreator.equalCondition(fieldName, value);
                    }
                }
            }

            if (!StringUtil.isEmpty(order)) {
                sql = objectMapper.readTree(order);
                query = sql.fieldNames();

                while (query.hasNext()) {
                    fieldName = (String) query.next();
                    value = sql.get(fieldName).asText().toUpperCase();
                    sqlCreator.order(fieldName, value);
                }
            }
        } catch (Exception var13) {
            var13.printStackTrace();
        }

        String sql1 = sqlCreator.selectData(tableName);
        Query query1 = this.getQuery(sqlCreator, sql1);
        if (limit != null) {
            query1.setMaxResults(limit.intValue());
            if (offset != null) {
                query1.setFirstResult(offset.intValue() * limit.intValue());
            }
        }

        return query1.list();
    }

    public List getListByIdList(Class tClass, String tableName, String fieldName, List<Integer> idList) {
        SqlCreator sqlCreator = new SqlCreator(tClass);

        try {
            sqlCreator.inCondition(fieldName, idList);
        } catch (Exception var8) {
            var8.printStackTrace();
            return null;
        }

        String sql = sqlCreator.selectData(tableName);
        Query query = this.getQuery(sqlCreator, sql);
        return query.list();
    }

    public Integer getDataSetInt(Class tClass, String tableName, String condition) {
        SqlCreator sqlCreator = new SqlCreator(tClass);
        ObjectMapper objectMapper = new ObjectMapper();

        try {
            if (!StringUtil.isEmpty(condition)) {
                JsonNode sql = objectMapper.readTree(condition);
                Iterator query = sql.fieldNames();

                while (query.hasNext()) {
                    String count = (String) query.next();
                    String value = sql.get(count).asText();
                    if (NumberUtil.isInteger(value)) {
                        sqlCreator.equalCondition(count, Integer.valueOf(Integer.parseInt(value)));
                    } else {
                        sqlCreator.equalCondition(count, value);
                    }
                }
            }
        } catch (Exception var10) {
            var10.printStackTrace();
        }

        String sql1 = sqlCreator.countData(tableName);
        Query query1 = this.getQuery(sqlCreator, sql1);
        Integer count1 = Integer.valueOf(Integer.parseInt(StringUtil.toString(query1.list().get(0))));
        return count1;
    }

    public Object get(Class tClass, String tableName, Object id) {
        SqlCreator sqlCreator = new SqlCreator(tClass);
        sqlCreator.equalCondition("id", id);
        String sql = sqlCreator.selectData(tableName);
        Query query = this.getQuery(sqlCreator, sql);
        return query.uniqueResult();
    }

    public Query getQuery(SqlCreator sqlCreator, String sql) {
        SQLQuery query = this.getCurrentSession().createSQLQuery(sql);
        Iterator var4 = sqlCreator.getKeyValueMap().keySet().iterator();

        while (var4.hasNext()) {
            String key = (String) var4.next();
            Object value = sqlCreator.getKeyValueMap().get(key);
            if (value instanceof Collection) {
                query.setParameterList(key, (Collection) value);
            } else {
                query.setParameter(key, value);
            }
        }

        query.setResultTransformer(sqlCreator.getTransformer());
        return query;
    }

    public void insertBatch(final List<String> insertSqlList) {
        Session session = this.getHibernateTemplate().getSessionFactory().getCurrentSession();
        session.doWork(new Work() {
            public void execute(Connection connection) throws SQLException {
                if (!CollectionUtil.isEmpty(insertSqlList)) {
                    Statement stmt = connection.createStatement();
                    connection.setAutoCommit(false);
                    Iterator ex = insertSqlList.iterator();

                    while (ex.hasNext()) {
                        String sql = (String) ex.next();
                        stmt.addBatch(sql);
                    }

                    try {
                        stmt.executeBatch();
                    } catch (Exception var5) {
                        logger.error("insertBatch-ERROR: ", var5);
                    }

                    stmt.close();
                }

            }
        });
    }

    public Session openSession() {
        return this.getHibernateTemplate().getSessionFactory().openSession();
    }

    public Session getCurrentSession() {
        return this.getHibernateTemplate().getSessionFactory().getCurrentSession();
    }

    public Integer getMaxId(String tableName) {
        String sql = "select max(id) from " + tableName;
        SQLQuery query = this.getCurrentSession().createSQLQuery(sql);
        Object object = query.uniqueResult();
        Integer maxId = Integer.valueOf(object == null ? 1 : Integer.parseInt(object.toString()) + 1);
        return maxId;
    }

    public Query getExeuteQuery(SqlCreator sqlCreator, String sql) {
        SQLQuery query = this.getCurrentSession().createSQLQuery(sql);
        Iterator var4 = sqlCreator.getKeyValueMap().keySet().iterator();

        while (var4.hasNext()) {
            String key = (String) var4.next();
            Object value = sqlCreator.getKeyValueMap().get(key);
            if (value instanceof Collection) {
                query.setParameterList(key, (Collection) value);
            } else {
                query.setParameter(key, value);
            }
        }

        return query;
    }

    protected void doClose(Session session, Statement stmt, ResultSet rs) {
        if (rs != null) {
            try {
                rs.close();
                rs = null;
            } catch (Exception var6) {
                rs = null;
                logger.error("close-ResultSet ", var6);
                var6.printStackTrace();
            }
        }

        if (stmt != null) {
            try {
                stmt.close();
                stmt = null;
            } catch (Exception var5) {
                stmt = null;
                logger.error("close-ResultSet ", var5);
                var5.printStackTrace();
            }
        }

    }
}
