package com.rndchina.aisin.base.dao.impl;

import java.io.Serializable;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.Resource;

import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.criterion.Property;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.stereotype.Component;

import com.rndchina.aisin.base.dao.CommonDao;

@Component("commonDao")
public class CommonDaoImpl implements CommonDao {

	@Resource(name = "hibernateTemplate")
	private HibernateTemplate template;

	public HibernateTemplate getTemplate() {
		return this.template;
	}

	public void setTemplate(HibernateTemplate template) {
		this.template = template;
	}

	@Override
	public void save(Object o) {
		this.template.setFlushMode(HibernateTemplate.FLUSH_AUTO);
		this.getTemplate().save(o);
		this.template.flush();

	}

	@Override
	public void update(Object o) {
		this.template.setFlushMode(HibernateTemplate.FLUSH_AUTO);
		this.getTemplate().update(o);
		this.template.flush();
	}

	@Override
	public void delete(Object o) {
		this.template.setFlushMode(HibernateTemplate.FLUSH_AUTO);
		this.getTemplate().delete(o);
		this.template.flush();
	}

	@Override
	public Object get(Class<?> clazz, Serializable id) {
		return this.getTemplate().get(clazz, id);

	}

	@Override
	public List<?> findAll(Class<?> clazz) {
		return this.getTemplate().find("from " + clazz.getName());
	}

	@Override
	public List<?> findPart(final Class<?> clazz, final int pageNo,
			final int pageSize, final String orderBy, final String order,
			final Map<String, Object> parameters) {

		return this.getTemplate().executeFind(new HibernateCallback() {
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {

				Criteria criteria = session.createCriteria(clazz);

				if (parameters != null && parameters.size() > 0) {
					for (String field : parameters.keySet()) {
						criteria.add(Property.forName(field).eq(
								parameters.get(field)));
					}

				}

				if (null != orderBy && !"".equals(orderBy)) {
					if ("ASC".equals(order.toUpperCase())) {
						criteria.addOrder(org.hibernate.criterion.Order
								.asc(orderBy));
					} else if ("DESC".equals(order.toUpperCase())) {
						criteria.addOrder(org.hibernate.criterion.Order
								.desc(orderBy));
					}
				}

				criteria.setFirstResult((pageNo - 1) * pageSize);
				criteria.setMaxResults(pageSize);

				return criteria.list();
			}
		});
	}

	@Override
	public List<?> findAll(final Class<?> clazz, final String orderBy,
			final String order) {
		return this.getTemplate().executeFind(new HibernateCallback() {
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				Criteria criteria = session.createCriteria(clazz);

				if (null != orderBy && !"".equals(orderBy)) {
					if ("ASC".equals(order.toUpperCase())) {
						criteria.addOrder(org.hibernate.criterion.Order
								.asc(orderBy));
					} else if ("DESC".equals(order.toUpperCase())) {
						criteria.addOrder(org.hibernate.criterion.Order
								.desc(orderBy));
					}

				}

				return criteria.list();
			}
		});

	}

	@SuppressWarnings("unchecked")
	@Override
	public long findCount(Class<?> clazz) {
		List<Long> count = new ArrayList<Long>();
		StringBuilder builder = new StringBuilder();
		builder.append("select COUNT(*) from ");
		builder.append(clazz.getName());
		count = this.getTemplate().find(builder.toString());
		return count.size() > 0 ? (count.get(0)) : 0L;
	}

	@Override
	public long findCount(final Class<?> clazz,
			final Map<String, Object> parameters) {
		return this.getTemplate().executeFind(new HibernateCallback() {
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				Criteria criteria = session.createCriteria(clazz);
				if (null != parameters && parameters.size() > 0) {
					for (String field : parameters.keySet()) {
						criteria.add(Property.forName(field).eq(
								parameters.get(field)));
					}
				}
				return criteria.list();
			}
		}).size();

	}

	@SuppressWarnings("unchecked")
	@Override
	public long getSumPage(Class<?> className, int size) {
		List<Long> count = new ArrayList<Long>();
		count = this.getTemplate().find(
				"select COUNT(*) from " + className.getName());
		return count.size() > 0 ? (count.get(0) - 1 + size) / size : 0L;
	}

	@Override
	public List<?> searchPart(final Class<?> clazz, final int pageNo,
			final int pageSize, final String orderBy, final String order,
			final Map<String, String> conditions,
			final Map<String, Object> parameters) {

		List<?> list = this.getTemplate().executeFind(new HibernateCallback() {
			@Override
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {

				int beginIndex = (pageNo - 1) * pageSize;
				StringBuilder hql = new StringBuilder("FROM "
						+ clazz.getSimpleName() + " o WHERE 1=1 ");
				Query query = null;
				List<String> conditionsKeys = null;
				if (conditions != null && conditions.size() > 0) {
					Set<String> set = conditions.keySet();
					conditionsKeys = new ArrayList<String>(set);
					for (String key : conditionsKeys) {
						hql.append("AND o." + key + " LIKE ? ");
					}

				} else {
					return findPart(clazz, pageNo, pageSize, orderBy, order,
							parameters);
				}

				List<String> parametersKeys = null;
				if (parameters != null && parameters.size() > 0) {
					Set<String> set = parameters.keySet();
					parametersKeys = new ArrayList<String>(set);
					for (String key : parametersKeys) {
						hql.append("AND o." + key + " = ? ");
					}
				}

				System.out.println("xuxin--HQL:" + hql.toString());

				query = session.createQuery(hql.toString())
						.setFirstResult(beginIndex).setMaxResults(pageSize);

				int i = 0;
				if (conditionsKeys != null && conditionsKeys.size() > 0) {
					for (String key : conditionsKeys) {
						query.setParameter(i, conditions.get(key));
						i++;
					}
				}
				if (parametersKeys != null && parametersKeys.size() > 0) {
					for (String key : parametersKeys) {
						query.setParameter(i, parameters.get(key));
						i++;
					}
				}

				return query.list();

			}
		});

		return list;

	}

	@Override
	public List<?> findWithSql(final Class<?> clazz, final int pageNo,
			final int pageSize, final String sql, final List<?> parameters) {
		List<?> list = this.getTemplate().executeFind(new HibernateCallback() {
			@Override
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				Query query = session.createSQLQuery(sql).addEntity(clazz);
				if (pageNo > 0 && pageSize > 0) {
					int beginIndex = (pageNo - 1) * pageSize;
					query.setFirstResult(beginIndex).setMaxResults(pageSize);
				}
				if (parameters != null && parameters.size() > 0) {
					for (int i = 0; i < parameters.size(); i++) {
						query.setParameter(i, parameters.get(i));
					}
				}
				return query.list();
			}
		});
		return list;
	}

	@Override
	public List<?> findWithHql(final int currentPage, final int pageSize,
			final String hql, final Object[] parameters) {
		List<?> list = this.getTemplate().executeFind(new HibernateCallback() {
			@Override
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				int beginIndex = (currentPage - 1) * pageSize;
				Query query = session.createQuery(hql)
						.setFirstResult(beginIndex).setMaxResults(pageSize);
				if (parameters != null && parameters.length > 0) {
					for (int i = 0; i < parameters.length; i++) {
						query.setParameter(i, parameters[i]);
					}
				}
				return query.list();
			}
		});
		return list;
	}

	@Override
	public long findCountWithHql(final String countHql) {
		Object count = this.getTemplate().execute(new HibernateCallback() {
			@Override
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				return ((Number) (session.createQuery(countHql).uniqueResult()));
			}
		});

		return null == count ? 0L : (Long) count;

	}

	@Override
	public long findCountWithSql(final String countSql) {
		Object count = this.getTemplate().execute(new HibernateCallback() {
			@Override
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				return (session.createSQLQuery(countSql)).uniqueResult();
			}
		});
		int c = Integer.parseInt(count.toString());
		return c;
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Object[]> findObjectArrayWithSql(final String sql,
			final int pageNo, final int pageSize) {
		return this.getTemplate().executeFind(new HibernateCallback() {
			@Override
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				int beginIndex = (pageNo - 1) * pageSize;
				SQLQuery sqlQuery = session.createSQLQuery(sql);
				if (pageNo > 0 && pageSize > 0) {
					sqlQuery.setFirstResult(beginIndex).setMaxResults(pageSize);
				}
				return sqlQuery.list();
			}
		});

	}

	@Override
	public void batchDel(final Class<?> clazz, final String ids,
			final String idName) {
		this.getTemplate().execute(new HibernateCallback() {
			@Override
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				int flag = session.createQuery(
						"DELETE FROM " + clazz.getSimpleName() + " WHERE "
								+ idName + " IN(" + ids + ")").executeUpdate();
				return flag;
			}
		});

	}
}
