package com.fp.persistence.commondb;

import java.sql.Timestamp;
import java.util.ResourceBundle;

import javax.ejb.NoSuchEntityException;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NameNotFoundException;
import javax.naming.NamingException;
import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import javax.persistence.Query;
import javax.persistence.TypedQuery;
import javax.transaction.HeuristicMixedException;
import javax.transaction.HeuristicRollbackException;
import javax.transaction.NotSupportedException;
import javax.transaction.RollbackException;
import javax.transaction.SystemException;
import javax.transaction.TransactionManager;
import javax.transaction.UserTransaction;

import org.hibernate.HibernateException;
import org.hibernate.Session;

import bitronix.tm.TransactionManagerServices;

import com.fp.common.exception.APPException;
import com.fp.common.exception.CommonException;
import com.fp.common.helper.BeanManager;
import com.fp.common.logger.APPLogger;
import com.fp.dto.AbstractDataTransport;
import com.fp.dto.data.SaveData;
import com.fp.dto.hb.Cache;
import com.fp.dto.hb.HibernateBean;
import com.fp.dto.hb.History;
import com.fp.dto.hb.Log;
import com.fp.persistence.commondb.cache.CacheManager;
import com.fp.persistence.commondb.exception.CommondbException;
import com.fp.persistence.commondb.helper.FormatDates;
import com.fp.persistence.commondb.log.Audit;

public class PersistenceHelper {

    /**
     * Almacena un EntityManager de JPA.
     */
    private static final ThreadLocal<EntityManager> threadSession = new ThreadLocal<EntityManager>();
    /**
     * Almacena una transaccion de Hibernate.
     */
    // private static final ThreadLocal<EntityTransaction> threadTransaction = new ThreadLocal<EntityTransaction>();
    private static final ThreadLocal<UserTransaction> threadTransaction = new ThreadLocal<UserTransaction>();
    private static final ThreadLocal<TransactionManager> threadTransactionManager = new ThreadLocal<TransactionManager>();
    private static final ThreadLocal<EntityTransaction> threadEntityTransaction = new ThreadLocal<EntityTransaction>();
    private static final ThreadLocal<Boolean> threadcommit = new ThreadLocal<Boolean>();

    /**
     * Retorna una session de hibernate.
     *
     * @return s
     * @throws CommonException
     * @throws Exception
     */
    public static Session getSession() throws CommondbException {
        Session s = (Session) PersistenceHelper.threadSession.get().getDelegate();
        if (s == null) {
            throw new CommondbException("COMMONDB-0004", "SESION NO ASOCIADA A UNA TRANSACCION");
        }
        return s;
    }

    public static boolean isrollbackonly() {
        try {
            UserTransaction ut = PersistenceHelper.threadTransaction.get();
            if (ut != null) {
                int i = ut.getStatus();
                if (i == javax.transaction.Status.STATUS_MARKED_ROLLBACK) {
                    return true;
                }
            }
            TransactionManager tm = PersistenceHelper.threadTransactionManager.get();
            if (tm != null) {
                int i = tm.getStatus();
                if (i == javax.transaction.Status.STATUS_MARKED_ROLLBACK) {
                    return true;
                }
            }
            return false;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * Retorna una Connection de tipo sql
     *
     * @return Connection
     * @throws CommonException
     * @throws Exception
     */
    @SuppressWarnings("deprecation")
    /*
    public static Connection getConnection() throws CommondbException {
        Session s = (Session) PersistenceHelper.threadSession.get().getDelegate();
        if (s == null) {
            throw new CommondbException("COMMONDB-0004", "SESION NO ASOCIADA A UNA TRANSACCION");
        }
        return s.connection();
    }
     */

    public static EntityManager getEntityManager() throws CommondbException {
        EntityManager em = PersistenceHelper.threadSession.get();
        if (em == null) {
            throw new CommondbException("COMMONDB-0004", "SESION NO ASOCIADA A UNA TRANSACCION");
        }
        return em;
    }

    /**
     * Encera y cierra el EntityManager.
     */
    public static void closeSession() {
        try {
            EntityManager em = PersistenceHelper.threadSession.get();
            if ((em != null)) {
                em.clear();
            }
            if (em.isOpen()) {
                em.close();
            }
            PersistenceHelper.threadTransaction.set(null);
            PersistenceHelper.threadSession.set(null);
            PersistenceHelper.threadcommit.set(null);
            PersistenceHelper.threadTransactionManager.set(null);
            PersistenceHelper.threadEntityTransaction.set(null);
        } catch (Exception e) {
            APPLogger.getLogger().error(e);
        }
    }

    /**
     * Fija una session de hibernate.
     *
     * @param session
     * @throws Exception
     */
    public static boolean getThreadcommit() {
        if (PersistenceHelper.threadcommit.get() == null) {
            return true;
        }
        return PersistenceHelper.threadcommit.get();
    }

    /**
     * Fija una session de hibernate.
     *
     * @param session
     * @throws Exception
     */
    public static void setThreadcommit(boolean pDocommit) {
        PersistenceHelper.threadcommit.set(pDocommit);
    }

    /**
     * Fija una session de hibernate.
     *
     * @param session
     * @throws Exception
     */
    public static void setEntityManager(EntityManager pEntityManager) {
        PersistenceHelper.threadSession.set(pEntityManager);
    }

    /**
     * Inicia el proceso de una transaccion de hibernate..
     *
     * @throws CommonException
     * @throws HibernateException
     * @throws SystemException
     * @throws NotSupportedException
     * @throws NamingException
     * @throws Exception
     */
    public static EntityTransaction beginTransactionLocal() throws HibernateException, CommondbException, NotSupportedException, SystemException,
    NamingException {
        EntityTransaction et = PersistenceHelper.getEntityManager().getTransaction();
        PersistenceHelper.threadEntityTransaction.set(et);
        et.begin();
        return et;
    }

    /**
     * Inicia el proceso de una transaccion de hibernate..
     *
     * @throws CommonException
     * @throws HibernateException
     * @throws SystemException
     * @throws NotSupportedException
     * @throws NamingException
     * @throws Exception
     */
    public static UserTransaction beginTransaction() throws HibernateException, CommondbException, NotSupportedException, SystemException,
    NamingException {
        PersistenceHelper.called();
        UserTransaction ut = (UserTransaction) new InitialContext().lookup("java:comp/UserTransaction");
        PersistenceHelper.threadTransaction.set(ut);
        ut.begin();
        PersistenceHelper.getEntityManager().joinTransaction();
        return ut;
    }

    public static void beginNewTransaction() throws HibernateException, CommondbException, NotSupportedException, SystemException, NamingException {
        // WebLogic javax.transaction.TransactionManager
        // JBOSS java:/TransactionManager
        TransactionManager tm = null;
        try {
            tm = (TransactionManager) new InitialContext().lookup("java:/TransactionManager");
        } catch (NameNotFoundException e) {
            tm = TransactionManagerServices.getTransactionManager();
        }

        PersistenceHelper.threadTransactionManager.set(tm);
        tm.begin();
        PersistenceHelper.getEntityManager().joinTransaction();

    }

    /**
     * Graba los dml que estan en la transaccion.
     *
     * @throws CommonException
     * @throws Exception
     */
    public static void commitNewTransaction() throws Exception {
        if (!PersistenceHelper.getThreadcommit()) {
            PersistenceHelper.rollbackNewTransaction();
            return;
        }
        if (PersistenceHelper.isrollbackonly()) {
            PersistenceHelper.called();
            throw new APPException("FLIP01", "TRANSACCION NO PERMITE COMMIT");
        }
        TransactionManager tx = PersistenceHelper.threadTransactionManager.get();
        try {
            if ((tx != null)) {
                try {
                    if (ResourceBundle.getBundle("jndi").getString(Context.INITIAL_CONTEXT_FACTORY)
                            .compareTo("bitronix.tm.jndi.BitronixInitialContextFactory") == 0) {
                        PersistenceHelper.flushTransaction();
                        PersistenceHelper.getEntityManager().createNativeQuery("commit").executeUpdate();
                    }
                } catch (Exception e) {
                    // No hacer nada
                }

                tx.commit();
            } else {
                throw new CommondbException("COMMONDB-0005", "TRANSACCION YA APLICADA");
            }
        } finally {
            PersistenceHelper.getEntityManager().clear();
            PersistenceHelper.threadTransactionManager.set(null);
        }
    }

    /**
     * Graba los dml que estan en la transaccion.
     *
     * @throws CommonException
     * @throws Exception
     */
    public static void commitTransaction() throws CommondbException, SecurityException, IllegalStateException, RollbackException,
    HeuristicMixedException, HeuristicRollbackException, SystemException, APPException {
        if (!PersistenceHelper.getThreadcommit()) {
            PersistenceHelper.rollbackTransaction();
            return;
        }
        PersistenceHelper.called();
        if (PersistenceHelper.isrollbackonly()) {
            throw new APPException("COMMONDB-0006", "TRANSACCION NO PUEDE SER PROCESADA ");
        }
        UserTransaction tx = PersistenceHelper.threadTransaction.get();
        try {
            if ((tx != null)) {
                tx.commit();
            } else {
                throw new CommondbException("COMMONDB-0005", "TRANSACCION YA APLICADA");
            }
        } finally {
            PersistenceHelper.getEntityManager().clear();
            PersistenceHelper.threadTransaction.set(null);
        }
    }

    /**
     * Graba los dml que estan en la transaccion.
     *
     * @throws CommonException
     * @throws Exception
     */
    public static void commitTransactionLocal() throws CommondbException, SecurityException, IllegalStateException, RollbackException,
    HeuristicMixedException, HeuristicRollbackException, SystemException, APPException {
        if (!PersistenceHelper.getThreadcommit()) {
            PersistenceHelper.rollbackTransaction();
            return;
        }
        PersistenceHelper.called();
        if (PersistenceHelper.isrollbackonly()) {
            throw new APPException("COMMONDB-0006", "TRANSACCION NO PUEDE SER PROCESADA ");
        }
        EntityTransaction tx = PersistenceHelper.threadEntityTransaction.get();
        try {
            if ((tx != null)) {
                tx.commit();
            } else {
                throw new CommondbException("COMMONDB-0005", "TRANSACCION YA APLICADA");
            }
        } finally {
            PersistenceHelper.getEntityManager().clear();
            PersistenceHelper.threadTransaction.set(null);
        }
    }

    /**
     * Graba los dml que estan en la transaccion.
     *
     * @throws CommondbException
     */
    public static void flushTransaction() throws Exception {

        if (PersistenceHelper.isrollbackonly()) {
            PersistenceHelper.called();
            throw new APPException("COMMONDB-0006", "TRANSACCION NO PUEDE SER PROCESADA ");
        }
        EntityManager em = PersistenceHelper.getEntityManager();
        em.flush();
    }

    private static void called() {
        StackTraceElement st = new Exception().getStackTrace()[2];
        StackTraceElement st1 = new Exception().getStackTrace()[1];
        APPLogger.getLogger().info(
                st1.getMethodName().toUpperCase() + "==>>" + st.getClassName() + "." + st.getMethodName() + ":" + st.getLineNumber());
    }

    /**
     * rollback de los dml que estan dentro de la transaccion.
     *
     * @throws SystemException
     * @throws SecurityException
     * @throws IllegalStateException
     *
     * @throws CommonException
     */
    public static void rollbackTransaction() {
        PersistenceHelper.called();
        UserTransaction tx = PersistenceHelper.threadTransaction.get();
        try {
            if ((tx != null)) {
                try {
                    PersistenceHelper.getEntityManager().createNativeQuery("rollback").executeUpdate();
                } catch (Exception e) {
                    // NO HACER NADA
                }
                tx.setRollbackOnly();
                tx.rollback();
            }
        } catch (Exception e1) {
            APPLogger.getLogger().error(e1, e1);
        } finally {
            PersistenceHelper.threadTransaction.set(null);
        }
    }

    /**
     * rollback de los dml que estan dentro de la transaccion.
     *
     * @throws SystemException
     * @throws SecurityException
     * @throws IllegalStateException
     *
     * @throws CommonException
     */
    public static void rollbackTransactionLocal() {
        PersistenceHelper.called();
        EntityTransaction tx = PersistenceHelper.threadEntityTransaction.get();
        try {
            if ((tx != null)) {
                try {
                    PersistenceHelper.getEntityManager().createNativeQuery("rollback").executeUpdate();
                } catch (Exception e) {
                    // NO HACER NADA
                }
                tx.setRollbackOnly();
                tx.rollback();
            }
        } catch (Exception e1) {
            APPLogger.getLogger().error(e1, e1);
        } finally {
            PersistenceHelper.threadTransaction.set(null);
        }
    }

    /**
     * rollback de los dml que estan dentro de la transaccion.
     *
     * @throws SystemException
     * @throws SecurityException
     * @throws IllegalStateException
     *
     * @throws CommonException
     */
    public static void rollbackNewTransaction() {
        Exception e = new Exception();
        StackTraceElement s = e.getStackTrace()[1];
        APPLogger.getLogger().error(s.getClassName() + "." + s.getMethodName() + ":" + s.getLineNumber());
        TransactionManager tx = PersistenceHelper.threadTransactionManager.get();
        if (PersistenceHelper.isrollbackonly()) {
        }
        try {
            if ((tx != null)) {
                try {
                    PersistenceHelper.getEntityManager().createNativeQuery("rollback").executeUpdate();
                } catch (Exception ex) {
                    tx.setRollbackOnly();
                    // NO HACER NADA
                }
                tx.setRollbackOnly();
                tx.rollback();
            }
        } catch (Exception e1) {
            APPLogger.getLogger().error(e1, e1);
        } finally {
            PersistenceHelper.threadTransactionManager.set(null);
        }
    }

    /**
     * Retorna verdadero si a la transacci�n se dio un commit;
     *
     * @return boolean
     * @throws Exception
     */
    public static boolean isCommitted() throws Exception {
        // EntityTransaction tx = PersistenceHelper.threadTransaction.get();
        UserTransaction tx = PersistenceHelper.threadTransaction.get();
        // if ((tx != null) && !tx.isActive()) {
        if ((tx != null)) {
            return false;
        }
        return true;
    }

    /**
     * Retorna verdadero si a la transacci�n se dio un commit;
     *
     * @return boolean
     * @throws Exception
     */
    public static boolean isRolledBack() throws Exception {
        // EntityTransaction tx = PersistenceHelper.threadTransaction.get();
        // if ((tx != null) && !tx.isActive()) {
        UserTransaction tx = PersistenceHelper.threadTransaction.get();
        if ((tx != null)) {
            return false;
        }
        return true;
    }

    /**
     * Inserta un registro en la base de datos.
     *
     * @param pClassName Nombre de la clase que maneja la persistencia de una
     * tabla.
     * @param pBean Bean a insertar.
     * @throws CommonException
     * @throws Exception
     */
    public static void save(HibernateBean pBean) throws CommondbException, Exception {
        EntityManager em = PersistenceHelper.getEntityManager();
        Object id = BeanManager.getBeanAttributeValue(pBean, "pk");
        if ((id instanceof History)) {
            if (BeanManager.getBeanAttributeValue(pBean, "datefrom") == null) {
                Timestamp t = FormatDates.getInstance().getDataBaseTimestamp();
                BeanManager.setBeanAttributeValue(pBean, "datefrom", t);
            }
            History pk = (History) id;
            BeanManager.setBeanAttributeValue(pk, "dateto", FormatDates.getDefaultExpiryTimestamp());
        }
        PersistenceHelper.setIngressUser(pBean);
        PersistenceHelper.setLastupdate(pBean);
        PersistenceHelper.setCreationDate(pBean);
        // s.psave(pClassName,pBean);
        em.persist(pBean);
        if (pBean instanceof Log) {
            Audit.insert(pBean);
        }
    }

    /**
     * Actualiza un registro en la base de datos.
     *
     * @param pBean Bean a actualiar.
     * @throws CommonException
     * @throws Exception
     */
    public static void update(HibernateBean pBean) throws CommondbException {
        EntityManager em = PersistenceHelper.getEntityManager();
        // pBean = em.merge(pBean);
        if (!em.contains(pBean)) {
            throw new NoSuchEntityException();
        }
    }

    /**
     * Actualiza o inserta un registro en la base de datos.
     *
     * @param pBean Bean a actualiar o insertar.
     * @throws CommonException
     * @throws Exception
     */
    public static void saveOrUpdate(HibernateBean pBean) throws CommondbException, Exception {
        PersistenceHelper.called();
        APPLogger.getLogger().info(pBean.getClass().getName());
        APPLogger.getLogger().debug(pBean);
        EntityManager em = PersistenceHelper.getEntityManager();

        Object id = BeanManager.getBeanAttributeValue(pBean, "pk");
        if ((id instanceof History)) {
            HibernateBean bean = PersistenceHelper.manageHistory(pBean, id);
            pBean = em.merge(bean);
        } else {
            em.detach(pBean);
            PersistenceHelper.setModifyUser(pBean);
            PersistenceHelper.setLastupdate(pBean);
            PersistenceHelper.setCreationDate(pBean);
            if (pBean instanceof Cache) {
                // Limpia el cache de datos internamente obtiene el nombre real del bean sin considerar el paquete.
                CacheManager cm = CacheManager.getInstance();
                cm.clean(pBean.getClass().getName());
            }
            if ((pBean instanceof Log)) {
                HibernateBean oldbean = em.find(pBean.getClass(), id);
                if (oldbean != null) {
                    // Graba log de auditoria.
                    Audit.process(pBean, oldbean);
                }
            }
            pBean = em.merge(pBean);
        }
    }

    public static void persist(HibernateBean pBean) throws CommondbException, Exception {
        EntityManager em = PersistenceHelper.getEntityManager();
        PersistenceHelper.setIngressUser(pBean);
        em.persist(pBean);
        Audit.insert(pBean);
    }

    /**
     * Metodo que se encarga de caducar un registro que maneja historia.
     *
     * @param pBean Bean a caducar.
     * @throws CommondbException
     * @throws Exception
     */
    public static void expire(HibernateBean pBean) throws CommondbException, Exception {
        EntityManager em = PersistenceHelper.getEntityManager();
        Object id = BeanManager.getBeanAttributeValue(pBean, "pk");
        if ((id instanceof History)) {
            HibernateBean newbean = (HibernateBean) pBean.cloneMe();
            PersistenceHelper.getEntityManager().remove(pBean);;
            History pk = (History) BeanManager.getBeanAttributeValue(newbean, "pk");
            pk.setDateto(FormatDates.getInstance().getDataBaseTimestamp());
            em.persist(newbean);
        }
        if (pBean instanceof Cache) {
            // Limpia el cache de la tabla.
            CacheManager cm = CacheManager.getInstance();
            cm.clean(pBean.getClass().getName());
        }
    }

    /**
     * Caduca registro persistente.
     *
     * @param pBean Bean a caducar.
     * @throws CommonException
     * @throws Exception
     */
    public static void delete(HibernateBean pBean) throws CommondbException, Exception {
        EntityManager em = PersistenceHelper.getEntityManager();
        Object id = BeanManager.getBeanAttributeValue(pBean, "pk");
        if (id == null) {
            return;
        }
        if (pBean != null) {
            if ((id instanceof History)) {
                //Las siguientes 3 lineas corrigen el problema con los registros que manejan auditoria
                History pk = (History) BeanManager.getBeanAttributeValue(pBean, "pk");
                if (pk.getDateto() == null) {
                    pk.setDateto(FormatDates.getDefaultExpiryTimestamp());
                }
                HibernateBean newbean = (HibernateBean) pBean.cloneMe();
                PersistenceHelper.expireRecord(newbean, FormatDates.getInstance().getDataBaseTimestamp());
            }
            if (!em.contains(pBean)) {
                em.remove(em.find(pBean.getClass(), id));
            } else {
                em.remove(pBean);
            }
            if (pBean instanceof Log) {
                Audit.delete(pBean);
            }
        }
        if (pBean instanceof Cache) {
            // Limpia el cache de la tabla.
            CacheManager cm = CacheManager.getInstance();
            cm.clean(pBean.getClass().getName());
        }
    }

    /**
     * Metodo que se encarga del manejo de la historia de registros en la base,
     * si estos manejan date from date to.
     *
     * @param pBean Bena a almacenar en la base de datos.
     * @return HibernateBean
     * @throws Exception
     */
    private static HibernateBean manageHistory(HibernateBean pBean, Object pid) throws Exception {
        EntityManager em = PersistenceHelper.getEntityManager();
        Object id = pid;
        HibernateBean oldbean = null;
        HibernateBean newbean = pBean;
        if ((id instanceof History)) {
            History pk = (History) id;
            if (pk.getDateto() == null) {
                // Si es null y existe un registro en la base indica que se da mantenimiento sobre el mismo registro, en
                // este caso
                // se elimina de la base.
                PersistenceHelper.verifyBean(em, pBean, id);
                // pk.setDateto(null);
            }
            if (pk.getDateto() != null) {
                Object obj = ((AbstractDataTransport)pBean).get("ORIGINALBEAN");
                if(obj == null){
                    em.detach(pBean);
                    newbean = (HibernateBean) pBean.cloneMe();
                    oldbean = em.find(pBean.getClass(), id);
                    if(oldbean != null){
                        em.detach(oldbean);
                    }
                }else{
                    oldbean = (HibernateBean)obj;
                }

                id = BeanManager.getBeanAttributeValue(newbean, "pk");
                pk = (History) id;
                if (pk.getDateto().compareTo(FormatDates.getDefaultExpiryTimestamp()) < 0) {
                    return pBean;
                }
            }
            Timestamp t = FormatDates.getInstance().getDataBaseTimestamp();
            if ((pBean instanceof Cache) && (oldbean != null)) {
                // Limpia el cache de la tabla unicamente si esta dando mantenimiento a un registro.
                CacheManager cm = CacheManager.getInstance();
                cm.clean(pBean.getClass().getName());
            }
            if ((pBean instanceof Log)) {
                // Graba log de auditoria.
                if (oldbean != null) {
                    Audit.process(pBean, oldbean);
                } else {
                    Audit.insert(pBean);
                }

            }
            if ((oldbean != null) && !BeanManager.compareObject(pBean, oldbean)) {
                PersistenceHelper.expireRecord(oldbean, t);
                BeanManager.setBeanAttributeValue(newbean, "datefrom", t);
            }
            if (BeanManager.getBeanAttributeValue(newbean, "datefrom") == null) {
                BeanManager.setBeanAttributeValue(newbean, "datefrom", t);
            }
            BeanManager.setBeanAttributeValue(pk, "dateto", FormatDates.getDefaultExpiryTimestamp());
            PersistenceHelper.setpartition(pk, pk.getDateto());
            PersistenceHelper.setModifyUser(newbean);
        }
        return newbean;
    }

    /**
     * Si valor de dateto es null y existe un registro en la base indica que se
     * da mantenimiento sobre el mismo registro, en este caso se elimina el
     * registro de la base.
     *
     * @param em EntityManager utilizado en dml.
     * @param pBean Referencia al bean persistente.
     * @param id Pk del bean.
     * @throws Exception
     */
    private static void verifyBean(EntityManager em, HibernateBean pBean, Object id) throws Exception {
        try {
            History pk = (History) id;
            pk.setDateto(FormatDates.getDefaultExpiryTimestamp());
            HibernateBean oldbean = em.find(pBean.getClass(), id);
            if (oldbean != null) {
                em.detach(pBean);
                em.remove(oldbean);
            }
        } catch (Exception e) {
            // No hacer nada
        }

    }

    /**
     * Metodo que expira un registro en la base de datos.
     *
     * @param pOldBean Objeto que contiene el registro de una tabla a expirar.
     * @param pTimestamp Fecha con la cual se expira un registro.
     * @throws Exception
     */
    public static void expireRecord(HibernateBean pOldBean, Timestamp pTimestamp) throws Exception {
        EntityManager em = PersistenceHelper.getEntityManager();
        History pk = (History) BeanManager.getBeanAttributeValue(pOldBean, "pk");
        pk.setDateto(pTimestamp);
        PersistenceHelper.setpartition(pk, pTimestamp);
        em.persist(pOldBean);
    }

    /**
     * Metodo fija la particion en un registro, la particion es yyyymm del campo
     * dateto.
     *
     * @param pHistory Pk de un registro.
     * @param pTimestamp fecha con la cual se caduca un registro.
     * @throws Exception
     */
    private static void setpartition(History pHistory, Timestamp pTimestamp) throws Exception {
        try {
            BeanManager.setBeanAttributeValue(pHistory, "partition", FormatDates.getPartition(pTimestamp));
        } catch (Exception e1) {
        }
    }

    /**
     * Metodo que separa el objeto de la session de la base de datos.
     *
     * @param pBean Objeto a separar de la base de datos.
     * @throws Exception
     */
    public static void detatch(HibernateBean pBean) throws Exception {
        if(pBean != null){
            PersistenceHelper.called();
            EntityManager em = PersistenceHelper.getEntityManager();
            em.detach(pBean);
        }
    }

    /**
     * Fija el usuario de creacion de un registro.
     *
     * @param pBean Objeto a almacenar en la base de datos.
     * @throws Exception
     */
    public static void setIngressUser(HibernateBean pBean) throws Exception {
        try {
            BeanManager.setBeanAttributeValue(pBean, "ingressuser", SaveData.getSaveRequest().getUser());
        } catch (Exception e) {
            try {
                BeanManager.setBeanAttributeValue(pBean, "ingressusercode", SaveData.getSaveRequest().getUser());
            } catch (Exception e2) {
                // Si no existe el campo en el bean no hacer nada.
            }
        }
    }

    /**
     * Fija el usuario de creacion de un registro.
     *
     * @param pBean Objeto a almacenar en la base de datos.
     * @throws Exception
     */
    public static void setLastupdate(HibernateBean pBean) throws Exception {
        try {
            BeanManager.setBeanAttributeValue(pBean, "lastupdate", SaveData.getSaveRequest().get("accountingdate"));
        } catch (Exception e) {
            // Si no existe el campo en el bean no hacer nada.
        }
    }

    /**
     * Fija el fecha de admision de un registro.
     *
     * @param pBean Objeto a almacenar en la base de datos.
     * @throws Exception
     */
    public static void setCreationDate(HibernateBean pBean) throws Exception {
        try {
            if (BeanManager.getBeanAttributeValue(pBean, "creationdate") == null) {
                BeanManager.setBeanAttributeValue(pBean, "creationdate", SaveData.getSaveRequest().get("accountingdate"));
            }
        } catch (Exception e) {
            // Si no existe el campo en el bean no hacer nada.
        }
    }

    /**
     * Fija el usuario de creacion de un registro.
     *
     * @param pBean Objeto a almacenar en la base de datos.
     * @throws Exception
     */
    public static void setModifyUser(HibernateBean pBean) throws Exception {
        try {
            BeanManager.setBeanAttributeValue(pBean, "modifyuser", SaveData.getSaveRequest().getUser());
        } catch (Exception e) {
            try {
                BeanManager.setBeanAttributeValue(pBean, "modifyusercode", SaveData.getSaveRequest().getUser());
            } catch (Exception e2) {
                // Si no existe el campo en el bean no hacer nada.
            }
        }
    }

    public static Query prepareQuery(String pName, Integer pPage, Integer pRecords) throws Exception {
        Query q = PersistenceHelper.getEntityManager().createNamedQuery(pName);
        q.setFirstResult((pPage - 1) * pRecords);
        q.setMaxResults(pRecords);
        return q;
    }

    public static Query prepareQuery(String pName) throws Exception {
        return PersistenceHelper.getEntityManager().createNamedQuery(pName);
    }

    public static Query createQuery(String pJPQL) throws Exception {
        return PersistenceHelper.getEntityManager().createQuery(pJPQL);
    }

    public static Query createNativeQuery(String pSQL) throws Exception {
        return PersistenceHelper.getEntityManager().createNativeQuery(pSQL);
    }

    public static <T> TypedQuery<T> prepareQuery(String pName, Class<T> pType) throws Exception {
        return PersistenceHelper.getEntityManager().createNamedQuery(pName, pType);
    }

}
