/*
 * Arrebol Consultancy copyright.
 * 
 * This code belongs to Arrebol Consultancy
 * its use, redistribution or modification are prohibited 
 * without written authorization from Arrebol Consultancy.
 */
package com.arrebol.taxiservicios.controller.util;

import java.util.ArrayList;
import java.util.List;
import javax.persistence.Tuple;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.query.Query;
import org.hibernate.service.ServiceRegistry;

/**
 *
 * @author Carlos Janitzio Zavala Lopez <janitzio.zavala@arrebol.com.mx>
 * @param <T>
 */
public class DAOHibernateRepository<T> {

    static final String HIBERNATE_CFG_XML = "taxi.cfg.xml";

    final static ServiceRegistry SERVICE_REGISTRY = new StandardServiceRegistryBuilder().configure(HIBERNATE_CFG_XML).build();

    final static Metadata METADATA = new MetadataSources(SERVICE_REGISTRY).getMetadataBuilder().build();

    public final static SessionFactory SESSION_FACTORY = METADATA.getSessionFactoryBuilder().build();

    /**
     *
     * @param entity
     * @return
     */
    public boolean saveEntity(T entity) {
        boolean success;

        Session session = null;
        Transaction transaction = null;
        try {
            session = SESSION_FACTORY.openSession();
            transaction = session.beginTransaction();

            session.save(entity);
            transaction.commit();

            success = true;
        } catch (Exception e) {
            logger.error("saveEntity: " + entity, e);
            if (null != transaction) {
                transaction.rollback();
            }
            success = false;
        } finally {
            if (null != session) {
                session.clear();
                session.close();
            }
        }
        return success;
    }

    /**
     *
     * @param namedQuery
     * @param parameters
     * @return
     */
    public boolean updateEntityFromNamedQuery(String namedQuery, List<ModelParameter> parameters) {
        boolean success;
        Session session = null;
        Transaction transaction = null;
        try {
            session = SESSION_FACTORY.openSession();
            transaction = session.beginTransaction();

            Query query = session.createNamedQuery(namedQuery);

            if (null != parameters && !parameters.isEmpty()) {
                parameters.forEach((param) -> {
                    query.setParameter(param.getParameter(), param.getValue());
                });
            }

            query.executeUpdate();
            transaction.commit();

            success = true;
        } catch (Exception e) {
            logger.error("updateEntityFromNamedQuery from named query: " + namedQuery, e);
            if (null != transaction) {
                transaction.rollback();
            }

            success = false;
        } finally {
            if (null != session) {
                session.clear();
                session.close();
            }
        }
        return success;
    }

    /**
     *
     * @param hbmQuery
     * @param parameters
     * @return
     */
    public long lazyLoadingEntityCount(String hbmQuery, List<ModelParameter> parameters) {
        Long total;
        Session session = null;
        Transaction transaction = null;
        try {
            session = SESSION_FACTORY.openSession();
            transaction = session.beginTransaction();
            Query query = session.createQuery(hbmQuery, Long.class);
            if (null != parameters) {
                parameters.forEach(param -> {
                    query.setParameter(param.getParameter(), param.getValue());
                });
            }
            total = (Long) query.getSingleResult();
            transaction.commit();
        } catch (Exception e) {
            logger.error("lazyLoadingEntityCount from hbmQuery: " + hbmQuery, e);
            if (null != transaction) {
                transaction.rollback();
            }
            total = 0l;
        } finally {
            if (null != session) {
                session.clear();
                session.close();
            }
        }
        return total;
    }

    /**
     *
     * @param clazz
     * @param hbmQuery
     * @param parameters
     * @param first
     * @param pageSize
     * @return
     */
    public List<T> lazyLoadingEntityList(Class clazz, String hbmQuery, List<ModelParameter> parameters, int first, int pageSize) {
        List<T> results;
        Session session = null;
        Transaction transaction = null;
        try {
            session = SESSION_FACTORY.openSession();
            transaction = session.beginTransaction();
            Query query = session.createQuery(hbmQuery, clazz);
            if (null != parameters) {
                parameters.forEach(param -> {
                    query.setParameter(param.getParameter(), param.getValue());
                });
            }
            query.setFirstResult(first);
            query.setMaxResults(pageSize);

            results = query.getResultList();
            transaction.commit();
        } catch (Exception e) {
            logger.error("lazyLoadingEntityList from class: " + clazz.getName(), e);
            if (null != transaction) {
                transaction.rollback();
            }
            results = new ArrayList<>();
        } finally {
            if (null != session) {
                session.clear();
                session.close();
            }
        }
        return results;
    }

    /**
     *
     * @param namedQuery
     * @param parameters
     * @return
     */
    public List<Tuple> findAllFromNamedQuery(String namedQuery, List<ModelParameter> parameters) {
        List<Tuple> results;
        Session session = null;
        Transaction transaction = null;
        try {
            session = SESSION_FACTORY.openSession();
            transaction = session.beginTransaction();

            Query query = session.createNamedQuery(namedQuery, Tuple.class);

            if (null != parameters) {
                parameters.forEach(param -> {
                    query.setParameter(param.getParameter(), param.getValue());
                });
            }

            results = query.getResultList();
            transaction.commit();
        } catch (Exception e) {
            logger.error("find All From Named Query from named query: " + namedQuery, e);
            if (null != transaction) {
                transaction.rollback();
            }
            results = new ArrayList<>();
        } finally {
            if (null != session) {
                session.clear();
                session.close();
            }
        }
        return results;
    }

    /**
     *
     * @param hbmQuery
     * @param parameters
     * @return
     */
    public List<Tuple> findAllEntity(String hbmQuery, List<ModelParameter> parameters) {
        List<Tuple> results;
        Session session = null;
        Transaction transaction = null;

        try {
            session = SESSION_FACTORY.openSession();
            transaction = session.beginTransaction();
            Query query = session.createQuery(hbmQuery, Tuple.class);
            if (null != parameters) {
                parameters.forEach(param -> {
                    query.setParameter(param.getParameter(), param.getValue());
                });
            }

            results = query.getResultList();
            transaction.commit();
        } catch (Exception e) {
            logger.error("findAllEntity from hbmQuery: " + hbmQuery, e);
            if (null != transaction) {
                transaction.rollback();
            }
            results = new ArrayList<>();
        } finally {
            if (null != session) {
                session.clear();
                session.close();
            }
        }
        return results;
    }

    final Logger logger = LogManager.getLogger(getClass());
}
