/*
 * 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.top;

import com.arrebol.taxiservicios.controller.connection.ConnectionManager;
import com.arrebol.taxiservicios.controller.util.HibernateUtil;
import com.arrebol.taxiservicios.model.core.Address;
import com.arrebol.taxiservicios.model.core.ContactNumber;
import com.arrebol.taxiservicios.model.core.Person;
import java.io.Serializable;
import java.util.List;
import javax.enterprise.context.RequestScoped;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaUpdate;
import javax.persistence.criteria.Root;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;

/**
 *
 * @author Carlos Janitzio Zavala Lopez <janitzio.zavala@arrebol.com.mx>
 */
@RequestScoped
public class ProfileServiceImpl extends ConnectionManager implements ProfileService, Serializable {

    @Override
    public Person getEmployeeById(String employeeId) {
        logger.info("getEmployeeById");

        Person employee = null;
        Transaction transaction = null;
        try {
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();

            employee = session.get(Person.class, employeeId);

            transaction.commit();
            logger.info("Employee " + employee);
        } catch (HibernateException e) {
            logger.error("Employee cannot be loaded " + employeeId, e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method getEmployeeById(" + employeeId + ") ", e);
            rollback(transaction);
        }
        return employee;
    }

    @Override
    public boolean updatePersonLocationById(Person person) {
        logger.info("updatePersonLocationById");

        boolean success = false;
        Transaction transaction = null;
        try {
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();

            CriteriaBuilder builder = session.getCriteriaBuilder();
            CriteriaUpdate<Person> update = builder.createCriteriaUpdate(Person.class);
            Root<Person> rootPerson = update.from(Person.class);

            update.set("location", person.getLocation());

            update.where(builder.equal(rootPerson.get("id"), person.getId()));

            int total = session.createQuery(update).executeUpdate();

            if (1 == total) {
                logger.info("Person location updated: " + person);
                transaction.commit();

                success = true;
            } else {
                logger.error("Person location can not be updated " + person);
                rollback(transaction);
            }
        } catch (HibernateException e) {
            logger.error("Person location cannot be updated " + person, e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method updatePersonLocationById(" + person + ") ", e);
            rollback(transaction);
        }
        return success;
    }

    @Override
    public boolean updatePersonById(Person person) {
        logger.info("updateEmployeeById");

        boolean success = false;
        Transaction transaction = null;
        try {
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();

            CriteriaBuilder builder = session.getCriteriaBuilder();
            CriteriaUpdate<Person> update = builder.createCriteriaUpdate(Person.class);
            Root<Person> rootPerson = update.from(Person.class);

            update.set("firstName", person.getFirstName());
            update.set("secondName", person.getSecondName());
            update.set("lastName", person.getLastName());
            update.set("middleName", person.getMiddleName());
            update.set("birthdate", person.getBirthdate());
            update.set("lastUpdatedBy", person.getLastUpdatedBy());
            update.set("lastUpdatedOn", person.getLastUpdatedOn());
            update.set("location", person.getLocation());

            update.where(builder.equal(rootPerson.get("id"), person.getId()));

            int total = session.createQuery(update).executeUpdate();

            if (1 == total) {
                logger.info("Person updated: " + person);
                transaction.commit();

                success = true;
            } else {
                logger.error("Person can not be updated " + person);
                rollback(transaction);
            }
        } catch (HibernateException e) {
            logger.error("Person cannot be updated " + person, e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method updatePersonById(" + person + ") ", e);
            rollback(transaction);
        }
        return success;
    }

    @Override
    public boolean updateEmployeeContactDetailsById(Person person, List<ContactNumber> phones) {
        logger.info("updateEmployeeContactDetailsById");

        boolean success = false;
        Transaction transaction = null;
        try {
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();

            CriteriaBuilder builder = session.getCriteriaBuilder();
            CriteriaUpdate<Person> update = builder.createCriteriaUpdate(Person.class);
            Root<Person> rootEmployee = update.from(Person.class);

            update.set("rfc", person.getRfc());
            update.set("curp", person.getCurp());
            update.set("mail", person.getMail());
            update.set("lastUpdatedBy", person.getLastUpdatedBy());
            update.set("lastUpdatedOn", person.getLastUpdatedOn());

            update.where(builder.equal(rootEmployee.get("id"), person.getId()));

            int total = session.createQuery(update).executeUpdate();

            if (1 == total) {
                logger.info("Contact details updated");
            }

            phones.forEach((phone) -> {
                session.saveOrUpdate(phone);
            });

            transaction.commit();

            success = true;

            logger.info("Person contact details updated " + person);
        } catch (HibernateException e) {
            logger.error("Person contact details cannot be updated " + person, e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method updateEmployeeContactDetailsById(" + person + ") ", e);
            rollback(transaction);
        }
        return success;
    }

    @Override
    public boolean saveOrUpdateAddress(Address address) {
        logger.info("saveOrUpdateAddress");

        boolean success = false;
        Transaction transaction = null;
        try {
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();

            session.saveOrUpdate(address);
            transaction.commit();

            success = true;

            logger.info("Address updated " + address);
        } catch (HibernateException e) {
            logger.error("Address cannot be updated " + address, e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method saveOrUpdateAddress(" + address + ") ", e);
            rollback(transaction);
        }
        return success;
    }

    @Override
    public boolean updateAvatar(String employeeId, String avatar) {
        logger.info("updateAvatar");

        boolean success = false;
        Transaction transaction = null;
        try {
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();

            CriteriaBuilder builder = session.getCriteriaBuilder();
            CriteriaUpdate<Person> update = builder.createCriteriaUpdate(Person.class);
            Root<Person> root = update.from(Person.class);

            update.set(root.get("avatar"), avatar);
            update.where(builder.equal(root.get("id"), employeeId));

            int total = session.createQuery(update).executeUpdate();

            if (1 == total) {
                transaction.commit();
                logger.info("Avatar was updated ");

                success = true;
            } else {
                rollback(transaction);
            }
        } catch (HibernateException e) {
            logger.error("Avatar cannot be updated", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method updateAvatar(" + employeeId + ", " + avatar + ")", e);
            rollback(transaction);
        }
        return success;
    }
    
    private static final long serialVersionUID = 7989294279925727197L;
    final Logger logger = LogManager.getLogger(getClass());
}
