package com.bcxin.survey.dao.report;

import com.bcxin.survey.vo.DwzPage;
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.transform.Transformers;
import org.hibernate.type.Type;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

/**
 * 基础类dao
 * @author admin
 *
 */
@Repository("baseDao")
public class BaseDaoImpl implements BaseDao {

	@Autowired
	protected SessionFactory sessionFactory;

	@Autowired
	@Qualifier("jdbcTemplate")
	private JdbcTemplate jdbcTemplate;

	
	protected Session getSession(){
		return sessionFactory.getCurrentSession();
	}

	@Override
	public void evictObj(Object obj){
		Session session = getSession();
		session.evict(obj);
	}

	@Override
	public void mergeObj(Object obj){
		Session session = getSession();
		session.merge(obj);
	}

	@Override
	public boolean batchSave(List<Object> list){
		Session session = getSession();
		session.beginTransaction().begin();
		int count = 0;
		for (Object object : list) {
			session.save(object);
			count++;
			if ( count % 10 == 0  ) {
				session.flush();
				session.clear();
			}
		}
		session.getTransaction().commit();
		session.close();
		return true;
	}

	@Override
	public Criteria createCriteria(Class clazz){
		return getSession().createCriteria(clazz);
	}

	@Override
	public <T>T get(Class<T> clazz,Long oid){
		return (T)getSession().get(clazz,oid);
	}

	@Override
	public <T>T findByCriterionToUnique(Class<T> clazz,Criterion criterion){
		Criteria criteria = createCriteria(clazz);
		if(criterion != null){
			criteria.add(criterion);
		}
		return (T)criteria.uniqueResult();
	}

	@Override
	public void save(Object obj){
		getSession().saveOrUpdate(obj);
	}

	@Override
	public void saveOrUpdate(Object obj) {
		getSession().saveOrUpdate(obj);
	}

	@Override
	public void update(Object obj){
		getSession().saveOrUpdate(obj);
	}

	@Override
	public void delete(Object obj){
		Session session = getSession();
		if(obj != null){
			session.delete(obj);
		}
	}

	@Override
	public <T>List findAll(Class<T> clazz){
		Criteria criteria = createCriteria(clazz);
		return criteria.list();
	}

	@Override
	public <T>List findByCriterion(Class<T> clazz,Criterion criterion){
		Criteria criteria = createCriteria(clazz);
		if(criterion != null){
			criteria.add(criterion);
		}
		return criteria.list();
	}

	@Override
	public List findByHql(String queryString, Object value) throws DataAccessException {
		return findByHql(queryString, new Object[] { value });
	}

	@Override
	public <T>List findByHql(final String queryString, final Object[] values) {
		Query queryObject = getSession().createQuery(queryString);
		if (values != null) {
			for (int i = 0; i < values.length; i++) {
				if (values[i] != null) {
					queryObject.setParameter(i, values[i]);
				}
			}
		}
		return queryObject.list();
	}

	@Override
	public List findByHql(String queryString) throws DataAccessException {
		return findByHql(queryString, (Object[]) null);
	}

	@Override
	public List find(String queryString,Map paras){
		Query queryObject = getSession().createQuery(queryString);
		for(Iterator it = paras.entrySet().iterator();it.hasNext();){
			Entry entry = (Entry)it.next();
			queryObject.setParameter((String)entry.getKey(),entry.getValue());
		}
		return queryObject.list();
	}

	@Override
	public List findPageByHql(String queryString,Map paras,DwzPage page){
		Query query = getSession().createQuery(queryString);
		for(Iterator it = paras.entrySet().iterator();it.hasNext();){
			Entry entry = (Entry)it.next();
			query.setParameter((String)entry.getKey(),entry.getValue());
		}
		if(null!=page){
			page.setTotalCount(getCount(queryString,paras));
			query.setFirstResult((page.getPageNum() - 1) * page.getNumPerPage());
			query.setMaxResults(page.getNumPerPage());
		}
		return query.list();
	}

	@Override
	public Integer getCount(String queryString,Map paras){
		String hql = "select count(*) "+queryString;
		Query query =  getSession().createQuery(hql);
		for(Iterator it = paras.entrySet().iterator();it.hasNext();){
			Entry entry = (Entry)it.next();
			query.setParameter((String)entry.getKey(),entry.getValue());
		}
		return ((Long)query.uniqueResult()).intValue();   
	}

	@Override
	public List getObejctByCollection(String queryString,String name,Collection collection){
		return getSession().createQuery(queryString).setParameterList(name, collection).list();
	}

	@Override
	public List getObejctByCollection(String queryString,String name,Collection collection,Type type){
		return getSession().createQuery(queryString).setParameterList(name, collection, type).list();
	}

	@Override
	public <T>List findByCriterionForPage(Class<T> clazz, List<Criterion> criterionList, DwzPage page) {
		Criteria criteria = createCriteria(clazz);
		if(criterionList != null) {
			for(int i = 0; i < criterionList.size(); i++) {
				criteria.add(criterionList.get(i));
			}
		}
		criteria.addOrder(Order.desc("oid"));
		if( page != null) {
			int totalCount = ((Long) criteria.setProjection(Projections.rowCount()).uniqueResult()).intValue();
			page.setTotalCount(totalCount);
			
			criteria.setProjection(null);
			criteria.setFirstResult((page.getPageNum() - 1) * page.getNumPerPage()).setMaxResults(page.getNumPerPage());
		} 
		
		return criteria.list();
	}

	@Override
	public <T>List findByCriterionForPage(Class<T> clazz, List<Criterion> criterionList, DwzPage page, Order order) {
		Criteria criteria = createCriteria(clazz);
		if(criterionList != null) {
			for(int i = 0; i < criterionList.size(); i++) {
				criteria.add(criterionList.get(i));
			}
		}
		if(order != null) {
			criteria.addOrder(order);
		}
		if( page != null) {
			int totalCount = ((Long) criteria.setProjection(Projections.rowCount()).uniqueResult()).intValue();
			page.setTotalCount(totalCount);
			
			criteria.setProjection(null);
			criteria.setFirstResult((page.getPageNum() - 1) * page.getNumPerPage()).setMaxResults(page.getNumPerPage());
		} 
		
		return criteria.list();
	}

	@Override
	public <T>List findByCriterion(Class<T> clazz, List<Criterion> criterionList) {
		Criteria criteria = createCriteria(clazz);
		if(criterionList != null) {
			for(int i = 0; i < criterionList.size(); i++) {
				criteria.add(criterionList.get(i));
			}
		}
		criteria.addOrder(Order.desc("oid"));
		return criteria.list();
	}

	@Override
	public <T>List findByCriterion(Class<T> clazz, List<Criterion> criterionList, List<Order> orderList) {
		Criteria criteria = createCriteria(clazz);
		if(criterionList != null) {
			for(int i = 0; i < criterionList.size(); i++) {
				criteria.add(criterionList.get(i));
			}
		}
		if(orderList !=null && orderList.size() > 0){
			for (Order order : orderList){
				criteria.addOrder(order);
			}
		}
		return criteria.list();
	}

	@Override
	public <T>List findByCriterion(Class<T> clazz, List<Criterion> criterionList, Order order) {
		Criteria criteria = createCriteria(clazz);
		if(criterionList != null) {
			for(int i = 0; i < criterionList.size(); i++) {
				criteria.add(criterionList.get(i));
			}
		}
		if( order != null){
			criteria.addOrder(order);
		}
		return criteria.list();
	}

	@Override
	public int executeUpdate(final String sql) {
		int result ;    
        Query query = this.getSession().createSQLQuery(sql);
        result = query.executeUpdate();
        return result;
	}

	@Override
	public List findBySQL(String sql, final Object[] values) {
		Query query = this.getSession().createSQLQuery(sql).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);    
		if (values != null) {
			for (int i = 0; i < values.length; i++) {
				if (values[i] != null) {
					query.setParameter(i, values[i]);
				}
			}
		}
		return query.list();
	}


	@Override
	public Integer findCountBySQL(String sql, final Object[] values) {
		sql = "select count(0) AS 'count' from (" + sql + ")t";
		Query query = this.getSession().createSQLQuery(sql).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
		if (values != null) {
			for (int i = 0; i < values.length; i++) {
				if (values[i] != null) {
					query.setParameter(i, values[i]);
				}
			}
		}
		List<Map<String,Object>> list = query.list();
		if(list != null && list.size() > 0){
			return Integer.parseInt(list.get(0).get("count").toString());
		}
		return 0;
	}
	@Override
	public <T> List findByCriterionForPage(Class<T> clazz, List<Criterion> criterionList, DwzPage page, List<Order> orderList) {
		Criteria criteria = createCriteria(clazz);
		if(criterionList != null) {
			for(int i = 0; i < criterionList.size(); i++) {
				criteria.add(criterionList.get(i));
			}
		}
		if(orderList !=null && orderList.size() > 0){
			for (Order order : orderList){
				criteria.addOrder(order);
			}
		}
		if( page != null) {
			int totalCount = ((Long) criteria.setProjection(Projections.rowCount()).uniqueResult()).intValue();
			page.setTotalCount(totalCount);
			
			criteria.setProjection(null);
			criteria.setFirstResult((page.getPageNum() - 1) * page.getNumPerPage()).setMaxResults(page.getNumPerPage());
		} 
		return criteria.list();
	}

	@Override
	public <T> T load(Class<T> clazz, Long oid) {
		return (T) this.getSession().load(clazz, oid);
	}

	@Override
	public <T>List findByCriterionForPage(Class<T> clazz, List<Criterion> criterionList, int pagesize, int offset) {
		Criteria criteria = createCriteria(clazz);
		if(criterionList != null) {
			for(int i = 0; i < criterionList.size(); i++) {
				criteria.add(criterionList.get(i));
			}
		}
		//criteria.addOrder(Order.desc("oid"));
		
		if( offset>=0) {
			int totalCount = ((Long) criteria.setProjection(Projections.rowCount()).uniqueResult()).intValue();
			
			criteria.setProjection(null);
			criteria.setFirstResult((offset-1)*pagesize).setMaxResults(pagesize);
		} 
		
		return criteria.list();
	}

	@Override
	public <T>List findByCriterionForPage(Class<T> clazz, List<Criterion> criterionList, int pagesize, int offset, Order order) {
		Criteria criteria = createCriteria(clazz);
		if(criterionList != null) {
			for(int i = 0; i < criterionList.size(); i++) {
				criteria.add(criterionList.get(i));
			}
		}
		if(order != null) {
			criteria.addOrder(order);
		}
		
		if( offset>=0) {
			int totalCount = ((Long) criteria.setProjection(Projections.rowCount()).uniqueResult()).intValue();
			
			criteria.setProjection(null);
			criteria.setFirstResult((offset-1)*pagesize).setMaxResults(pagesize);
		} 
		
		return criteria.list();
	}
}
