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.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Property;
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.AbastoCentralDAO;
import com.rjconsultores.ventaboletos.entidad.AbastoCentral;
import com.rjconsultores.ventaboletos.entidad.Aidf;
import com.rjconsultores.ventaboletos.entidad.ControleEstoqueMigracao;
import com.rjconsultores.ventaboletos.entidad.Estacion;
import com.rjconsultores.ventaboletos.entidad.PuntoVenta;

@Repository("abastoCentralDAO")
public class AbastoCentralHibernateDAO extends GenericHibernateDAO<AbastoCentral, Long> implements AbastoCentralDAO {
	
	@Autowired
	public AbastoCentralHibernateDAO(
			@Qualifier("sessionFactory") SessionFactory factory) {
		setSessionFactory(factory);
	}
	
	public List<AbastoCentral> obtenerTodos() {
		Criteria c = getSession().createCriteria(getPersistentClass());
		c.add(Restrictions.eq(ACTIVO, Boolean.TRUE));

		return (List<AbastoCentral>)c.list();
	}


	public List<AbastoCentral> obtenerBilhetes(Aidf aidf, PuntoVenta origem) {
		Criteria c = getSession().createCriteria(getPersistentClass());
		c.add(Restrictions.eq("aidf", aidf));
		c.add(Restrictions.eq("puntoventa", origem));
		c.add(Restrictions.eq(ACTIVO, Boolean.TRUE));
		
		return (List<AbastoCentral>)c.list();
	}


	public List<AbastoCentral> obtenerBilhetes(Aidf aidf, String formInicial, String formFinal, PuntoVenta origem) {
		
		String queryStr = "from AbastoCentral act where act.aidf = :aidf and act.puntoventa = :puntoventa and act.activo = true and act.numfoliopreimpreso between :folioinicial and :foliofinal"; 
		
		Query query = getSession().createQuery(queryStr);
		
		query.setLong("aidf", aidf.getAidfId());
		query.setInteger("puntoventa", origem.getPuntoventaId());
		query.setLong("folioinicial", Long.valueOf(formInicial));
		query.setLong("foliofinal", Long.valueOf(formFinal));
		
		return (List<AbastoCentral>)query.list();
	}
	
	@Transactional
	public void actualizaBilhetes(List<AbastoCentral> bilhetes, PuntoVenta destino) {
		
		Session session = getSessionFactory().getCurrentSession(); 
		
		int count = 0;
		
		for(AbastoCentral bilhete : bilhetes){
			bilhete.setPuntoventa(destino);
			session.update(bilhete);
			
			if(++count % 20 == 0){
				session.flush();
				session.clear();
			}
		}
		
		session.flush();
		session.clear();
	}

	@Transactional(readOnly=true)
	public void suscribirBilhetes(List<AbastoCentral> bilhetes) {
		Session session = getSessionFactory().getCurrentSession(); 
		
		int count = 0;
		
		for(AbastoCentral bilhete : bilhetes){
			
			session.save(bilhete);
			
			if(++count % 50 == 0){
				session.flush();
				session.clear();
			}
		}
		
		session.flush();
		session.clear();
	}

	public List<AbastoCentral> buscaBilhetesPorAidf(Aidf aidf) {
		Criteria c = getSession().createCriteria(getPersistentClass());
		c.add(Restrictions.eq("aidf", aidf));
		
		return (List<AbastoCentral>)c.list();
	}

	public List<AbastoCentral> obtenerBilhetesPorPuntoVenta(PuntoVenta puntoVentaBilhetes) {
		Criteria c = getSession().createCriteria(getPersistentClass());
		c.add(Restrictions.eq("puntoventa", puntoVentaBilhetes));
		c.add(Restrictions.eq(ACTIVO, Boolean.TRUE));
		
		return (List<AbastoCentral>)c.list();
	}

	public List<AbastoCentral> obtenerBilhetesPorPuntoVenta(String formInicial, String formFinal, PuntoVenta puntoVentaBilhetes) {
		
		String queryStr = "from AbastoCentral act where act.puntoventa = :puntoventa and act.activo = true and act.numfoliopreimpreso between :folioinicial and :foliofinal"; 
		
		Query query = getSession().createQuery(queryStr);
		
		query.setInteger("puntoventa", puntoVentaBilhetes.getPuntoventaId());
		query.setLong("folioinicial", Long.valueOf(formInicial));
		query.setLong("foliofinal", Long.valueOf(formFinal));
		
		return (List<AbastoCentral>)query.list();
	}
	
	public List<AbastoCentral> obtenerBilhetesPorPuntoVenta(PuntoVenta puntoVentaBilhetes, Estacion origem) {
		
		Criteria c = getSession().createCriteria(getPersistentClass());
		c.add(Restrictions.eq("puntoventa", puntoVentaBilhetes));
		c.add(Restrictions.eq(ACTIVO, Boolean.TRUE));
		c.add(Restrictions.eq("estacion", origem));
		c.addOrder(Order.asc("numfoliopreimpreso"));
		
		return (List<AbastoCentral>)c.list();
	}

	public List<AbastoCentral> obtenerBilhetesPorPuntoVenta(String numSerie, String formInicial, String formFinal, PuntoVenta puntoVentaBilhetes, Estacion origem) {
		
		String queryStr = "from AbastoCentral act where act.puntoventa = :puntoventa and act.numseriepreimpresa = :numseriepreimpresa and act.activo = true and act.numfoliopreimpreso between :folioinicial and :foliofinal"; 
		
		if(origem != null)
			queryStr += " and act.estacion = :estacion";
		
		Query query = getSession().createQuery(queryStr);
		
		query.setInteger("puntoventa", puntoVentaBilhetes.getPuntoventaId());
		query.setString("numseriepreimpresa", numSerie);
		query.setLong("folioinicial", Long.valueOf(formInicial));
		query.setLong("foliofinal", Long.valueOf(formFinal));
		
		if(origem != null)
			query.setInteger("estacion", origem.getEstacionId());
		
		return (List<AbastoCentral>)query.list();
	}
	
	@Transactional
	public void actualizaBilhetes(List<AbastoCentral> bilhetes, Estacion destino) {
		
		Session session = getSessionFactory().getCurrentSession(); 
		
		int count = 0;
		
		for(AbastoCentral bilhete : bilhetes){
			bilhete.setEstacion(destino);
			session.update(bilhete);
			
			if(++count % 20 == 0){
				session.flush();
				session.clear();
			}
		}
		
		session.flush();
		session.clear();
	}

	@Override
	public void gravaControleEstoqueMigracao(PuntoVenta puntoVenta, Date fecmodif, Integer usuarioId) {
		Session session = getSessionFactory().getCurrentSession(); 
		ControleEstoqueMigracao ctrlMigracao = new ControleEstoqueMigracao(puntoVenta, fecmodif, usuarioId);
		session.save(ctrlMigracao);
		session.flush();
		session.clear();
	}

	@Override
	public List<String> buscarSeriesBilhetesPorEstacion(Estacion estacion) {
		
		Criteria c = getSession().createCriteria(getPersistentClass());
		c.setProjection(Projections.distinct(Property.forName("numseriepreimpresa")));		
		c.add(Restrictions.eq(ACTIVO, Boolean.TRUE));
		c.add(Restrictions.eq("estacion", estacion));
		c.addOrder(Order.asc("numseriepreimpresa"));
		
		return (List<String>)c.list();
	}	
	
	@Override
	public void borrarLosQueTienenAIDF(Aidf aidf){
		  String hql = " delete from AbastoCentral where aidf.aidfId = " + aidf.getAidfId();
	        Query sq = getSession().createQuery(hql);
	        sq.executeUpdate();
	}
	
}
