/*
	cursus - Race series management program
	Copyright 2011  Simon Arlott

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package eu.lp0.cursus.db.dao;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;

import eu.lp0.cursus.db.DatabaseSession;
import eu.lp0.cursus.db.data.AbstractEntity;

public abstract class AbstractDAO<E extends AbstractEntity> {
	protected final Class<E> clazz;

	public AbstractDAO(Class<E> clazz) {
		this.clazz = clazz;
	}

	EntityManager getEntityManager() {
		return DatabaseSession.getEntityManager();
	}

	/**
	 * Save/update transient/persisted (but not detached) entity
	 */
	public void persist(E entity) {
		DatabaseSession.getEntityManager().persist(entity);
	}

	/**
	 * Copy detached entity to an updated persisted entity, merging all changes
	 * 
	 * Merge behaviour may cause unexpected changes (override with DIY merge)
	 */
	protected E merge(E entity) {
		return DatabaseSession.getEntityManager().merge(entity);
	}

	/**
	 * Remove persisted entity
	 */
	public void remove(E entity) {
		DatabaseSession.getEntityManager().remove(entity);
	}

	/**
	 * Detach persisted entity
	 */
	public void detach(E entity) {
		// Don't detach during a transaction as there may be persisted changes not yet committed
		assert (!DatabaseSession.isActive());
		DatabaseSession.getEntityManager().detach(entity);
	}

	public E get(E entity) {
		EntityManager em = getEntityManager();
		CriteriaBuilder cb = em.getCriteriaBuilder();

		CriteriaQuery<E> q = cb.createQuery(clazz);
		Root<E> s = q.from(clazz);
		q.select(s);
		q.where(cb.equal(s.get("id"), entity.getId())); //$NON-NLS-1$

		TypedQuery<E> tq = em.createQuery(q);
		return tq.getSingleResult();
	}

	public List<E> findAll() {
		EntityManager em = getEntityManager();
		CriteriaBuilder cb = em.getCriteriaBuilder();

		CriteriaQuery<E> q = cb.createQuery(clazz);
		Root<E> s = q.from(clazz);
		q.select(s);

		TypedQuery<E> tq = em.createQuery(q);
		return tq.getResultList();
	}
}
@@ -963,24 +963,70 @@
 eria.Root;%0A%0A
+import com.google.common.base.Preconditions;%0A%0A
 import eu.lp
@@ -1054,16 +1054,16 @@
 ession;%0A
-
 import e
@@ -1442,32 +1442,70 @@
 ist(E entity) %7B%0A
+%09%09Preconditions.checkNotNull(entity);%0A
 %09%09DatabaseSessio
@@ -1740,24 +1740,62 @@
 E entity) %7B%0A
+%09%09Preconditions.checkNotNull(entity);%0A
 %09%09return Dat
@@ -1915,16 +1915,54 @@
 tity) %7B%0A
+%09%09Preconditions.checkNotNull(entity);%0A
 %09%09Databa
@@ -2177,15 +2177,32 @@
 d%0A%09%09
-assert 
+Preconditions.checkState
 (!Da
@@ -2225,16 +2225,90 @@
 Active()
+, %22Transaction active%22); //$NON-NLS-1$%0A%09%09Preconditions.checkNotNull(entity
 );%0A%09%09Dat
@@ -2662,32 +2662,32 @@
 createQuery(q);%0A
-
 %09%09return tq.getS
@@ -2697,24 +2697,119 @@
 leResult();%0A
+%09%09Preconditions.checkNotNull(entity);%0A%09%09return getEntityManager().find(clazz, entity.getId());%0A
 %09%7D%0A%0A%09public 

add argument and state checks