/*
 * Created on Jun 12, 2006
 * 
 * (C) Copyright TANDBERG Television Ltd.
 */

package com.tandbergtv.watchpoint.pmm.dao.hibernate;

import java.io.Serializable;
import java.util.List;

import org.apache.log4j.Logger;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.criterion.Criterion;


/**
 * The Abstract Hibernate Data Access Object that is used to save data to the persistence layer
 * 
 * @author Vijay Silva
 * 
 * @param <DO>
 *            The Data Object
 * @param <DOK>
 *            The Data Object Key
 */
public abstract class HibernateDAO<DO, DOK extends Serializable> implements
		DataAccessInterface<DO, DOK>
{
	private Class<DO> persistentClass;

	private Session session;

	/**
	 * @param persistentClass
	 *            The DataObject Class
	 * @param session
	 *            The Session used to make calls to the Persistence Layer
	 */
	public HibernateDAO(Class<DO> persistentClass, Session session)
	{
		this.persistentClass = persistentClass;
		this.session = session;
	}

	/*
	 * Method to get the Session associated with this Data Access Object
	 */
	protected Session getSession()
	{
		return session;
	}

	/**
	 * Method to ge the Class associated with this Data Access Object
	 * 
	 * @return The Data Object class that is used when saving data to the persistence layer
	 */
	public Class<DO> getPersistentClass()
	{
		return persistentClass;
	}

	/**
	 * @param entity
	 *            The Entity to save
	 * 
	 * @return The saved entity
	 * 
	 * @see com.tandbergtv.workflow.dao.DataAccessInterface#create(Object)
	 */
	public DO create(DO entity)
	{
		Logger log = Logger.getLogger(this.getClass());
		log.debug("Creating new entity in the DB...");

		DO createdEntity = this.persist(entity);

		log.debug("Successfully created new entity in DB.");

		return createdEntity;
	}

	/**
	 * @param entity
	 *            The Entity to update
	 * 
	 * @return The saved entity
	 * 
	 * @see com.tandbergtv.workflow.dao.DataAccessInterface#update(Object)
	 */
	public DO update(DO entity)
	{
		Logger log = Logger.getLogger(this.getClass());
		log.debug("Updating existing entity in the DB...");

		DO updatedEntity = this.persist(entity);

		log.debug("Successfully updated entity in DB.");

		return updatedEntity;
	}

	/*
	 * Method to persist the entity to the persistence layer
	 */
	protected DO persist(DO entity)
	{
		this.getSession().saveOrUpdate(entity);

		return entity;
	}

	/**
	 * @param entityKey
	 *            The Entity Key
	 * 
	 * @see com.tandbergtv.workflow.dao.DataAccessInterface#delete(Serializable)
	 */
	public void delete(DOK entityKey)
	{
		Logger log = Logger.getLogger(this.getClass());
		log.debug("Deleting existing entity in the DB with key: " + entityKey.toString());

		DO entity = findByKey(entityKey);
		getSession().delete(entity);

		log.debug("Successfully deleted existing entity in the DB with key: "
				+ entityKey.toString());
	}

	/**
	 * @param key
	 *            The Entity Key used to find the Entity
	 * 
	 * @return The Matching Entity
	 * 
	 * @see com.tandbergtv.workflow.dao.DataAccessInterface#findByKey(Serializable)
	 */
	@SuppressWarnings("unchecked")
	public DO findByKey(DOK key)
	{
		Logger log = Logger.getLogger(this.getClass());
		log.debug("Finding Entity in the DB with key: " + key.toString());

		DO entity = (DO) getSession().load(getPersistentClass(), key);

		log.debug("Found Entity in the DB with key: " + key.toString());

		return entity;
	}

	/**
	 * @see com.tandbergtv.workflow.dao.DataAccessInterface#findAll()
	 */
	public List<DO> findAll()
	{
		Logger log = Logger.getLogger(this.getClass());
		log.debug("Finding all entities in the DB...");

		List<DO> entityList = findByCriteria();

		log.debug("Successfully found all entities(" + entityList.size() + ") in the DB.");

		return entityList;
	}

	/*
	 * Method to find a unique matching entity given the list of criterion to search by.
	 */
	@SuppressWarnings("unchecked")
	protected DO findUniqueByCriteria(Criterion... criterion)
	{
		return (DO) this.createCriteria(criterion).uniqueResult();
	}

	/*
	 * Method to find a unique matching entity given the criteria to search by.
	 */
	@SuppressWarnings("unchecked")
	protected DO findUniqueByCriteria(Criteria criteria)
	{
		return (DO) criteria.uniqueResult();
	}

	/*
	 * Method to find a matching entity given the list of criterion to search by.
	 */
	@SuppressWarnings("unchecked")
	protected List<DO> findByCriteria(Criterion... criterion)
	{
		return this.createCriteria(criterion).list();
	}

	/*
	 * Method to find a matching entity given the criteria to search by.
	 */
	@SuppressWarnings("unchecked")
	protected List<DO> findByCriteria(Criteria criteria)
	{
		return criteria.list();
	}

	/*
	 * Method to build the criteria from the input criterion
	 */
	protected Criteria createCriteria(Criterion... criterion)
	{
		Criteria criteria = getSession().createCriteria(getPersistentClass());

		for (Criterion c : criterion)
		{
			criteria.add(c);
		}

		return criteria;
	}
}
