package org.academiadecodigo.enuminatti.hibernatebootstrap;

import javax.persistence.*;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;

/**
 * MIT License
 * (c) 2017 Ricardo Constantino
 */

public class SaveUtil<T> {
    private EntityManagerFactory emf;

    public SaveUtil() {
        this.emf = Persistence.createEntityManagerFactory("test");
    }

    public SaveUtil(EntityManagerFactory emf) {
        this.emf = emf;
    }

    public T save(T o) {
        EntityManager em = emf.createEntityManager();

        try {
            em.getTransaction().begin();

            em.persist(o);

            em.getTransaction().commit();
        } catch (RollbackException e) {
            em.getTransaction().rollback();
        } finally {
            if (em != null) {
                em.close();
            }
        }
        return o;
    }

    public T fetch(Class<? extends T> objectClass, Integer id) {
        EntityManager em = emf.createEntityManager();
        T fetched = null;

        try {
            em.getTransaction().begin();

            fetched = em.find(objectClass, id);

            em.getTransaction().commit();
        } catch (RollbackException e) {
            em.getTransaction().rollback();
        } finally {
            if (em != null) {
                em.close();
            }
        }
        return fetched;
    }

    public void close() {
        emf.close();
    }

    public T edit(T o) {
        EntityManager em = emf.createEntityManager();
        T saved = null;

        try {
            em.getTransaction().begin();

            saved = em.merge(o);

            em.getTransaction().commit();
        } catch (RollbackException e) {
            em.getTransaction().rollback();
        } finally {
            if (em != null) {
                em.close();
            }
        }

        return saved;
    }

    public T findByName(Class<T> objectClass, String name) {
        EntityManager em = emf.createEntityManager();

        try {
            CriteriaBuilder builder = em.getCriteriaBuilder();

            CriteriaQuery<T> criteriaQuery = builder.createQuery(objectClass);

            Root<T> root = criteriaQuery.from(objectClass);

            criteriaQuery.select(root);

            criteriaQuery.where(builder.equal(root.get("name"), name));

            return em.createQuery(criteriaQuery).getSingleResult();
        } catch (NoResultException e) {
            return null;
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

}
