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

import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.FetchMode;
import org.hibernate.Query;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.hibernate.transform.Transformers;
import org.hibernate.type.BigDecimalType;
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.TramoDAO;
import com.rjconsultores.ventaboletos.entidad.ClaseServicio;
import com.rjconsultores.ventaboletos.entidad.OrgaoTramo;
import com.rjconsultores.ventaboletos.entidad.Parada;
import com.rjconsultores.ventaboletos.entidad.Tramo;
import com.rjconsultores.ventaboletos.entidad.TramoServicio;
import com.rjconsultores.ventaboletos.entidad.Via;
import com.rjconsultores.ventaboletos.utilerias.DateUtil;
import com.rjconsultores.ventaboletos.vo.tramo.TramoVO;

/**
 * 
 * @author Administrador
 */
@SuppressWarnings("unchecked")
@Repository("tramoDAO")
public class TramoHibernateDAO extends GenericHibernateDAO<Tramo, Integer>
		implements TramoDAO {

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

	@Override
	public List<Tramo> obtenerTodos() {
		Criteria c = getSession().createCriteria(getPersistentClass());
		c.add(Restrictions.eq(ACTIVO, Boolean.TRUE));
		c.addOrder(Order.asc("desctramo"));

		return c.list();
	}
	
	public List<TramoServicio> obtenerTramosServiciosPorTramo(Tramo t){
		return obtenerID(t.getTramoId()).getTramoServicioList();
	}

	public Tramo obtenerPorOrigemDestino(Parada origem, Parada destino) {
		Criteria c = getSession().createCriteria(getPersistentClass());
		c.add(Restrictions.eq("origem", origem));
		c.add(Restrictions.eq("destino", destino));
		c.add(Restrictions.eq(ACTIVO, Boolean.TRUE));

		Tramo t = new Tramo();
		if (c.list().size() > 0) {
			t = (Tramo) c.list().get(0);
		}

		return t;
	}

	public Tramo obtenerTramotPorOrigemDestinoVia(Parada origem, Parada destino, Via via) {
		Criteria c = getSession().createCriteria(getPersistentClass());
		c.add(Restrictions.eq("origem", origem));
		c.add(Restrictions.eq("destino", destino));
		c.add(Restrictions.eq("via", via));
		c.add(Restrictions.eq(ACTIVO, Boolean.TRUE));

		return (Tramo) c.uniqueResult();
	}

	public List<Tramo> obtenerListPorOrigemDestino(Parada origem, Parada destino) {
		Criteria c = getSession().createCriteria(getPersistentClass());
		c.add(Restrictions.eq("origem", origem));
		c.add(Restrictions.eq("destino", destino));
		c.add(Restrictions.eq(ACTIVO, Boolean.TRUE));
		c.addOrder(Order.asc("desctramo"));

		return c.list();
	}

	public List<Tramo> obtenerPorOrigemDestinoFetchLazy(Parada origem, Parada destino) {
		Criteria c = getSession().createCriteria(getPersistentClass());
		c.add(Restrictions.eq("origem", origem));
		c.add(Restrictions.eq("destino", destino));
		c.add(Restrictions.eq(ACTIVO, Boolean.TRUE));
		c.addOrder(Order.asc("desctramo"));

		c.setFetchMode("origem", FetchMode.SELECT);
		c.setFetchMode("destino", FetchMode.SELECT);
		c.setFetchMode("lsTramoTiempo", FetchMode.SELECT);
		c.setFetchMode("rutaSecuenciaList", FetchMode.SELECT);
		c.setFetchMode("rutaCombinacionList", FetchMode.SELECT);
		c.setFetchMode("tramoServicioList", FetchMode.SELECT);
		c.setFetchMode("tramoKms", FetchMode.SELECT);

		return c.list();
	}

	// Obtener Vias Possiveis
	public List<Via> obtenerViasOrigemDestino(Parada origem, Parada destino) {
		Criteria c = makeCriteria();
		c.add(Restrictions.eq("origem", origem));
		c.add(Restrictions.eq("destino", destino));
		c.add(Restrictions.eq(ACTIVO, Boolean.TRUE));
		c.addOrder(Order.asc("desctramo"));

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

		return c.list();
	}

	public Tramo busca(Parada origem, Parada destino, Via via) {
		Criteria c = getSession().createCriteria(getPersistentClass());
		c.add(Restrictions.eq(ACTIVO, Boolean.TRUE));
		c.add(Restrictions.eq("origem", origem));
		c.add(Restrictions.eq("destino", destino));
		c.add(Restrictions.eq("via", via));

		return (Tramo) c.uniqueResult();
	}

	public List<Tramo> buscarCveParada(String origen, String destino, String via) {
		Criteria c = getSession().createCriteria(getPersistentClass());

		c.createCriteria("origem").add(Restrictions.eq("paradaId", Integer.parseInt(origen)));
		c.createCriteria("destino").add(Restrictions.eq("paradaId", Integer.parseInt(destino)));
		c.createCriteria("via").add(Restrictions.eq("viaId", Integer.parseInt(via)));

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

		return c.list();
	}

	public Tramo obtenerTramoUnicoRuta(Parada origem, Parada destino, Via via,
			ClaseServicio claseServicio) {
		Criteria c = getSession().createCriteria(getPersistentClass());
		c.add(Restrictions.eq("origem", origem));
		c.add(Restrictions.eq("destino", destino));
		c.add(Restrictions.eq("via", via));
		c.add(Restrictions.eq(ACTIVO, Boolean.TRUE));

		c.setFetchMode("origem", FetchMode.SELECT);
		c.setFetchMode("destino", FetchMode.SELECT);
		c.setFetchMode("lsTramoTiempo", FetchMode.SELECT);
		c.setFetchMode("rutaSecuenciaList", FetchMode.SELECT);
		c.setFetchMode("rutaCombinacionList", FetchMode.SELECT);
		c.setFetchMode("tramoServicioList", FetchMode.SELECT);
		c.setFetchMode("tramoKms", FetchMode.SELECT);

		Criteria c2 = c.createCriteria("tramoServicioList");
		c2.add(Restrictions.eq("claseServicio", claseServicio));
		c2.add(Restrictions.eq(ACTIVO, Boolean.TRUE));

		c.setMaxResults(1);
		List<Tramo> result = c.list();

		if (result.isEmpty()) {
			return null;
		}

		return result.get(0);
	}

	public Long count(Via via) {
		Criteria c = this.makeCriteria();

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

		c.setProjection(Projections.rowCount());

		return HibernateFix.count(c.list());
	}
	
	public List<OrgaoTramo> getLsOrgaoTramo(Tramo tramo){
		return obtenerID(tramo.getTramoId()).getLsOrgaoTramo();
	}

	@Override
	public List<Tramo> buscarListaPorIds(List<Integer> tramoIds) {
		Criteria c = this.makeCriteria();
		c.add(Restrictions.in("tramoId", tramoIds));
		c.add(Restrictions.eq(ACTIVO, Boolean.TRUE));
	
		return c.list();
	}
	
	@Override
	public List<TramoVO> buscarListaPorIds(List<Integer> tramoIds, String chaveCorrida, boolean tarifaEmbarcada ) throws Exception {
		StringBuilder sql = new StringBuilder(); 
		
		sql.append(" SELECT ");
		sql.append("     trm.tramo_id                          AS tramoid, ");
		sql.append("     trm.desctramo                         AS desctramo, ");
		sql.append("     trm.origen_id                         AS origemId, ");
		sql.append("     trm.destino_id                        AS destinoId, ");
		sql.append("     ta.moneda_id			               AS monedaId, ");
		sql.append("     coalesce(ta.importetaxaembarque, 0)   AS valorTaxa, ");
		sql.append("     coalesce(ta.importepedagio, 0)        AS valorPedagio, ");
		sql.append("     coalesce(ta.importeoutros, 0)         AS valorOutros, ");
		sql.append("     coalesce(ta.importeseguro, 0)         AS valorSeguro, ");
		sql.append("     coalesce(ta.precio, 0)                AS valorTarifa, ");
		sql.append("     0                                     AS tarifaMinima, ");
		sql.append("     emp.empresa_id                        AS empresaId ");
		sql.append(" FROM ");
		sql.append("     ruta_combinacion   rc ");
		sql.append("     JOIN tramo trm ON trm.tramo_id = rc.tramo_id AND trm.activo = 1  ");
		sql.append("     JOIN corrida_tramo crt ON crt.destino_id = trm.destino_id ");
		sql.append("                               AND crt.corrida_id = :corridaId ");
		sql.append("                               AND crt.feccorrida = to_date(:fecCorrida,'ddMMyyyy') ");
		sql.append("                               AND crt.activo = 1 ");
		sql.append("     JOIN corrida  co ON co.corrida_id = crt.corrida_id ");
		sql.append("                               AND crt.feccorrida = co.feccorrida ");
		sql.append("                               and rc.ruta_id = co.ruta_id ");
		sql.append("     JOIN empresa emp ON emp.empresa_id = co.empresacorrida_id ");
		sql.append("     JOIN marca mar ON mar.empresa_id = emp.empresa_id AND mar.activo = 1 ");
		if (tarifaEmbarcada) {
			sql.append("    JOIN TARIFA_EMBARCADA ta ON ta.marca_id = mar.marca_id ");
			sql.append("                       AND ta.tramo_id = trm.tramo_id ");
			sql.append("                       AND ta.ruta_id = rc.ruta_id ");
			sql.append("                       AND ta.activo = 1 ");
		} else {
			sql.append("     JOIN tarifa ta ON ta.marca_id = mar.marca_id ");
			sql.append("                       AND ta.tramo_id = trm.tramo_id ");
			sql.append("                       AND ta.ruta_id = rc.ruta_id ");
			sql.append("                       AND ta.activo = 1 ");
		}
		sql.append("     JOIN vigencia_tarifa  vt ON vt.vigenciatarifa_id = ta.vigenciatarifa_id AND vt.activo = 1 ");
		sql.append("                                AND sysdate BETWEEN vt.feciniciovigencia AND vt.fecfinvigencia ");
		sql.append(" WHERE ");
		sql.append("     rc.activo = 1 ");
		sql.append("     AND coalesce(rc.indventa, 0) = 1 ");
		sql.append("     AND trm.origen_id IN ( ");
		sql.append("         SELECT  x.origen_id ");
		sql.append("         FROM  corrida_tramo x ");
		sql.append("         WHERE  x.corrida_id = co.corrida_id ");
		sql.append("             AND x.feccorrida = co.feccorrida ");
		sql.append("     ) ");
		sql.append("     AND trm.destino_id IN ( ");
		sql.append("         SELECT  x.destino_id ");
		sql.append("         FROM  corrida_tramo x ");
		sql.append("         WHERE  x.corrida_id = co.corrida_id ");
		sql.append("             AND x.feccorrida = co.feccorrida ");
		sql.append("     ) ");
		sql.append("           and trm.tramo_id in (  :tramoIds )  ");
		sql.append("  ORDER BY crt.numsecuencia ");
	
		Query query = getSession().createSQLQuery(sql.toString())
			.addScalar("tramoId", IntegerType.INSTANCE)
			.addScalar("desctramo", StringType.INSTANCE)
			.addScalar("origemId", IntegerType.INSTANCE)			
			.addScalar("destinoId", IntegerType.INSTANCE)
			.addScalar("monedaId", IntegerType.INSTANCE)
			.addScalar("valorTaxa", BigDecimalType.INSTANCE)
			.addScalar("valorPedagio", BigDecimalType.INSTANCE)
			.addScalar("valorOutros", BigDecimalType.INSTANCE)
			.addScalar("valorSeguro", BigDecimalType.INSTANCE)
			.addScalar("valorTarifa", BigDecimalType.INSTANCE)
			.addScalar("tarifaMinima", BigDecimalType.INSTANCE)
			.addScalar("empresaId", IntegerType.INSTANCE)
			
			.setResultTransformer(Transformers.aliasToBean(TramoVO.class));
		
		String[] split = chaveCorrida.split(";");
		String corridaId = split[0].trim();
		String fecha = split[1].trim();
		
		query.setParameter("corridaId", Integer.parseInt(corridaId) );
		query.setString("fecCorrida", fecha);
		query.setParameterList("tramoIds", tramoIds);
		
		return query.list();
	}
	
	@Override
	public List<Tramo> obtenerTramosPorOrigemDestino(Parada origem, Parada destino) {
		Criteria c = getSession().createCriteria(getPersistentClass());
		c.add(Restrictions.eq("origem", origem));
		c.add(Restrictions.eq("destino", destino));
		c.add(Restrictions.eq(ACTIVO, Boolean.TRUE));


		return c.list();
	}
}
