/*
 * 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.lang.StringUtils;
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.constantes.Constantes;
import com.rjconsultores.ventaboletos.dao.EsquemaAsientoDAO;
import com.rjconsultores.ventaboletos.dao.RutaSecuenciaDAO;
import com.rjconsultores.ventaboletos.entidad.Constante;
import com.rjconsultores.ventaboletos.entidad.DetDiagramaAutobus;
import com.rjconsultores.ventaboletos.entidad.DiagramaAutobus;
import com.rjconsultores.ventaboletos.entidad.EsquemaAsiento;
import com.rjconsultores.ventaboletos.entidad.EsquemaCorrida;
import com.rjconsultores.ventaboletos.entidad.Parada;
import com.rjconsultores.ventaboletos.exception.BusinessException;
import com.rjconsultores.ventaboletos.service.ConstanteService;
import com.rjconsultores.ventaboletos.service.DiagramaAutobusService;
import com.rjconsultores.ventaboletos.service.EsquemaAsientoService;
import com.rjconsultores.ventaboletos.service.RutaSecuenciaService;
import com.rjconsultores.ventaboletos.utilerias.UsuarioLogado;

/**
 * 
 * @author Rafius
 */
@Service("esquemaAsientoService")
public class EsquemaAsientoServiceImpl implements EsquemaAsientoService {

	private static Logger log = LogManager.getLogger(EsquemaAsientoServiceImpl.class);
	private static final String BLOQUEO_EXCLUSIVO = "BLOQUEO_EXCLUSIVO";
	private static final String BLOQUEO_OCUPACION = "BLOQUEO_OCUPACION";
	
	@Autowired
	private EsquemaAsientoDAO esquemaAsientoDAO;
	
	@Autowired
	private RutaSecuenciaDAO rutaSecuenciaDAO;
	
	@Autowired
	private DiagramaAutobusService diagramaAutobusService;
	
	@Autowired
	private RutaSecuenciaService rutaSecuenciaService;
	
	@Autowired
	ConstanteService constanteService;

	private EsquemaAsiento suscribir(EsquemaAsiento entidad) {
		entidad.setUsuarioId(UsuarioLogado.getUsuarioLogado().getUsuarioId());
		entidad.setFecmodif(Calendar.getInstance().getTime());
		entidad.setActivo(Boolean.TRUE);

		return esquemaAsientoDAO.suscribir(entidad);
	}

	@Transactional
	public void borrar(EsquemaAsiento entidad) {
		entidad.setUsuarioId(UsuarioLogado.getUsuarioLogado().getUsuarioId());
		entidad.setFecmodif(Calendar.getInstance().getTime());
		entidad.setActivo(Boolean.FALSE);

		esquemaAsientoDAO.actualizacion(entidad);
	}

	public List<EsquemaAsiento> obtenerPorCorrida(EsquemaCorrida esquemaCorrida) {
		return esquemaAsientoDAO.obtenerPorCorrida(esquemaCorrida);
	}

	public EsquemaAsiento obtenerPorCorridaeAsiento(EsquemaCorrida esquemaCorrida, String asiento) {
		return esquemaAsientoDAO.obtenerPorCorridaeAsiento(esquemaCorrida, asiento);
	}
	
	@Transactional(rollbackFor = BusinessException.class)
	@Override
	public void bloqueoAsientoExclusivo(EsquemaCorrida esquemaCorrida, String strAsiento, Parada origen, Parada destino, Integer tiempoLiberacion) throws BusinessException {

		if (origen == null) {
			throw new BusinessException("editarConfiguracionCorridaAsientoController.MSG.origenObligatoria");
		}

		hacerBloqueo(BLOQUEO_EXCLUSIVO, esquemaCorrida, strAsiento, origen, destino, null, tiempoLiberacion);
	}

	private boolean hacerBloqueo(String tipoBloqueo, EsquemaCorrida esquemaCorrida, String strAsiento, Parada origen, Parada destino, String motivoOcupacion, Integer tiempoLiberacion) throws BusinessException {
		List<String> asientos = cargarAsientos(strAsiento);

		DiagramaAutobus da = diagramaAutobusService.obtenerID(esquemaCorrida.getRolOperativo().getDiagramaAutobus().getDiagramaautobusId());

		for (String asiento : asientos) {

			boolean vende = true;
			boolean existe = false;
			List<DetDiagramaAutobus> listDda = da.getDetDiagramaAutobusList();
			for (DetDiagramaAutobus dd : listDda) {
				if (dd.getAsiento().equals(asiento)) {
					existe = true;
					if (!dd.getVendible()) {
						vende = false;
					}
				}
			}
			if (!existe) {
				throw new BusinessException("editarConfiguracionCorridaAsientoController.MSG.invalido");
			}

			if (vende) {
				
				if (reviseAsientoBloqueado(asiento, esquemaCorrida, origen, destino)) {
					throw new BusinessException("editarConfiguracionCorridaAsientoController.MSG.poltronaJahConfigurada", new Object[] { asiento });
				}
				
				EsquemaAsiento es = new EsquemaAsiento();
				es.setActivo(Boolean.TRUE);
				es.setFecmodif(Calendar.getInstance().getTime());
				es.setUsuarioId(UsuarioLogado.getUsuarioLogado().getUsuarioId());
				es.setNumasiento(asiento.toString());
				es.setTiempoLiberacion(tiempoLiberacion);

				if (tipoBloqueo.equals(BLOQUEO_EXCLUSIVO)) {
					es.setIndvendible(Boolean.TRUE);
					es.setParada(origen);
				} else {
					es.setIndvendible(Boolean.FALSE);
					es.setParada(origen);
					es.setDestino(destino);
					es.setMotivobloqueo(motivoOcupacion);
				}

				es.setEsquemaCorrida(esquemaCorrida);
				es = suscribir(es);

				// validação extra para garantir que salvou corretamente
				if (tipoBloqueo.equals(BLOQUEO_EXCLUSIVO)) {

					if (!(es.getIndvendible() && (es.getParada() != null) && (es.getDestino() == null))) {

						throw new BusinessException("editarConfiguracionCorridaAsientoController.MSG.validacionGrabacion");
					}

				} else {
					// validação extra para garantir que salvou corretamente
					if (!(!es.getIndvendible() && (es.getParada() != null) && (es.getDestino() != null))) {
						throw new BusinessException("editarConfiguracionCorridaAsientoController.MSG.validacionGrabacion");
					}
				}

			} else {
				throw new BusinessException("editarConfiguracionCorridaAsientoController.MSG.poltronaNoVendible", new Object[] { asiento });
			}
		}

		return true;
	}

	private boolean reviseAsientoBloqueado(String asiento, EsquemaCorrida esquemaCorrida, Parada origen, Parada destino) {
		
		List<Integer> numSequenciaOcupada = rutaSecuenciaService.obtenerNumRutaSecuenciaOcupadaPorCorridaAsiento(esquemaCorrida, asiento);
		List<Short> numSequenciaSeleccionado = rutaSecuenciaService.obtenerNumRutaSecuenciaPorCorridaOrigemDestino(esquemaCorrida, origen, destino);
		for (Short numSequencia : numSequenciaSeleccionado) {
			if (numSequenciaOcupada.contains(numSequencia.intValue())) {
				return true;
			}
		}
		
		return false;
		
	}

	@Transactional(rollbackFor = BusinessException.class)
	@Override
	public void bloqueoAsientoOcupacion(EsquemaCorrida esquemaCorrida, String strAsiento, Parada origen, Parada destino, Integer tiempoLiberacion, String motivoOcupacion) throws BusinessException {

		if (origen == null) {
			throw new BusinessException("editarConfiguracionCorridaAsientoController.MSG.origenObligatoria");
		}
		if (destino == null) {
			throw new BusinessException("editarConfiguracionCorridaAsientoController.MSG.destinoObligatoria");
		}
		if (StringUtils.isBlank(motivoOcupacion)) {
			throw new BusinessException("editarConfiguracionCorridaAsientoController.MSG.motivo");
		}

		if (!rutaSecuenciaDAO.paradaSecuenciaValida(esquemaCorrida.getRuta(), origen, destino)) {
			throw new BusinessException("editarConfiguracionCorridaAsientoController.MSG.tramo");
		}

		hacerBloqueo(BLOQUEO_OCUPACION, esquemaCorrida, strAsiento, origen, destino, motivoOcupacion, tiempoLiberacion);
	}

	/**
	 * Hace la conversion de la string strAsientos en una lista de asientos válidos<br/>
	 * 
	 * @param strAsientos
	 * @return
	 * @throws BusinessException
	 */
	private List<String> cargarAsientos(String strAsientos) throws BusinessException {
		List<String> todosAsientos = new ArrayList<String>();

		try {
			String asientos[] = strAsientos.split(",");

			for (int i = 0; i < asientos.length; i++) {
				if (asientos[i].contains("-")) {
					String intervalo[] = asientos[i].split("-");
					Integer ini = Integer.parseInt(intervalo[0]);
					Integer fim = Integer.parseInt(intervalo[1]);

					while (ini <= fim) {
						todosAsientos.add(ini.toString());
						ini++;
					}
				} else {
					Constante constNumAsientoComLetra = constanteService.buscarPorNomeConstante(Constantes.NUM_ASIENTO_CON_LETRA);
					if (!constNumAsientoComLetra.getValorconstante().equals("true")) {
						Integer.parseInt(asientos[i]);
					}
					// para validar
					todosAsientos.add(asientos[i]);
				}
			}
		} catch (NumberFormatException t) {
			throw new BusinessException("editarConfiguracionCorridaAsientoController.MSG.invalido");
		} catch (Throwable t) {
			log.error("", t);

			throw new BusinessException("editarConfiguracionCorridaAsientoController.MSG.invalido");
		}

		return todosAsientos;
	}
	
}
