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

import com.arrebol.taxiservicios.controller.catalog.*;
import com.arrebol.taxiservicios.controller.connection.ConnectionManager;
import com.arrebol.taxiservicios.controller.util.HibernateUtil;
import com.arrebol.taxiservicios.model.catalog.ClaveProductoServicio;
import com.arrebol.taxiservicios.model.catalog.ClaveUnidad;
import com.arrebol.taxiservicios.model.catalog.ExpenseIncomeCatalog;
import com.arrebol.taxiservicios.model.catalog.Location;
import com.arrebol.taxiservicios.model.core.User;
import com.arrebol.taxiservicios.model.enums.BasicType;
import com.arrebol.taxiservicios.model.enums.BoxType;
import com.arrebol.taxiservicios.model.enums.ExpenseCatalogType;
import com.arrebol.taxiservicios.model.enums.ExpenseIncomeType;
import java.io.Serializable;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.CriteriaUpdate;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
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;
import org.hibernate.query.NativeQuery;
import org.hibernate.query.Query;

/**
 *
 * @author Carlos Janitzio Zavala Lopez <janitzio.zavala@arrebol.com.mx>
 */
public class ExpenseIncomeCatalogController extends ConnectionManager implements Serializable {
    /**
     * Find stable small box by location
     *
     * @param location
     * @return
     */
    public List<ExpenseIncomeCatalog> findSExpenseIncomeCatalog(Location location) {
    logger.info("findExpenseIncomeCatalogBetweenDates");
    List<ExpenseIncomeCatalog> results = null;
    Transaction transaction = null;
    try {
        Session session = HibernateUtil.getSessionFactory().getCurrentSession();
        transaction = session.beginTransaction();
        CriteriaBuilder builder = session.getCriteriaBuilder();
        CriteriaQuery<ExpenseIncomeCatalog> query = builder.createQuery(ExpenseIncomeCatalog.class);
        Root<ExpenseIncomeCatalog> root = query.from(ExpenseIncomeCatalog.class);

        query.where(
            builder.and(
                builder.equal(root.get("active"), BasicType.ENEBLED),
                builder.equal(root.get("location"), location)
            )
        );
        
        query.orderBy(builder.asc(root.get("createdOn")));

        results = session.createQuery(query).getResultList();

        transaction.commit();

        logger.info("Expense Income Catalog list " + results.size());
    } catch (HibernateException e) {
        logger.error("Can not find Expense Income Catalog between dates", e);
        rollback(transaction);
    } catch (Exception e) {
        logger.error("Method findExpenseIncomeCatalogBetweenDates()", e);
        rollback(transaction);
    }
    return results;
}

    public List<ExpenseIncomeCatalog> findExpenseIncomeCatalogSmallBox() {
        logger.info("findExpenseIncomeCatalogBetweenDates");
        List<ExpenseIncomeCatalog> results = null;
        Transaction transaction = null;
        try {
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();
            CriteriaBuilder builder = session.getCriteriaBuilder();
            CriteriaQuery<ExpenseIncomeCatalog> query = builder.createQuery(ExpenseIncomeCatalog.class);
            Root<ExpenseIncomeCatalog> root = query.from(ExpenseIncomeCatalog.class);

            Predicate predicateActive = builder.equal(root.get("active"), BasicType.ENEBLED);
            
            Predicate predicateBox = builder.or(builder.equal(root.get("activeBox"), BoxType.SMALL),builder.equal(root.get("activeBox"), BoxType.BOTH));
            
            
            query.where(builder.and(predicateActive,predicateBox));
            query.orderBy(builder.asc(root.get("createdOn")));

            results = session.createQuery(query).getResultList();

            transaction.commit();

            logger.info("Expense Income Catalog list " + results.size());
        } catch (HibernateException e) {
            logger.error("Can not find Expense Income Catalog between dates", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method findExpenseIncomeCatalogBetweenDates()", e);
            rollback(transaction);
        }
        return results;
    }
    
    public List<ExpenseIncomeCatalog> findExpenseIncomeCatalogGeneralBox() {
        logger.info("findExpenseIncomeCatalogBetweenDates");
        List<ExpenseIncomeCatalog> results = null;
        Transaction transaction = null;
        try {
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();
            CriteriaBuilder builder = session.getCriteriaBuilder();
            CriteriaQuery<ExpenseIncomeCatalog> query = builder.createQuery(ExpenseIncomeCatalog.class);
            Root<ExpenseIncomeCatalog> root = query.from(ExpenseIncomeCatalog.class);

            Predicate predicateActive = builder.equal(root.get("active"), BasicType.ENEBLED);
            Predicate predicateExpenseType = builder.equal(root.get("expenseIncomeCatalogType"), ExpenseIncomeType.EARNING);
            Predicate predicateBox = builder.or(builder.equal(root.get("activeBox"), BoxType.GENERAL),builder.equal(root.get("activeBox"), BoxType.BOTH));
            
            
            query.where(builder.and(predicateActive,predicateExpenseType,predicateBox));
            query.orderBy(builder.asc(root.get("createdOn")));

            results = session.createQuery(query).getResultList();

            transaction.commit();

            logger.info("Expense Income Catalog list " + results.size());
        } catch (HibernateException e) {
            logger.error("Can not find Expense Income Catalog between dates", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method findExpenseIncomeCatalogBetweenDates()", e);
            rollback(transaction);
        }
        return results;
    }
    
    public List<ExpenseIncomeCatalog> findExpenseCatalogGeneralBox() {
        logger.info("findExpenseIncomeCatalogBetweenDates");
        List<ExpenseIncomeCatalog> results = null;
        Transaction transaction = null;
        try {
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();
            CriteriaBuilder builder = session.getCriteriaBuilder();
            CriteriaQuery<ExpenseIncomeCatalog> query = builder.createQuery(ExpenseIncomeCatalog.class);
            Root<ExpenseIncomeCatalog> root = query.from(ExpenseIncomeCatalog.class);

            Predicate predicateActive = builder.equal(root.get("active"), BasicType.ENEBLED);
            Predicate predicateExpenseType = builder.equal(root.get("expenseIncomeCatalogType"), ExpenseIncomeType.EXPENSE);
            Predicate predicateBox = builder.or(builder.equal(root.get("activeBox"), BoxType.GENERAL),builder.equal(root.get("activeBox"), BoxType.BOTH));
            
            
            query.where(builder.and(predicateActive,predicateExpenseType,predicateBox));
            query.orderBy(builder.asc(root.get("createdOn")));

            results = session.createQuery(query).getResultList();

            transaction.commit();

            logger.info("Expense Income Catalog list " + results.size());
        } catch (HibernateException e) {
            logger.error("Can not find Expense Income Catalog between dates", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method findExpenseIncomeCatalogBetweenDates()", e);
            rollback(transaction);
        }
        return results;
    }

    /**
     * Update active status (ENEBLED/DISABLED) of stable small box by ID.
     *
     * @param id Primary key to be updated.
     * @param status Status to be updated (ENEBLED/DISABLED).
     * @param lastUpdatedBy User to apply update.
     * @return
     */
    
    public void delete(ExpenseIncomeCatalog expense,String userId) {

        Transaction transaction = null;
        try {
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();
            CriteriaBuilder builder = session.getCriteriaBuilder();

            if (expense.getId()!= null) {            
                
                CriteriaUpdate<ExpenseIncomeCatalog> update = builder.createCriteriaUpdate(ExpenseIncomeCatalog.class);
                Root<ExpenseIncomeCatalog> rootPerson = update.from(ExpenseIncomeCatalog.class);

                update.set(("active"), BasicType.DISABLED);
                update.set("lastUpdatedBy", new User(userId, ""));
                update.set("lastUpdatedOn", new Date());

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

                int total = session.createQuery(update).executeUpdate();
                
                if (1 == total) {
                    logger.info("The expense was deleted - " + expense.getId());
                    transaction.commit();

                } else {
                    logger.error("Expense can not be updated " + expense.getId());
                    transaction.rollback();
                }

            }
        } catch (HibernateException e) {
            logger.error("The expense can not be deleted - " + expense, e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method  delete(" + expense + ")", e);
            rollback(transaction);
        }
    }
    
    public void saveExpense(ExpenseIncomeCatalog expense, String userId) {        
        Transaction transaction = null;        
        try {     
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();               
            transaction = session.beginTransaction();
            CriteriaBuilder builder = session.getCriteriaBuilder();
            
            if(expense.getId()!=null){
                CriteriaUpdate<ExpenseIncomeCatalog> update = builder.createCriteriaUpdate(ExpenseIncomeCatalog.class);
                Root<ExpenseIncomeCatalog> root = update.from(ExpenseIncomeCatalog.class);                
                update.set("name", expense.getName());
                update.set("expenseIncomeCatalogType", expense.getExpenseIncomeCatalogType());
                update.set("activePaymentCustomer", expense.getActivePaymentCustomer());
                update.set("activeBox", expense.getActiveBox());
                update.set("claveUnidad", expense.getClaveUnidad());
                update.set("claveProductoServicio", expense.getClaveProductoServicio());
                update.set("expenseCatalogType", expense.getExpenseCatalogType());
                update.set("lastUpdatedBy", new User(userId, ""));
                update.set("lastUpdatedOn", new Date());                
                update.where(builder.equal(root.get("id"), expense.getId()));
                int total = session.createQuery(update).executeUpdate();
                if (1 == total) {
                    logger.info("The expense was updated - " + expense.getId());
                } else {
                    logger.error("Expense can not be updated " + expense.getId());
                    transaction.rollback();
                }
            }else{
                expense.setId(UUID.randomUUID().toString());
                expense.setName(expense.getName());
                expense.setExpenseIncomeCatalogType(expense.getExpenseIncomeCatalogType());
                expense.setActivePaymentCustomer(expense.getActivePaymentCustomer());
                expense.setActiveBox(expense.getActiveBox());
                expense.setActive(BasicType.ENEBLED);
                expense.setClaveUnidad(expense.getClaveUnidad());
                expense.setClaveProductoServicio(expense.getClaveProductoServicio());
                expense.setExpenseCatalogType(expense.getExpenseCatalogType());
                expense.setCreatedBy(new User(userId, ""));
                expense.setCreatedOn(new Date());
                session.save(expense);
                logger.info("The expense was saved - " + expense);
            }
            transaction.commit();
        } catch (HibernateException e) {
            logger.error("The expense can not be saved - " + expense, e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method saveEventType(" + expense + ")", e);
            rollback(transaction);
        }
    }

    /**
     * Find an entry that match with date (dd/mm/yyyy).
     *
     * @param date
     * @param locationId
     * @return True if exist a coincidence otherwise false.
     */
    public boolean existExpenseIncomeCatalogEqToDate(Date date, String locationId) {
        logger.info("existExpenseIncomeCatalogEqToDate");

        boolean success = false;
        Transaction transaction = null;

        try {
            Session session = HibernateUtil.getSessionFactory().getCurrentSession();
            transaction = session.beginTransaction();
            String queryStr = "SELECT COUNT(ssb.id) FROM ExpenseIncomeCatalog ssb WHERE DATE(ssb.createdOn) = DATE(:date) AND ssb.activeStatus = 'ENEBLED' AND location = :location";

            Query query = session.createQuery(queryStr);
            query.setParameter("date", date);
            query.setParameter("location", new Location(locationId));
            success = (Long) (query.getSingleResult()) > 0;

            transaction.commit();
        } catch (HibernateException e) {
            logger.error("Can not load the stable small box", e);
            rollback(transaction);
        } catch (Exception e) {
            logger.error("Method existExpenseIncomeCatalogEqToDate()", e);
            rollback(transaction);
        }
        return success;
    }


    private static final long serialVersionUID = -3049612223190797349L;
    final Logger logger = LogManager.getLogger(ExpenseIncomeCatalogController.class);

}
