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

import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.Predicate;
import org.hibernate.LazyInitializationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.rjconsultores.ventaboletos.dao.RutaCombinacionDAO;
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.TramoTiempo;
import com.rjconsultores.ventaboletos.entidad.Via;
import com.rjconsultores.ventaboletos.exception.BusinessException;
import com.rjconsultores.ventaboletos.service.EsquemaCorridaService;
import com.rjconsultores.ventaboletos.service.TarifaService;
import com.rjconsultores.ventaboletos.service.TramoService;
import com.rjconsultores.ventaboletos.utilerias.UsuarioLogado;

/**
 *
 * @author Administrador
 */
@Service("tramoService")
public class TramoServiceImpl implements TramoService {

    @Autowired
    private TramoDAO tramoDAO;
    @Autowired
    private RutaCombinacionDAO rutaCombinacionDAO;
    @Autowired
	private EsquemaCorridaService esquemaCorridaService;
    @Autowired
	private TarifaService tarifaService;

    public List<Tramo> obtenerTodos() {
        return tramoDAO.obtenerTodos();
    }

    public Tramo obtenerID(Integer id) {
        return tramoDAO.obtenerID(id);
    }

    @Transactional(rollbackFor = BusinessException.class)
    public void borrar(Tramo entidad) throws BusinessException {
        

        boolean rutaOcupaTramo = rutaCombinacionDAO.existeTramo(entidad);
		if (rutaOcupaTramo){
			throw new BusinessException("editarTramosController.MSG.borrarFalse");
		}
		
		boolean existeEsquemaCorrida = esquemaCorridaService.buscarEsquemaCorridaExisteTramo(entidad);
		if (existeEsquemaCorrida){
			throw new BusinessException("editarTramosController.MSG.borrarFalse");
		}
		
		boolean existeTarifa = tarifaService.buscarTarifaExisteTramo(entidad);
		if (existeTarifa){
			throw new BusinessException("editarTramosController.MSG.borrarFalse");
		}

		entidad = tramoDAO.obtenerID(entidad.getTramoId());
        if (entidad.getLsTramoTiempo() != null) {
            for (TramoTiempo tramo : entidad.getLsTramoTiempo()) {
                tramo.setUsuarioId(UsuarioLogado.getUsuarioLogado().getUsuarioId());
                tramo.setFecmodif(Calendar.getInstance().getTime());
                tramo.setActivo(Boolean.FALSE);
            }
        }

        if (entidad.getTramoServicioList() != null) {
            for (TramoServicio tramo : entidad.getTramoServicioList()) {
                tramo.setUsuarioId(UsuarioLogado.getUsuarioLogado().getUsuarioId());
                tramo.setFecmodif(Calendar.getInstance().getTime());
                tramo.setActivo(Boolean.FALSE);
            }
        }

        entidad.setUsuarioId(UsuarioLogado.getUsuarioLogado().getUsuarioId());
        entidad.setFecmodif(Calendar.getInstance().getTime());
        entidad.setActivo(Boolean.FALSE);

        tramoDAO.actualizacion(entidad);
    }

    public Tramo obtenerPorOrigemDestino(Parada origem, Parada destino) {
        return tramoDAO.obtenerPorOrigemDestino(origem, destino);
    }

    public List<Tramo> obtenerListPorOrigemDestino(Parada origem, Parada destino) {
        return tramoDAO.obtenerListPorOrigemDestino(origem, destino);
    }

    public Tramo obtenerTramotPorOrigemDestinoVia(Parada origem, Parada destino, Via via) {
        return tramoDAO.obtenerTramotPorOrigemDestinoVia(origem, destino, via);
    }

    public Tramo buscar(Parada origem, Parada destino, Via via) {
        return tramoDAO.busca(origem, destino, via);
    }
    
    @Override
    public String gerarDescripcionTramo(Parada origen,Parada destino,Via via){
    	String descTramo = origen.getCveparada() + "-" + destino.getCveparada() + "(" + via.getNombvia() + ")";
		if (descTramo.length() > 20) {
			descTramo = descTramo.substring(0, 20);
		}
		return descTramo;
    }

    public List<Tramo> buscarCveParada(String origen, String destino, String via) {
        return tramoDAO.buscarCveParada(origen, destino, via);
    }

    public Tramo obtenerTramoUnicoRuta(Parada origem, Parada destino, Via via, ClaseServicio claseServicio) {
        return tramoDAO.obtenerTramoUnicoRuta(origem, destino, via, claseServicio);
    }

    public List<Tramo> buscar(List<Parada> lsParadas, Via via) {
        List<Tramo> respuesta = new ArrayList<Tramo>();

        Parada origen = lsParadas.get(0);
        Parada destino = null;


        for (int i = 1; i < lsParadas.size(); i++) {
            destino = lsParadas.get(i);
            Tramo busca = tramoDAO.busca(origen, destino, via);

            if (busca!= null) {
                respuesta.add(busca);
            }
        }

        return respuesta;
    }

    @Transactional
    public void guardarTramosKm(List<Tramo> lsTramos, Via via) {
        for (Tramo tramo : lsTramos) {
            Tramo busca = tramoDAO.busca(tramo.getOrigem(), tramo.getDestino(), via);
            if (busca==null) {
                tramo.setVia(via);
                tramo.setActivo(Boolean.TRUE);
                tramo.setUsuarioId(UsuarioLogado.getUsuarioLogado().getUsuarioId());
                tramo.setFecmodif(Calendar.getInstance().getTime());
                tramo.setDesctramo(tramo.getOrigem().getCveparada().trim()+"-"+tramo.getDestino().getCveparada().trim());
                tramoDAO.suscribir(tramo);
                
            } else {
                Tramo tramoExiste = busca;
                tramoExiste.setKmPagoConductor(tramo.getKmPagoConductor());
                tramoExiste.setKmReal(tramo.getKmReal());
                tramoExiste.setUsuarioId(UsuarioLogado.getUsuarioLogado().getUsuarioId());
                tramoExiste.setFecmodif(Calendar.getInstance().getTime());
            }
        }
    }
    public List<Via> obtenerViasOrigemDestino(Parada origem, Parada destino) {
    	return tramoDAO.obtenerViasOrigemDestino(origem, destino);
    }
    public List<Tramo> obtenerPorOrigemDestinoFetchLazy(Parada origem, Parada destino) {
    	return tramoDAO.obtenerPorOrigemDestinoFetchLazy(origem, destino);
    }
    
    private List<TramoServicio> getListTramoService(Tramo t){
    	return tramoDAO.obtenerTramosServiciosPorTramo(t);
    }
    
    public List<OrgaoTramo> getLsOrgaoTramoByTramo(Tramo tramo){
    	return tramoDAO.getLsOrgaoTramo(tramo);
    }
    
    @Override
    @Transactional(rollbackFor = BusinessException.class)
	public Tramo suscribirActualizar(Tramo tramo) throws BusinessException {

    	
		Tramo tramoBusqueda = buscar(tramo.getOrigem(), tramo.getDestino(), tramo.getVia());

		if (tramo.getOrigem().equals(tramo.getDestino())) {
			throw new BusinessException("editarTramosController.MSG.OrigemDestinoIguais");
		}

		if ((tramoBusqueda != null) && (tramo.getTramoId() == null)) {
			throw new BusinessException("MSG.Registro.Existe.Origem.Destino.Via");
		}

		if ((tramoBusqueda != null) && (!tramo.equals(tramoBusqueda))) {
			throw new BusinessException("MSG.Registro.Existe.Origem.Destino.Via");
		}

		
		if (tramo.getTramoId() != null) {
			boolean rutaOcupaTramo = rutaCombinacionDAO.existeTramo(tramo);

			if (rutaOcupaTramo) {
				Tramo tramoOriginal = tramoDAO.obtenerID(tramo.getTramoId());

				if (!tramo.getVia().equals(tramoOriginal.getVia())) {
					throw new BusinessException("tramoServiceImpl.msg.validacionVia");
				}

				if (!tramo.getOrigem().equals(tramoOriginal.getOrigem())) {
					throw new BusinessException("tramoServiceImpl.msg.validacionOrigen");
				}

				if (!tramo.getDestino().equals(tramoOriginal.getDestino())) {
					throw new BusinessException("tramoServiceImpl.msg.validacionDestino");
				}

				// validaciOn: No es posible quitar ClaseServicio de un tramo que esta asociado a una ruta e esa ruta tenga la misma clase de servicio
				// Esa validaciOn tambien permite que el usuario quite una clase y la agregue de nuevo con otro tiempo de recorrido
				List<TramoServicio> lsTramoServicioOriginal = tramoOriginal.getTramoServicioList();
				for (final TramoServicio ts : lsTramoServicioOriginal) {
				
					
					boolean alterouClaseTramoServico = true;
					
					try{
						tramo.getTramoServicioList();
					} catch(LazyInitializationException le){ 
						tramo.setTramoServicioList(getListTramoService(tramo));
					}
					
					for( TramoServicio tsNovo : tramo.getTramoServicioList()){
						if (tsNovo.getClaseServicio().equals(ts.getClaseServicio())){
							alterouClaseTramoServico = false;
							break;
						}
					}

					if (alterouClaseTramoServico) {
						if (rutaCombinacionDAO.existeTramo(tramo, ts.getClaseServicio())) {
							throw new BusinessException("tramoServiceImpl.msg.validacionTramoServicio");
						}
					}
				}

				List<TramoTiempo> lsTramoTiempoOriginal = tramoOriginal.getLsTramoTiempo();
				for (final TramoTiempo tt : lsTramoTiempoOriginal) {
					boolean existe = CollectionUtils.exists(tramo.getLsTramoTiempo(), new Predicate() {

						@Override
						public boolean evaluate(Object o) {
							TramoTiempo t = (TramoTiempo) o;
							if (t.getActivo()) {
								return t.getClaseServicio().equals(tt.getClaseServicio());
							}
							return false;
						}
					});

					if (!existe) {
						if (rutaCombinacionDAO.existeTramo(tramo, tt.getClaseServicio())) {
							throw new BusinessException("tramoServiceImpl.msg.validacionTramoTiempo");
						}
					}
				}

			}
		}

		tramo.setDesctramo(gerarDescripcionTramo(tramo.getOrigem(), tramo.getDestino(), tramo.getVia()));
		tramo.setUsuarioId(UsuarioLogado.getUsuarioLogado().getUsuarioId());
		tramo.setFecmodif(Calendar.getInstance().getTime());
		tramo.setActivo(Boolean.TRUE);

		if (tramo.getTramoId() == null) {
			return tramoDAO.suscribir(tramo);
		} else {
			return tramoDAO.actualizacion(tramo);
		}
	}

	@Override
	public Boolean existe(Parada origem, Parada destino) {
		if(tramoDAO.obtenerPorOrigemDestino(origem, destino).getTramoId()!=null){
			return true;
		}
		return false;
	}
}
