/*
 * 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.Date;
import java.util.List;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.rjconsultores.ventaboletos.dao.EsquemaAsientoDAO;
import com.rjconsultores.ventaboletos.dao.EsquemaCorridaDAO;
import com.rjconsultores.ventaboletos.dao.EsquemaTramoDAO;
import com.rjconsultores.ventaboletos.dao.RutaCombinacionDAO;
import com.rjconsultores.ventaboletos.entidad.Autobus;
import com.rjconsultores.ventaboletos.entidad.ClaseServicio;
import com.rjconsultores.ventaboletos.entidad.Empresa;
import com.rjconsultores.ventaboletos.entidad.EsquemaAsiento;
import com.rjconsultores.ventaboletos.entidad.EsquemaCorrida;
import com.rjconsultores.ventaboletos.entidad.EsquemaOperacional;
import com.rjconsultores.ventaboletos.entidad.EsquemaTramo;
import com.rjconsultores.ventaboletos.entidad.Marca;
import com.rjconsultores.ventaboletos.entidad.Parada;
import com.rjconsultores.ventaboletos.entidad.ParadaEsquema;
import com.rjconsultores.ventaboletos.entidad.RolOperativo;
import com.rjconsultores.ventaboletos.entidad.Ruta;
import com.rjconsultores.ventaboletos.entidad.Tramo;
import com.rjconsultores.ventaboletos.service.EsquemaAsientoService;
import com.rjconsultores.ventaboletos.service.EsquemaCorridaService;
import com.rjconsultores.ventaboletos.service.LogAuditoriaService;
import com.rjconsultores.ventaboletos.utilerias.DateUtil;
import com.rjconsultores.ventaboletos.utilerias.UsuarioLogado;

/**
 * 
 * @author Rafius
 */
@Service("esquemaCorridaService")
public class EsquemaCorridaServiceImpl implements EsquemaCorridaService {
	
	private static final Logger log = LogManager.getLogger(EsquemaCorridaServiceImpl.class);

	@Autowired
	private EsquemaCorridaDAO esquemaCorridaDAO;
	@Autowired
	private RutaCombinacionDAO rutaCombinacionDAO;
	@Autowired
	private EsquemaTramoDAO esquemaTramoDAO;
	@Autowired
	private EsquemaAsientoService esquemaAsientoService;	
	@Autowired
	private EsquemaAsientoDAO esquemaAsientoDAO; 
	
	@Autowired
	private LogAuditoriaService logAuditoriaService;

	public List<EsquemaCorrida> obtenerTodos() {
		return esquemaCorridaDAO.obtenerTodos();
	}

	public EsquemaCorrida obtenerID(Integer id) {
		EsquemaCorrida esquemaCorrida = esquemaCorridaDAO.obtenerID(id);
		try {
			esquemaCorrida.clonar();
		} catch (Exception e) {
			log.error(e.getMessage(), e);
		}
		return esquemaCorrida;
	}

	@Override
	public List<EsquemaCorrida> buscarPorEmpresaCorrida(Empresa empresa) {
		return esquemaCorridaDAO.buscarPorEmpresaCorrida(empresa);
	}
	
	@Override
	public List<EsquemaCorrida> buscarPorEmpresaCorridaAtiva(Empresa empresa, Date dataGeracaoInicial, Date dataGeracaoFinal) {
		return esquemaCorridaDAO.buscarPorEmpresaCorridaAtiva(empresa, dataGeracaoInicial, dataGeracaoFinal);
	}

	@Transactional
	public EsquemaCorrida suscribir(EsquemaCorrida entidad) {
		List<EsquemaAsiento> asientos = new ArrayList<EsquemaAsiento>();
		// org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing
		asientos.addAll(entidad.getEsquemaAsientoList()); 
		entidad.clearEsquemaAsiento();
		
		entidad.setUsuarioId(UsuarioLogado.getUsuarioLogado().getUsuarioId());
		entidad.setFecmodif(Calendar.getInstance().getTime());
		entidad.setActivo(Boolean.TRUE);

		Autobus a = entidad.getAutoBus();
		ClaseServicio c = entidad.getClaseServicio();
		RolOperativo r =  entidad.getRolOperativo();
		
		entidad.setAutoBus(null);
		entidad.setClaseServicio(null);
		entidad.setRolOperativo(null);
		
		entidad = esquemaCorridaDAO.suscribir(entidad);
		
		for (EsquemaAsiento esquemaAsiento : asientos) {
			esquemaAsiento = esquemaAsientoDAO.suscribir(esquemaAsiento);
		}
		
		entidad.setAutoBus(a);
		entidad.setClaseServicio(c);
		entidad.setRolOperativo(r);
		entidad.setEsquemaAsientoList(asientos);
		
		entidad = esquemaCorridaDAO.actualizacion(entidad);
		
		logAuditoriaService.auditar(null, entidad, entidad.getEmpresa() != null ? entidad.getEmpresa().getEmpresaId() : null);
		
		return entidad;
	}

	@Transactional
	public EsquemaCorrida actualizacion(EsquemaCorrida entidad) {
		try {
			entidad.setUsuarioId(UsuarioLogado.getUsuarioLogado().getUsuarioId());
			entidad.setFecmodif(Calendar.getInstance().getTime());
			entidad.setActivo(Boolean.TRUE);
			
			EsquemaCorrida clone = entidad.getCloneObject();
			
			entidad = esquemaCorridaDAO.actualizacion(entidad);
			entidad.clonar();
			EsquemaCorrida novoClone = entidad.getCloneObject();

			novoClone.setEsquemaAsientoList(null);
			List<EsquemaAsiento> lsAsientos = esquemaAsientoService.obtenerPorCorrida(entidad);
			if(lsAsientos != null) {
				List<EsquemaAsiento> lsNovoAsientos = new ArrayList<EsquemaAsiento>();
				for (EsquemaAsiento esquemaAsiento : lsAsientos) {
					esquemaAsiento.clonar();
					lsNovoAsientos.add(esquemaAsiento.getCloneObject());
				}
				novoClone.setEsquemaAsientoList(lsNovoAsientos);
			}
			
			logAuditoriaService.auditar(clone, novoClone, entidad.getEmpresa() != null ? entidad.getEmpresa().getEmpresaId() : null);
		
			return entidad;
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			throw new RuntimeException(e.getMessage(), e);
		}

	}

	@Transactional
	public void borrar(EsquemaCorrida entidad) {
		entidad = (entidad.getEsquemacorridaId() == null) ? entidad : esquemaCorridaDAO.obtenerID(entidad.getEsquemacorridaId());
		for (EsquemaAsiento pricing : entidad.getEsquemaAsientoList()) {
			pricing.setUsuarioId(UsuarioLogado.getUsuarioLogado().getUsuarioId());
			pricing.setFecmodif(Calendar.getInstance().getTime());
			pricing.setActivo(Boolean.FALSE);
			pricing = esquemaAsientoDAO.actualizacion(pricing);
		}

		for (EsquemaTramo pricing : entidad.getEsquemaTramoList()) {
			pricing.setUsuarioId(UsuarioLogado.getUsuarioLogado().getUsuarioId());
			pricing.setFecmodif(Calendar.getInstance().getTime());
			pricing.setActivo(Boolean.FALSE);
		}

		entidad.setUsuarioId(UsuarioLogado.getUsuarioLogado().getUsuarioId());
		entidad.setFecmodif(Calendar.getInstance().getTime());
		entidad.setActivo(Boolean.FALSE);
		
		logAuditoriaService.auditarExclusao(entidad, entidad.getEmpresa() != null ? entidad.getEmpresa().getEmpresaId() : null);

		esquemaCorridaDAO.actualizacion(entidad);
	}

	public List<EsquemaCorrida> buscarPorEsquemaOperacional(EsquemaOperacional eo) {
		return esquemaCorridaDAO.buscarPorEsquemaOperacional(eo);
	}

	public List<EsquemaCorrida> buscar(Marca marca, RolOperativo rolOperativo,
			Ruta ruta, ClaseServicio claseServicio) {
		return esquemaCorridaDAO.buscar(marca, rolOperativo, ruta, claseServicio);
	}

	public boolean buscarNumCorrida(Integer numCorrida, Integer numCorridaPisoExtra, boolean isDoublePiso) {
		return esquemaCorridaDAO.buscarNumCorrida(numCorrida, numCorridaPisoExtra, isDoublePiso);
	}
	
	public EsquemaCorrida buscarPeloNumCorrida(Integer numCorridaPisoExtra) {
		return esquemaCorridaDAO.buscarPeloNumCorrida(numCorridaPisoExtra);
	}

	@Transactional
	public void actualizaEsquemaTramo(List<ParadaEsquema> listParadaEsquema, EsquemaCorrida ec) {
		
		try {
			
			ec = this.obtenerID(ec.getEsquemacorridaId());
			ec.clonar();
			EsquemaCorrida originalClone = ec.getCloneObject();
			ec.clonar();
			EsquemaCorrida novoClone = ec.getCloneObject();
			List<EsquemaTramo> lsTramosNovo = new ArrayList<EsquemaTramo>();
			
			if (ec.getEsquemaTramoList() != null) {
				for (EsquemaTramo et : ec.getEsquemaTramoList()) {
					et.setActivo(Boolean.FALSE);
					et.setUsuarioId(UsuarioLogado.getUsuarioLogado().getUsuarioId());
					et.setFecmodif(Calendar.getInstance().getTime());
					esquemaTramoDAO.actualizacion(et);
				}
			}
	
			Date dataHorInicioSistema = DateUtil.getFecInicio().getTime();
			for (int i = 0; (i < listParadaEsquema.size() - 1); i++) {
				Parada paradaOrigen = listParadaEsquema.get(i).getParada();
				Parada paradaDestino = listParadaEsquema.get(i + 1).getParada();
	
				Tramo t = rutaCombinacionDAO.busqueda(ec.getRuta(), paradaOrigen, paradaDestino);
	
				if (t == null) {
					throw new RuntimeException("No fue encontrado el tramo para el origen:" + paradaOrigen + " y destino:" + paradaDestino);
				}
	
				EsquemaTramo et = new EsquemaTramo();
				et.setActivo(Boolean.TRUE);
				et.setEsquemaCorrida(ec);
				et.setFecmodif(Calendar.getInstance().getTime());
				et.setNumsecuencia((short) (i + 1));
				et.setTramo(t);
				et.setUsuarioId(UsuarioLogado.getUsuarioLogado().getUsuarioId());
				et.setPlataforma(listParadaEsquema.get(i).getPlataforma());
				et.setTipoPassagem(listParadaEsquema.get(i).getTipoPassagem());
				Date tiempoEstancia = listParadaEsquema.get(i).getTiempoEstancia();
				if ((tiempoEstancia != null) && (DateUtil.compareDate(tiempoEstancia, dataHorInicioSistema) == 0)) {
					et.setTiempoEstancia(null);
				} else {
					et.setTiempoEstancia(tiempoEstancia);
				}
	
				Date excepcionRecorrido = listParadaEsquema.get(i).getExcepcionRecorrido();
				if ((excepcionRecorrido != null) && (DateUtil.compareDate(excepcionRecorrido, dataHorInicioSistema) == 0)) {
					et.setExcepcionRecorrido(null);
				} else {
					et.setExcepcionRecorrido(excepcionRecorrido);
				}
				if(esquemaTramoDAO.verificarDuplicidadeEsquemaTramo(et)){
					throw new RuntimeException("No es possible suscribir tramos duplicados.");
				}
				esquemaTramoDAO.suscribir(et);
				
				lsTramosNovo.add(et);
			}
			novoClone.setEsquemaTramoList(lsTramosNovo);
			
			logAuditoriaService.auditar(originalClone, novoClone, ec.getEmpresa() != null ? ec.getEmpresa().getEmpresaId() : null);
		
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			throw new RuntimeException(e.getMessage(), e);
		}
	}

	@Override
	public List<EsquemaCorrida> buscaDentroVigencia(Date dataGeracao) {
		return esquemaCorridaDAO.buscaDentroVigencia(dataGeracao);
	}

	public List<EsquemaCorrida> buscaDentroVigenciaQtdeDiasNull(Date dataGeracao) {
		return esquemaCorridaDAO.buscaDentroVigenciaQtdeDiasNull(dataGeracao);
	}

	@Override
	public List<EsquemaCorrida> buscaDentroVigenciaQtdeDiasNotNull(Date dataDe) {
		return esquemaCorridaDAO.buscaDentroVigenciaQtdeDiasNotNull(dataDe);
	}

	public boolean buscarEsquemaCorridaExisteTramo(Tramo tramo) {
		return esquemaCorridaDAO.buscarEsquemaCorridaExisteTramo(tramo);
	}

	@Override
	public List<Integer> existe(Ruta ruta, Integer paradaId) {
		return esquemaCorridaDAO.existe(ruta, paradaId);
	}

	@Override
	public EsquemaCorrida obtenerByEsquemaCorrida(Integer id) {
		return esquemaCorridaDAO.obtenerByEsquemaCorrida(id);
	}

	@Override
	public EsquemaCorrida buscaEsquemaPorRuta(Ruta ruta) {
		return esquemaCorridaDAO.buscaEsquemaPorRuta(ruta);
	}
	
	@Override
	public EsquemaCorrida buscaEsquemaPorRutaSemVigencia(Integer rutaId, Integer numCorrida) {
		return esquemaCorridaDAO.buscaEsquemaPorRutaSemVigencia(rutaId, numCorrida);
	}
}
