package de.terrestris.shogun2.dao;

import java.io.Serializable;
import java.util.List;

import org.hibernate.Criteria;
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.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;

import de.terrestris.shogun2.model.PersistentObject;
import de.terrestris.shogun2.paging.PagingResult;

/**
 * @author Nils Bühner
 * 
 */
public abstract class GenericHibernateDao<E extends PersistentObject, ID extends Serializable> {

	/**
	 * Represents the class of the entity
	 */
	private Class<E> clazz;

	protected GenericHibernateDao(Class<E> clazz) {
		this.clazz = clazz;
	}

	/**
	 * Hibernate SessionFactory
	 */
	@Autowired
	private SessionFactory sessionFactory;

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

	public E findById(ID id) {
		return (E) getSession().get(clazz, id);
	}

	/**
	 * Returns all Entities by calling findByCriteria(), i.e. without arguments.
	 * 
	 * @see GenericHibernateDao#findByCriteria(Criterion...)
	 * @return All entities
	 */
	public List<E> findAll() {
		return findByCriteria();
	}

	public void saveOrUpdate(E e) {
		e.setModified(DateTime.now());
		getSession().saveOrUpdate(e);
	}

	public void delete(E e) {
		getSession().delete(e);
	}

	/**
	 * Gets the results, that match a variable number of passed criterions. Call
	 * this method without arguments to find all entities.
	 * 
	 * @param criterion
	 *            A variable number of hibernate criterions
	 * @return Entities matching the passed hibernate criterions
	 */
	@SuppressWarnings("unchecked")
	public List<E> findByCriteria(Criterion... criterion) {
		Criteria criteria = getSession().createCriteria(clazz);
		criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
		for (Criterion c : criterion) {
			if (c != null) {
				criteria.add(c);
			}
		}
		return criteria.list();
	}

	/**
	 * Gets the results, that match a variable number of passed criterions,
	 * considering the paging- and sort-info at the same time.
	 * 
	 * @param firstResult
	 *            Starting index for the paging request.
	 * @param maxResults
	 *            Max number of result size.
	 * @param criterion
	 *            A variable number of hibernate criterions
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public PagingResult<E> findByCriteriaWithSortingAndPaging(Integer firstResult,
			Integer maxResults, List<Order> sorters, Criterion... criterion) {
		Criteria criteria = getSession().createCriteria(clazz);

		// add paging info
		if (maxResults != null) {
			criteria.setMaxResults(maxResults);
		}
		if (firstResult != null) {
			criteria.setFirstResult(firstResult);
		}

		// add sort info
		if (sorters != null) {
			for (Order sortInfo : sorters) {
				criteria.addOrder(sortInfo);
			}
		}

		if(criterion != null) {
			for (Criterion c : criterion) {
				if (c != null) {
					criteria.add(c);
				}
			}
		}

		return new PagingResult<E>(criteria.list(), getTotalCount());
	}

	/**
	 * Returns the total count of db entries for the current type.
	 * 
	 * @return
	 */
	private Number getTotalCount() {
		Criteria criteria = getSession().createCriteria(clazz);
		criteria.setProjection(Projections.rowCount());
		return (Long) criteria.uniqueResult();
	}
}

@@ -532,17 +532,16 @@
 %C3%BChner%0A *
- 
 %0A */%0Apub
@@ -1113,25 +1113,24 @@
 guments.%0A%09 *
- 
 %0A%09 * @see Ge
@@ -1562,25 +1562,24 @@
 ntities.%0A%09 *
- 
 %0A%09 * @param 
@@ -1925,21 +1925,19 @@
 ITY);%0A%09%09
-for (
+add
 Criterio
@@ -1941,75 +1941,41 @@
 rion
- c : criterion) %7B%0A%09%09%09if (c != null) %7B%0A%09%09%09%09criteria.add(c);%0A%09%09%09%7D%0A%09%09%7D
+sToCriteria(criteria, criterion);
 %0A%09%09r
@@ -2138,25 +2138,24 @@
 me time.%0A%09 *
- 
 %0A%09 * @param 
@@ -2939,21 +2939,19 @@
 l) %7B%0A%09%09%09
-for (
+add
 Criterio
@@ -2955,79 +2955,41 @@
 rion
- c : criterion) %7B%0A%09%09%09%09if (c != null) %7B%0A%09%09%09%09%09criteria.add(c);%0A%09%09%09%09%7D%0A%09%09%09%7D
+sToCriteria(criteria, criterion);
 %0A%09%09%7D
@@ -3046,24 +3046,33 @@
 tTotalCount(
+criterion
 ));%0A%09%7D%0A%0A%09/**
@@ -3140,16 +3140,36 @@
 pe.%0A%09 * 
+@param criterion%0A%09 *
 %0A%09 * @re
@@ -3208,16 +3208,38 @@
 alCount(
+Criterion... criterion
 ) %7B%0A%09%09Cr
@@ -3284,32 +3284,80 @@
 riteria(clazz);%0A
+%09%09addCriterionsToCriteria(criteria, criterion);%0A
 %09%09criteria.setPr
@@ -3433,11 +3433,237 @@
 lt();%0A%09%7D
+%0A%0A%09/**%0A%09 *%0A%09 * @param criteria%0A%09 * @param criterion%0A%09 */%0A%09private void addCriterionsToCriteria(Criteria criteria, Criterion... criterion) %7B%0A%09%09for (Criterion c : criterion) %7B%0A%09%09%09if (c != null) %7B%0A%09%09%09%09criteria.add(c);%0A%09%09%09%7D%0A%09%09%7D%0A%09%7D
 %0A%7D%0A

Use criterion to compute total count