package com.fp.armas.portal.dao.general;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;

import javax.persistence.EntityExistsException;
import javax.persistence.EntityManager;
import javax.persistence.EntityNotFoundException;
import javax.persistence.LockTimeoutException;
import javax.persistence.NoResultException;
import javax.persistence.NonUniqueResultException;
import javax.persistence.OptimisticLockException;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceException;
import javax.persistence.PessimisticLockException;
import javax.persistence.QueryTimeoutException;
import javax.persistence.RollbackException;
import javax.persistence.TransactionRequiredException;

import com.fp.armas.portal.dao.exceptions.DaoException;
import com.fp.armas.portal.util.PortalMessages;
import com.fp.armas.portal.util.RegistroException;
import com.fp.armas.portal.util.qualifier.DefaultDao;

/**
 * Implementaci&oacute;n del DAO gen&eacute;rico
 * @author dcruz
 *
 * @param <T>
 */
@DefaultDao
public class GenericDaoImpl<T extends Serializable> implements GenericDao<T>{
	
	/**
	 * Contexto de persistencia asociado a la base
	 */
	@PersistenceContext(unitName="portalPU")
	private EntityManager entityManager;
	
	private Class<T> idClass;
	
	@SuppressWarnings("unchecked")
	public GenericDaoImpl(Class idClass) {
		this.idClass = idClass;
	}

	@Override
	public void create(T entity) throws DaoException {
		// TODO Auto-generated method stub
		try{
			this.getEntityManager().clear();
			this.getEntityManager().persist(entity);
			this.getEntityManager().flush();
		} catch(PersistenceException e){
			throw transformDaoException(e);
		} catch (Throwable e) {
			throw new DaoException(e);
		}
	}

	@Override
	public void update(T entity) throws DaoException {
		// TODO Auto-generated method stub
		try {
			this.getEntityManager().clear();
			this.getEntityManager().merge(entity);
			this.getEntityManager().flush();
		} catch(PersistenceException e){
			throw transformDaoException(e);
		} catch (Throwable e) {
			throw new DaoException(e);
		}
	}

	@Override
	public void delete(T entity) throws DaoException {
		// TODO Auto-generated method stub
		try{
			this.getEntityManager().clear();
			this.getEntityManager().remove(this.getEntityManager().contains(entity) ? entity : this.getEntityManager().merge(entity));
			this.getEntityManager().flush();
		} catch(PersistenceException e){
			throw transformDaoException(e);
		} catch (Throwable e) {
			throw new DaoException(e);
		}
	}
	
	@Override
	public T buscarPorId(Serializable id) throws RegistroException {
		try {
			return this.getEntityManager().find(idClass, id);
		} catch (PersistenceException e) {
			throw transformDaoException(e);
		} catch (Throwable e) {
			throw new DaoException(e);
		}
	}
	
	@Override
	public void detach(T entity) throws RegistroException {
		try {
			this.getEntityManager().detach(entity);
		} catch (PersistenceException e) {
			throw transformDaoException(e);
		} catch (Throwable e) {
			throw new DaoException(e);
		}
	}

	@Override
	public void refresh(T entity) throws RegistroException {
		try {
			this.getEntityManager().refresh(entity);
		} catch (PersistenceException e) {
			throw transformDaoException(e);
		} catch (Throwable e) {
			throw new DaoException(e);
		}
	}

	public EntityManager getEntityManager() {
		return entityManager;
	}
	
	private DaoException transformDaoException(PersistenceException e){
		if(e instanceof EntityExistsException){
			return new DaoException(PortalMessages.getInstancia().getString("error.jpa.entity.exists"), e);
		}else if(e instanceof EntityNotFoundException){
			return new DaoException(PortalMessages.getInstancia().getString("error.jpa.entity.notfound"), e);
		}else if(e instanceof LockTimeoutException){
			return new DaoException(PortalMessages.getInstancia().getString("error.jpa.lock.timeout"), e);
		}else if(e instanceof NonUniqueResultException){
			return new DaoException(PortalMessages.getInstancia().getString("error.jpa.entity.nonuniqueresult"), e);
		}else if(e instanceof NoResultException){
			return new DaoException(PortalMessages.getInstancia().getString("error.jpa.entity.noresult"), e);
		}else if(e instanceof OptimisticLockException){
			return new DaoException(PortalMessages.getInstancia().getString("error.jpa.lock.optimisticlock"), e);
		}else if(e instanceof PessimisticLockException){
			return new DaoException(PortalMessages.getInstancia().getString("error.jpa.lock.optimisticlock"), e);
		}else if(e instanceof QueryTimeoutException){
			return new DaoException(PortalMessages.getInstancia().getString("error.jpa.entity.querytimeout"), e);
		}else if(e instanceof RollbackException){
			return new DaoException(PortalMessages.getInstancia().getString("error.jpa.transaction.rollback"), e);
		}else if(e instanceof TransactionRequiredException){
			return new DaoException(PortalMessages.getInstancia().getString("error.jpa.transaction.requiredtransaction"), e);
		}
		return new DaoException(e);
	}

}
