/*
 * 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.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.hibernate.transform.AliasToBeanResultTransformer;
import org.hibernate.type.IntegerType;
import org.hibernate.type.StringType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Repository;

import com.rjconsultores.ventaboletos.dao.ParadaDAO;
import com.rjconsultores.ventaboletos.entidad.AgrupamentoParada;
import com.rjconsultores.ventaboletos.entidad.Ciudad;
import com.rjconsultores.ventaboletos.entidad.Nodo;
import com.rjconsultores.ventaboletos.entidad.Parada;
import com.rjconsultores.ventaboletos.entidad.RegionMetropolitana;
import com.rjconsultores.ventaboletos.entidad.Ruta;
import com.rjconsultores.ventaboletos.entidad.TipoParada;
import com.rjconsultores.ventaboletos.utilerias.DateUtil;
import java.util.Collections;

/**
 * 
 * @author Administrador
 */
@SuppressWarnings("unchecked")
@Repository("paradaDAO")
public class ParadaHibernateDAO extends GenericHibernateDAO<Parada, Integer> implements ParadaDAO {

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

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

		c.addOrder(Order.asc("descparada"));

		return c.list();
	}

	public List<Parada> buscar(String descparada, String cveparada, Ciudad ciudad, TipoParada tipoParada, Nodo nodo) {
		Criteria c = getSession().createCriteria(getPersistentClass());
		c.add(Restrictions.eq(ACTIVO, Boolean.TRUE));

		c.add(Restrictions.eq("descparada", descparada));
		c.add(Restrictions.eq("cveparada", cveparada));
		c.add(Restrictions.eq("ciudad", ciudad));
		c.add(Restrictions.eq("tipoParada", tipoParada));
		c.add(Restrictions.eq("nodo", nodo));

		return c.list();
	}

	public List<Parada> buscar(String descparada) {
		Criteria c = getSession().createCriteria(getPersistentClass());
		c.add(Restrictions.eq(ACTIVO, Boolean.TRUE));

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

		return c.list();
	}

	public List<Parada> buscarCVE(String cveparada) {
		Criteria c = getSession().createCriteria(getPersistentClass());
		c.add(Restrictions.eq(ACTIVO, Boolean.TRUE));

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

		return c.list();
	}

	public List<Parada> buscaLike(String descparada) {
		Criteria c = getSession().createCriteria(getPersistentClass());
		c.add(Restrictions.eq(ACTIVO, Boolean.TRUE));
		c.add(Restrictions.like("descparada", descparada, MatchMode.START));

		c.addOrder(Order.asc("descparada"));

		return c.list();
	}

	public Long count(TipoParada tipoParada) {
		Criteria c = this.makeCriteria();

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

		c.setProjection(Projections.rowCount());

		return HibernateFix.count(c.list());

	}

	@Override
	public List<Parada> buscar(Integer codAntt) {
		Criteria c = getSession().createCriteria(getPersistentClass());
		c.add(Restrictions.eq(ACTIVO, Boolean.TRUE));
		c.add(Restrictions.eq("codantt", codAntt));

		return c.list();
	}

	@Override
	public List<Parada> obtenerOrigenPorRuta(Ruta ruta) {
		Criteria c = getSession().createCriteria(getPersistentClass());
		c.createAlias("tramoOrigemList", "tramo");
		c.createAlias("tramo.rutaCombinacionList", "rutaCombinacion");
		c.createAlias("rutaCombinacion.ruta", "ruta");
		c.add(Restrictions.eq(ACTIVO, Boolean.TRUE));
		c.add(Restrictions.eq("ruta.rutaId", ruta.getRutaId()));

		c.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);

		return c.list();
	}
	
	@Override
	public List<Parada> obtenerOrigenPorListRutaIds(Integer orgaoConcendenteId, Integer empresaId,Integer[] listRuta) {
		Criteria c = getSession().createCriteria(getPersistentClass());
		Criteria criteriaTramo =c.createCriteria("tramoOrigemList");
		criteriaTramo.add(Restrictions.eq(ACTIVO, Boolean.TRUE));
		Criteria criteriaRutaCombinacionList =criteriaTramo.createCriteria("rutaCombinacionList");
		criteriaRutaCombinacionList.add(Restrictions.eq(ACTIVO, Boolean.TRUE));		
		Criteria criteriaRuta = criteriaRutaCombinacionList.createCriteria("ruta");
		criteriaRuta.add(Restrictions.eq(ACTIVO, Boolean.TRUE));
		if(null!=orgaoConcendenteId) {
			Criteria criteriaOrgaoConcendente = criteriaRuta.createCriteria("orgaoConcedente");
			criteriaOrgaoConcendente.add(Restrictions.eq("orgaoConcendenteID", orgaoConcendenteId));
			criteriaOrgaoConcendente.add(Restrictions.eq(ACTIVO, Boolean.TRUE));

		}
		if(null!=empresaId) {
			Criteria criteriaRutaEmpresa = criteriaRuta.createCriteria("lsRutaEmpresa");
			criteriaRutaEmpresa.add(Restrictions.eq("empresaId", empresaId));
			criteriaRutaEmpresa.add(Restrictions.eq(ACTIVO, Boolean.TRUE));
		}
		
		
		c.add(Restrictions.eq(ACTIVO, Boolean.TRUE));
		if(null!=listRuta) {
			criteriaRuta.add(Restrictions.in("rutaId", listRuta));
		}

		c.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);

		return c.list();
	}
	
	
	

	@Override
	public List<Parada> obterPossiveisDestinos(Parada origem) {
		if (origem == null) {
			return Collections.emptyList();
		}
		StringBuilder sql = new StringBuilder();
		sql.append("SELECT DISTINCT ")
		   .append("d ")
		   .append( "FROM Tramo t ")
		   .append( "JOIN t.destino d ")
		   .append( "WHERE t.origem = :origem ")
		   .append( "ORDER BY d.descparada ");

		return getSession()
				.createQuery(sql.toString())
				.setEntity("origem", origem)
				.list();
	}
	
	
	@Override
	public List<Parada> buscarDestinosPorOrigem(Integer origenId){
		StringBuilder sb = new StringBuilder();
		
		sb.append("SELECT *");
		sb.append("FROM");
		sb.append("  (SELECT DISTINCT pd.parada_id AS paradaId,");
		sb.append("                   pd.cveparada AS cveparada,");
		sb.append("                   pd.tipoparada_id AS potipoparada_id, ");
		sb.append("                   pd.descparada AS descparada ");
		sb.append("   FROM ruta_combinacion rc");
		sb.append("   INNER JOIN tramo t ON t.tramo_id = rc.tramo_id");
		sb.append("   INNER JOIN parada po ON po.parada_id = t.origen_id");
		sb.append("   INNER JOIN parada pd ON pd.parada_id = t.destino_id");
		sb.append("   INNER JOIN ruta r ON r.ruta_id = rc.ruta_id");
		sb.append("   INNER JOIN corrida c ON c.ruta_id = r.ruta_id");
		sb.append("   WHERE rc.activo = 1");
		sb.append("     AND r.activo = 1");
		sb.append("     AND c.activo = 1");
		sb.append("     AND po.activo = 1");
		sb.append("     AND pd.activo = 1");
		sb.append("     AND c.feccorrida BETWEEN :dataInicioHoje and :dataFim and  po.parada_id =:origenId ");
		sb.append("   UNION SELECT DISTINCT pd.parada_id AS paradaId,");
		sb.append("                         pd.cveparada AS cveparada,");
		sb.append("                         pd.tipoparada_id AS potipoparada_id,");
		sb.append("                         pd.descparada AS descparada ");
		sb.append("   FROM conexion c");
		sb.append("   INNER JOIN parada po ON po.parada_id = c.origen_id");
		sb.append("   INNER JOIN parada pd ON pd.parada_id = c.destino_id");
		sb.append("   INNER JOIN corrida co ON co.origen_id = c.origen_id");
		sb.append("   INNER JOIN corrida_tramo ct ON co.corrida_id = ct.corrida_id");
		sb.append("   WHERE 1 = 1");
		sb.append("     AND c.activo = 1");
		sb.append("     AND co.activo = 1");
		sb.append("     AND co.activo = 1");
		sb.append("     AND po.activo = 1");
		sb.append("     AND pd.activo = 1");
		sb.append("     AND co.feccorrida BETWEEN :dataInicioHoje and :dataFim and  po.parada_id =:origenId ) a ");
		sb.append(" ORDER BY a.descparada");		
		
		Query qry = getSession().createSQLQuery(sb.toString())
				.addScalar("paradaId", IntegerType.INSTANCE)
				.addScalar("cveparada", StringType.INSTANCE)
				.addScalar("descparada", StringType.INSTANCE)
				.setResultTransformer(new AliasToBeanResultTransformer(Parada.class));
		
		qry.setInteger("origenId", origenId);
		qry.setDate("dataInicioHoje", new Date());
		qry.setDate("dataFim", DateUtil.somarDias(new Date(), 7));

		List<Parada> list = qry.list();
		
		if (list.size() > 0) {
			return list;
		}
		
		return null;
		
	}

	public List<Parada> buscaParadaRegionMetropolitana(RegionMetropolitana regionMetropolitana) {
		Criteria c = getSession().createCriteria(getPersistentClass());
		c.add(Restrictions.eq(ACTIVO, Boolean.TRUE));
		c.add(Restrictions.eq("regionMetropolitana.regionMetropolitanaId", regionMetropolitana.getRegionMetropolitanaId()));
		return c.list();
	}
	
	@Override
    public List<Parada> buscarListaPorIds(List<Integer> paradaIds) {
		Criteria c = this.makeCriteria();
		c.add(Restrictions.in("paradaId", paradaIds));
		c.add(Restrictions.eq(ACTIVO, Boolean.TRUE));

		return c.list();
	}
	
	@Override
    public Parada buscarPorId(Integer paradaId) {
		Criteria c = this.makeCriteria();
		c.add(Restrictions.eq("paradaId", paradaId));
		c.add(Restrictions.eq(ACTIVO, Boolean.TRUE));

		return (Parada) c.uniqueResult();
	}

	@Override
	public List<Parada> buscarPorAgrupamentoParadaId(AgrupamentoParada agrupamentoParada) {
		if(agrupamentoParada !=null && agrupamentoParada.getAgrupamentoParadaId() !=null) {
			Criteria c = this.makeCriteria();
			c.add(Restrictions.eq("agrupamentoParada", agrupamentoParada));
			c.add(Restrictions.eq(ACTIVO, Boolean.TRUE));

			return c.list();
		}
		return null;
	}

	@Override
	public List<String> buscarDescOrigemDestino(Integer origemId, Integer destinoId) {
		StringBuilder sb = new StringBuilder();
		
		sb.append(" SELECT descparada AS descOrigem ");
		sb.append("   FROM parada po ");
		sb.append("   WHERE po.activo = 1 ");
		sb.append("   and  po.parada_id =:origemId ");
		sb.append(" UNION ");
		sb.append(" SELECT descparada AS descDestino ");
		sb.append("   FROM parada pd ");
		sb.append("   WHERE pd.activo = 1 ");
		sb.append("   and  pd.parada_id =:destinoId ");	
		
		Query qry = getSession().createSQLQuery(sb.toString());
		
		qry.setInteger("origemId", origemId);
		qry.setInteger("destinoId", destinoId);
		
		List<String> list = qry.list();

		return list;
		
	}
}
