package com.qmth.qrzk.repository.common.base;

import java.io.Serializable;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.session.RowBounds;
import org.mybatis.spring.MyBatisSystemException;
import org.mybatis.spring.support.SqlSessionDaoSupport;

import com.qmth.qrzk.repository.service.query.QueryParams;
import com.qmth.qrzk.repository.utils.General;

public class BaseDao extends SqlSessionDaoSupport{
	
	protected final Log logger = LogFactory.getLog(getClass());
	
	public int insert(String key, Object obj){
		return this.getSqlSession().insert(key, obj);
	}
	
	public int update(String key, Object obj){
		return this.getSqlSession().update(key, obj);
	}
	  
	public int delete(String key, Serializable obj){
		return this.getSqlSession().delete(key, obj);
	}
	
	public int  delete(String key, Object obj){
		return this.getSqlSession().delete(key, obj);
	}
	
	@SuppressWarnings("unchecked")
	public <T> T get(String key, Object param){
		return (T) this.getSqlSession().selectOne(key, param);
	}
	

	public <T> T getObject(String key, Object param){
		List<T> objList = this.getSqlSession().selectList(key, param);
		if(objList==null || objList.size()==0){
			return null;
		}
		return objList.get(0);
	}
	
	public <T> List<T> getList(String key) {
		return this.getSqlSession().selectList(key);
	}
	
	public <T> List<T> getList(String key, Object param) {
		return this.getSqlSession().selectList(key, param);
	}
	
	public int getCount(String key, Map<String,Object> map){
		MappedStatement statement = this.getSqlSession().getConfiguration().getMappedStatement(key);
		BoundSql boundSql = statement.getBoundSql(map);
		String sql = General.toCountSql(boundSql.getSql());// "SELECT COUNT(1) AS CNT FROM (" + boundSql.getSql() + ") t";
		List<ParameterMapping> paramMappings = boundSql.getParameterMappings();
		PreparedStatement ps = null;
		ResultSet rs = null;
		int index = 0;
		Connection conn = null;
		try {
			conn = this.getSqlSession().getConnection();
			ps = conn.prepareStatement(sql);
			for(ParameterMapping parameterMapping : paramMappings) {
				Object retObj = map.get(parameterMapping.getProperty());
				ps.setObject(++index, retObj);
			}
			rs = ps.executeQuery();
			if(rs.next()) return rs.getInt(1);
		} catch(Exception e){
			throw new MyBatisSystemException(e);
		} finally {
			General.close(rs);
			General.close(ps);
//			General.close(conn);
		}
		return 0;
	}
	
	public int getCount(String key, QueryParams param){
		MappedStatement statement = this.getSqlSession().getConfiguration().getMappedStatement(key);
		BoundSql boundSql = statement.getBoundSql(param);
		String sql = General.toCountSql(boundSql.getSql());//"SELECT COUNT(1) AS CNT FROM (" + boundSql.getSql() + ") tt";
		List<ParameterMapping> paramMappings = boundSql.getParameterMappings();
		PreparedStatement ps = null;
		ResultSet rs = null;
		int index = 0;
		Connection conn = null;
		try {
			conn = this.getSqlSession().getConnection();
			ps = conn.prepareStatement(sql);
			for(ParameterMapping parameterMapping : paramMappings) {
				String getterMethodName = General.getterMethodName(parameterMapping.getProperty());
				Object retObj = param.getClass().getMethod(getterMethodName, new Class[]{}).invoke(param, new Object[]{});
				ps.setObject(++index, retObj);
			}
			rs = ps.executeQuery();
			if(rs.next()) return rs.getInt(1);
		} catch(Exception e){
			throw new MyBatisSystemException(e);
		} finally {
			General.close(rs);
			General.close(ps);
//			General.close(conn);
		}
		return 0;
	}
	
	/**
	 * <p>分页查询，分页相关信息和查询条件都封装到在param里面。</p>
	 * <b>注意：</b>
	 * <p>
	 * 1.不支持直接union的SQL语句，例如：select a.* from AAA a union select b.* from BBB b，
	 * 但支持这样的SQL语句，例如：select c.* from (select a.* from AAA a union select b.* from BBB b) c；
	 * </p>
	 * <p>
	 * 2.不支持直接DISTINCT的SQL语句，例如：select DISTINCT a.* from AAA a，
	 * 但支持这样的SQL语句：select b.* from (select DISTINCT a.* from AAA a) b
	 * </p>
	 * <p>
	 * 3.暂时不支持直接in list的SQL语句，例如：
	 * select id,name from s_user where id in
	 *	&lt;foreach collection="list" item="item" index="index" open="("
	 *		separator="," close=")">#{item}
	 *	&lt;/foreach>
	 * </p>
	 * @param key
	 * @param param 继承QueryParams的查询类，分页相关信息和查询条件都在里面
	 * @return
	 */
	public <T> List<T> getPagerList(String key, QueryParams param) {
		List<T> list = this.getSqlSession().selectList(key, param, new RowBounds(param.getOffset(),param.getRows())); 
		int totalNum = this.getCount(key,param);
		param.setTotalNum(totalNum);
		return list;
	}
	
	/**
	 * <p>分页查询，分页相关信息在pageInfo里面，查询条件在paramMap里面。</p>
	 * <b>注意：</b>
	 * <p>
	 * 1.不支持直接union的SQL语句，例如：select a.* from AAA a union select b.* from BBB b，
	 * 但支持这样的SQL语句，例如：select c.* from (select a.* from AAA a union select b.* from BBB b) c；
	 * </p>
	 * <p>
	 * 2.不支持直接DISTINCT的SQL语句，例如：select DISTINCT a.* from AAA a，
	 * 但支持这样的SQL语句：select b.* from (select DISTINCT a.* from AAA a) b
	 * </p>
	 * <p>
	 * 3.暂时不支持直接in list的SQL语句，例如：
	 * select id,name from s_user where id in
	 *	&lt;foreach collection="list" item="item" index="index" open="("
	 *		separator="," close=")">#{item}
	 *	&lt;/foreach>
	 * </p>
	 * @param key
	 * @param pageInfo 分页相关信息
	 * @param paramMap 查询条件
	 * @return
	 */
	public <T> List<T> getPagerList(
			String key, 
			QueryParams pageInfo,  
			Map<String,Object> paramMap){
		List<T> list = this.getSqlSession().selectList(key, paramMap, 
				new RowBounds(pageInfo.getOffset(),pageInfo.getRows()));
		int totalNum = this.getCount(key,paramMap);
		pageInfo.setTotalNum(totalNum);
		return list;
	}
	
}
