/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.rjconsultores.ventaboletos.dao.hibernate;

import java.util.Date;
import java.util.List;

import org.apache.commons.lang.math.NumberUtils;
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Disjunction;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import com.rjconsultores.ventaboletos.dao.EsquemaCorridaDAO;
import com.rjconsultores.ventaboletos.entidad.ClaseServicio;
import com.rjconsultores.ventaboletos.entidad.Empresa;
import com.rjconsultores.ventaboletos.entidad.EsquemaCorrida;
import com.rjconsultores.ventaboletos.entidad.EsquemaOperacional;
import com.rjconsultores.ventaboletos.entidad.Marca;
import com.rjconsultores.ventaboletos.entidad.RolOperativo;
import com.rjconsultores.ventaboletos.entidad.Ruta;
import com.rjconsultores.ventaboletos.entidad.Tramo;
import com.rjconsultores.ventaboletos.exception.BusinessException;

/**
 * 
 * @author Rafius
 */
@Repository("esquemaCorridaDAO")
public class EsquemaCorridaHibernateDAO extends GenericHibernateDAO<EsquemaCorrida, Integer> implements EsquemaCorridaDAO {

	@Autowired
	public EsquemaCorridaHibernateDAO(
			@Qualifier("sessionFactory") SessionFactory factory) {
		setSessionFactory(factory);
	}

	@Override
	public List<EsquemaCorrida> obtenerTodos() {
		Criteria c = getSession().createCriteria(getPersistentClass());
		c.add(Restrictions.eq(ACTIVO, Boolean.TRUE));

		return c.list();
	}

	@Override
	public List<EsquemaCorrida> buscarPorEmpresaCorrida(Empresa empresa) {
		StringBuilder sb = new StringBuilder();
		sb.append("from EsquemaCorrida ec where ec.empresa.empresaId= :empresaId and activo = 1");

		Query qry = getSession().createQuery(sb.toString());
		qry.setInteger("empresaId", empresa.getEmpresaId());

		return qry.list();
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public List<EsquemaCorrida> buscarPorEmpresaCorridaAtiva(Empresa empresa, Date dataGeracaoInicial, Date dataGeracaoFinal) {
		StringBuilder sb = new StringBuilder();
		sb.append("from EsquemaCorrida ec where ec.empresa.empresaId= :empresaId and activo = 1");
		sb.append("  and (ec.indCorridaDesativada is null or ec.indCorridaDesativada = 0) ");
		sb.append("  and ( :dataGeracaoInicial between ec.esquemaOperacional.fecniciovigencia and ec.esquemaOperacional.fecfinvigencia  ");
		sb.append(" 	or :dataGeracaoFinal   between ec.esquemaOperacional.fecniciovigencia and ec.esquemaOperacional.fecfinvigencia )");

		Query qry = getSession().createQuery(sb.toString());
		qry.setInteger("empresaId", empresa.getEmpresaId());
		qry.setDate("dataGeracaoInicial", dataGeracaoInicial);
		qry.setDate("dataGeracaoFinal", dataGeracaoFinal);

		return qry.list();
	}

	@Override
	public List<EsquemaCorrida> buscarPorEsquemaOperacional(
			EsquemaOperacional eo) {
		Criteria c = getSession().createCriteria(getPersistentClass());

		c.add(Restrictions.eq("esquemaOperacional", eo));
		c.add(Restrictions.eq(ACTIVO, Boolean.TRUE));

		return c.list();
	}

	@Override
	public EsquemaCorrida obtenerByEsquemaCorrida(
			Integer ec) {
		Criteria c = getSession().createCriteria(getPersistentClass());

		c.add(Restrictions.eq("numCorrida", ec));
		c.add(Restrictions.eq(ACTIVO, Boolean.TRUE));

		List result = c.list();
		if (!result.isEmpty()) {
			return (EsquemaCorrida) result.get(NumberUtils.INTEGER_ZERO);
		}
		return null;
	}

	@Override
	public List<EsquemaCorrida> buscar(Marca marca, RolOperativo rolOperativo,
			Ruta ruta, ClaseServicio claseServicio) {
		Criteria c = getSession().createCriteria(getPersistentClass());
		c.add(Restrictions.eq(ACTIVO, Boolean.TRUE));

		c.add(Restrictions.eq("ruta", ruta));
		c.add(Restrictions.eq("marca", marca));
		c.add(Restrictions.eq("claseServicio", claseServicio));
		c.add(Restrictions.eq("rolOperativo", rolOperativo));

		return c.list();
	}
	
	@Override
	public List<EsquemaCorrida> buscarPorRuta(Ruta ruta) {
		Criteria c = getSession().createCriteria(getPersistentClass());
		c.add(Restrictions.eq(ACTIVO, Boolean.TRUE));

		c.add(Restrictions.eq("ruta", ruta));

		return c.list();
	}

	@Override
	public boolean esHijoRebote(EsquemaCorrida esquemaCorrida) {
		Criteria c = makeCriteria();
		c.setProjection(Projections.rowCount());
		c.add(Restrictions.eq(ACTIVO, Boolean.TRUE));
		c.add(Restrictions.eq("esquemaCorridaRebote", esquemaCorrida));

		Long cant = HibernateFix.count(c.list());

		return (cant > 0);
	}
	
	/**
	 * Buscar corrida, a partir do HijoRebote
	 * 
	 * @param esquemaCorrida
	 * @return
	 */
	@SuppressWarnings("unchecked")
	@Override
	public EsquemaCorrida buscarEsquemaPeloHijoRebote(EsquemaCorrida esquemaCorrida) {
		Criteria c = makeCriteria();
		c.add(Restrictions.eq(ACTIVO, Boolean.TRUE));
		c.add(Restrictions.eq("esquemaCorridaRebote", esquemaCorrida.getNumCorrida()));

		List<EsquemaCorrida> primeiroPiso = c.list();
		
		if(primeiroPiso != null && !primeiroPiso.isEmpty()) {
			return primeiroPiso.get(0);
		}
		
		return null;
	}

	/**
	 * Indica se o esquema é o indicado como segundo piso nas configuações de doble piso
	 * 
	 * @param esquemaCorrida
	 * @return
	 */
	@Override
	public boolean esSegundoPiso(EsquemaCorrida esquemaCorrida) {
		Criteria c = makeCriteria();
		c.setProjection(Projections.rowCount());
		c.add(Restrictions.eq(ACTIVO, Boolean.TRUE));
		c.add(Restrictions.eq("numCorridaPisoExtra", esquemaCorrida.getNumCorrida()));

		Long cant = HibernateFix.count(c.list());

		return (cant > 0);
	}
	
	/**
	 * Indica se o esquema é o indicado como terceiro piso nas configuações de doble piso
	 * 
	 * @param esquemaCorrida
	 * @return
	 */
	@Override
	public boolean esTerceiroPiso(EsquemaCorrida esquemaCorrida) {
		Criteria c = makeCriteria();
		c.setProjection(Projections.rowCount());
		c.add(Restrictions.eq(ACTIVO, Boolean.TRUE));
		c.add(Restrictions.eq("numCorridaPisoExtra2", esquemaCorrida.getNumCorrida()));

		Long cant = HibernateFix.count(c.list());

		return (cant > 0);
	}
	
	/**
	 * Buscar corrida primeiro piso, a partir do segundo
	 * 
	 * @param esquemaCorrida
	 * @return
	 */
	@SuppressWarnings("unchecked")
	@Override
	public EsquemaCorrida buscarPrimeiroPisoPeloSegundo(EsquemaCorrida esquemaCorrida) {
		Criteria c = makeCriteria();
		c.add(Restrictions.eq(ACTIVO, Boolean.TRUE));
		c.add(Restrictions.eq("numCorridaPisoExtra", esquemaCorrida.getNumCorrida()));

		List<EsquemaCorrida> primeiroPiso = c.list();
		
		if(primeiroPiso != null && !primeiroPiso.isEmpty()) {
			return primeiroPiso.get(0);
		}
		
		return null;
	}
	
	/**
	 * Buscar corrida primeiro piso, a partir do segundo
	 * 
	 * @param esquemaCorrida
	 * @return
	 */
	@SuppressWarnings("unchecked")
	@Override
	public EsquemaCorrida buscarPrimeiroPisoPeloTerceiro(EsquemaCorrida esquemaCorrida) {
		Criteria c = makeCriteria();
		c.add(Restrictions.eq(ACTIVO, Boolean.TRUE));
		c.add(Restrictions.eq("numCorridaPisoExtra2", esquemaCorrida.getNumCorrida()));

		List<EsquemaCorrida> primeiroPiso = c.list();
		
		if(primeiroPiso != null && !primeiroPiso.isEmpty()) {
			return primeiroPiso.get(0);
		}
		
		return null;
	}

	@Override
	public List<EsquemaCorrida> buscaDentroVigencia(Date dataGeracao) {
		Criteria c = makeCriteria();
		c.add(Restrictions.eq(ACTIVO, Boolean.TRUE));

		Criteria cEsquemaOperacional = c.createCriteria("esquemaOperacional");
		cEsquemaOperacional.add(Restrictions.le("fecniciovigencia", dataGeracao));
		cEsquemaOperacional.add(Restrictions.ge("fecfinvigencia", dataGeracao));
		cEsquemaOperacional.add(Restrictions.eq(ACTIVO, Boolean.TRUE));

		return c.list();
	}

	@Override
	public List<EsquemaCorrida> buscaDentroVigenciaQtdeDiasNull(Date dataGeracao) {
		Criteria c = makeCriteria();
		c.add(Restrictions.eq(ACTIVO, Boolean.TRUE));
		c.add(Restrictions.isNull("cantDiasGeneracion"));

		Criteria cEsquemaOperacional = c.createCriteria("esquemaOperacional");
		cEsquemaOperacional.add(Restrictions.le("fecniciovigencia", dataGeracao));
		cEsquemaOperacional.add(Restrictions.ge("fecfinvigencia", dataGeracao));
		cEsquemaOperacional.add(Restrictions.eq(ACTIVO, Boolean.TRUE));

		return c.list();
	}

	@Override
	public boolean buscarEsquemaCorridaExisteTramo(Tramo tramo) {
		Criteria c = makeCriteria();
		c.add(Restrictions.eq(ACTIVO, Boolean.TRUE));

		Criteria cEsquemaOperacional = c.createCriteria("esquemaTramoList");
		cEsquemaOperacional.add(Restrictions.eq("tramo", tramo));

		if (c.list().isEmpty()) {
			return false;
		} else {
			return true;
		}
	}

	@Override
	public List<Integer> existe(Ruta ruta, Integer paradaId) {

		Criteria c = makeCriteria();
		c.add(Restrictions.eq("ruta", ruta));
		c.add(Restrictions.eq(ACTIVO, Boolean.TRUE));

		Criteria cEsquemaTramo = c.createCriteria("esquemaTramoList");
		cEsquemaTramo.add(Restrictions.eq(ACTIVO, Boolean.TRUE));

		Criteria cTramo = cEsquemaTramo.createCriteria("tramo");

		Disjunction or = Restrictions.disjunction();
		or.add(Restrictions.eq("origem.paradaId", paradaId));
		or.add(Restrictions.eq("destino.paradaId", paradaId));

		cTramo.add(or);

		c.setProjection(Projections.property("esquemacorridaId"));

		return c.list();
	}

	@Override
	public EsquemaCorrida buscaEsquemaPorRuta(Ruta ruta) {
		List<EsquemaCorrida> lsEsquemaCorrida;
		Criteria c = makeCriteria();
		c.add(Restrictions.eq("ruta", ruta));
		c.add(Restrictions.eq(ACTIVO, Boolean.TRUE));
		c.setFirstResult(0);
		c.setMaxResults(1);
		c.createCriteria("esquemaOperacional").add(Restrictions.ge("fecfinvigencia", new Date()));

		lsEsquemaCorrida = c.list();
		return lsEsquemaCorrida.isEmpty() ? null : lsEsquemaCorrida.get(0);
	}
	
	@Override
	public EsquemaCorrida buscaEsquemaPorRutaSemVigencia(Integer rutaId, Integer numCorrida) {
		List<EsquemaCorrida> lsEsquemaCorrida;
		Criteria c = makeCriteria();
		c.add(Restrictions.eq("ruta.rutaId", rutaId));
		c.add(Restrictions.eq(ACTIVO, Boolean.TRUE));
		c.add(Restrictions.eq("numCorrida", numCorrida));
		c.setFirstResult(0);
		c.setMaxResults(1);
		
		lsEsquemaCorrida = c.list();
		return lsEsquemaCorrida.isEmpty() ? null : lsEsquemaCorrida.get(0);
	}

	@Override
	public boolean buscarNumCorrida(Integer numCorrida, Integer numCorridaPisoExtra, boolean isDoublePiso) {
		Criteria c = getSession().createCriteria(getPersistentClass());
		c.add(Restrictions.eq(ACTIVO, Boolean.TRUE));
		Disjunction or = Restrictions.disjunction();

		if (isDoublePiso) {
			or.add(Restrictions.or(Restrictions.eq("numCorridaPisoExtra", numCorridaPisoExtra), Restrictions.eq("numCorrida", numCorrida)));
			or.add(Restrictions.eq("numCorrida", numCorridaPisoExtra));
		} else {
			or.add(Restrictions.eq("numCorrida", numCorrida));
		}

		c.add(or);

		if (c.list().isEmpty()) {
			return false;
		} else {
			return true;
		}
	}

	@Override
	public EsquemaCorrida buscarPeloNumCorrida(Integer numCorrida) {

		Criteria c = getSession().createCriteria(getPersistentClass());
		c.add(Restrictions.eq(ACTIVO, Boolean.TRUE));
		c.add(Restrictions.eq("numCorrida", numCorrida));

		return (EsquemaCorrida) c.uniqueResult();
	}

	@Override
	public List<EsquemaCorrida> buscaDentroVigenciaQtdeDiasNotNull(Date dataGeracao) {
		Criteria c = makeCriteria();
		c.add(Restrictions.eq(ACTIVO, Boolean.TRUE));
		c.add(Restrictions.isNotNull("cantDiasGeneracion"));

		Criteria cEsquemaOperacional = c.createCriteria("esquemaOperacional");
		cEsquemaOperacional.add(Restrictions.ge("fecfinvigencia", dataGeracao));
		cEsquemaOperacional.add(Restrictions.eq(ACTIVO, Boolean.TRUE));

		return c.list();
	}

	@Override
	@Transactional(rollbackFor = { BusinessException.class })
	public Integer atualizaServicoIntegracaoTotvs(Marca marca, Integer numcorrida) throws BusinessException {

		// update caja set integradototvs = 0 where PUNTOVENTA_ID = 269 and FECHORVENTA >= '30/03/2018' and FECHORVENTA <= '01/04/2018';
		StringBuilder sb = new StringBuilder();
		sb.append("  update esquema_corrida set integradototvs = 0 ");
		sb.append(" where NUMCORRIDA = :numcorrida ");
		if (marca != null) {
			sb.append(" and  MARCA_ID = :marcaId  ");
		}
		SQLQuery query = getSession().createSQLQuery(sb.toString());
		if (marca != null) {
			query.setInteger("marcaId", marca.getMarcaId());
		}
		query.setInteger("numcorrida", numcorrida);
		Integer result = query.executeUpdate();
		return result;
	}

}