package com.ejie.ab04b.evento;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.ejie.ab04b.constantes.Constantes;
import com.ejie.ab04b.constantes.ConstantesPlateaTramitacion;
import com.ejie.ab04b.constantes.TipoTareaPlatea;
import com.ejie.ab04b.exception.AB04BException;
import com.ejie.ab04b.model.ComunicacionProcedimiento;
import com.ejie.ab04b.model.DocumentoAperturas;
import com.ejie.ab04b.model.DocumentoOS2;
import com.ejie.ab04b.model.DocumentoOS3;
import com.ejie.ab04b.model.Tarea;
import com.ejie.ab04b.model.TareaProcedimiento;
import com.ejie.ab04b.model.TramiteProcedimiento;
import com.ejie.ab04b.parse.MessageParserSax;
import com.ejie.ab04b.service.ConsolidarEventoService;
import com.ejie.ab04b.service.DocumentoAperturasService;
import com.ejie.ab04b.service.DocumentoOS2Service;
import com.ejie.ab04b.service.DocumentoOS3Service;
import com.ejie.ab04b.service.TareaService;
import com.ejie.ab04b.util.Utilities;
import com.ejie.foldermanagement.xml.ContextSubmissionEvent;
import com.ejie.foldermanagement.xml.DocumentEvent;
import com.ejie.mbt.xml.Task;
import com.ejie.r02k.xml.EjgvDocument;

/**
 * @author GFI-NORTE
 * 
 */
@Service(value = "eventoAvisosService")
public class EventoAvisosService {

	// private static final Logger logger = LoggerFactory
	// .getLogger(EventoAvisosService.class);

	@Autowired()
	private TareaService tareaService;
	@Autowired()
	private DocumentoAperturasService documentoAperturasService;
	@Autowired()
	private DocumentoOS2Service documentoOS2Service;
	@Autowired()
	private DocumentoOS3Service documentoOS3Service;

	@Autowired()
	private ManejadorTareasAperturas manejadorTareaAperturas;

	@Autowired()
	private ManejadorTareasOS2 manejadorTareaOS2;

	@Autowired()
	private ManejadorTareasOS3 manejadorTareaOS3;

	@Autowired()
	private ConsolidarEventoService consolidarEventoService;

	/**
	 * Gestionar tarea sugerida.
	 * 
	 * evento EventoAvisos task Task
	 * 
	 * @param evento
	 *            the evento
	 * @param task
	 *            the task
	 * @throws AB04BException
	 *             the AB 04 B exception
	 */
	public void gestionarTareaSugerida(EventoAvisos evento, Task task)
			throws AB04BException {

		try {
			Tarea tipoTarea = this.tareaService.findByTaskIdProcedureId(
					task.getTaskID(), task.getProcedureID());

			ManejadorTareas manejadorTareas = this
					.obtenerManejadorTareas(task.getProcedureID());

			TramiteProcedimiento tramite = null;
			// Comprobamos si es una tarea inicial y no es la tarea de apertura
			if (tipoTarea.getEsInicial090() && !TipoTareaPlatea.APERTURA.name()
					.equalsIgnoreCase(tipoTarea.getTaskId090())) {
				// Si es inicial, hay que crear trámite nuevo
				tramite = manejadorTareas.crearTramiteTareaSugerida(task,
						tipoTarea);
			}
			// si es tarea incial y es de apertura -> sleep para que le dé
			// tiempo a
			// crear el tramite
			else if (tipoTarea.getEsInicial090() && TipoTareaPlatea.APERTURA
					.name().equalsIgnoreCase(tipoTarea.getTaskId090())) {
				// try {
				// Thread.sleep(ConstantesNum.NUM_4000);
				// } catch (InterruptedException e) {
				// EventoAvisosService.logger
				// .error("[ERROR] : gestionarTareaSugerida por Evento y Task");
				// }

				ComunicacionProcedimiento comunicacion = manejadorTareas
						.findExpedienteByFolderId(task.getFolderID());

				tramite = manejadorTareas
						.obtenerTramitePadreExistente(tipoTarea, comunicacion);

				if (tramite == null) {
					throw new AB04BException("JMS Procesado antes de tiempo.");
				}

			} else {
				// Si NO es inicial o es la tarea de apertura, ya existe el
				// trámite
				ComunicacionProcedimiento comunicacion = manejadorTareas
						.findExpedienteByFolderId(task.getFolderID());
				tramite = manejadorTareas
						.obtenerTramitePadreExistente(tipoTarea, comunicacion);

				if (tramite == null) {
					throw new AB04BException("JMS Procesado antes de tiempo.");
				}
			}

			// Creamos la tarea
			TareaProcedimiento tarea = manejadorTareas.crearTareaSugerida(task,
					tipoTarea, tramite);

			// Si la tarea sugerida es automática, procedemos directamente
			// a su tramitación
			if (Constantes.AUTOMATICA
					.equals(tarea.getTipoTarea().getTipo090())) {

				manejadorTareas.ejecutarTareaAutomatica(tarea);
			}
		} catch (Exception e) {
			throw new AB04BException(e, e.getMessage());
		}

	}

	/**
	 * Gestionar tarea ejecutada.
	 * 
	 * evento EventoAvisos task Task
	 * 
	 * @param evento
	 *            the evento
	 * @param task
	 *            the task
	 * @throws AB04BException
	 */
	public void gestionarTareaEjecutada(EventoAvisos evento, Task task)
			throws AB04BException {

		ManejadorTareas manejadorTareas = this
				.obtenerManejadorTareas(task.getProcedureID());

		// Actualizamos los datos de la tarea ejecutada
		manejadorTareas.actualizarTareaEjecutada(task);

	}

	/**
	 * Gestionar evento transformacion PDFA.
	 * 
	 * oid String
	 * 
	 * @param oid
	 *            the oid
	 */
	public void gestionarEventoTransformacionPDFA(String oid) {

		// Tenemos el OID del documento que se ha transformado pero el mensaje
		// no nos informa a que procedureId corresponde

		// Buscamos de uno en uno en las distintas tablas de documentos
		String procedureId = null;
		Long idTarea = null;
		Long idDocumento = null;

		DocumentoAperturas filterDocAperturas = new DocumentoAperturas();
		filterDocAperturas.setOidDokusi065(oid);
		filterDocAperturas = this.documentoAperturasService.findByOid(oid);
		if (filterDocAperturas != null) {
			procedureId = Utilities.getInstance().obtenerProcedureIdApertura();
			idTarea = filterDocAperturas.getTareaAperturasContinuar()
					.getIdTarea063();
			idDocumento = filterDocAperturas.getIdDocumento065();
		} else {
			DocumentoOS2 filterDocOS2 = new DocumentoOS2();
			filterDocOS2.setOidDokusi094(oid);
			filterDocOS2 = this.documentoOS2Service.findByOid(oid);
			if (filterDocOS2 != null) {
				procedureId = Utilities.getInstance().obtenerProcedureIdOs2();
				idTarea = filterDocOS2.getTareaOS2Continuar().getIdTarea093();
				idDocumento = filterDocOS2.getIdDocumento094();
			} else {
				DocumentoOS3 filterDocOS3 = new DocumentoOS3();
				filterDocOS3.setOidDokusi097(oid);
				filterDocOS3 = this.documentoOS3Service.findByOid(oid);
				if (filterDocOS3 != null) {
					procedureId = Utilities.getInstance()
							.obtenerProcedureIdOs3();
					idTarea = filterDocOS3.getTareaOS3Continuar()
							.getIdTarea096();
					idDocumento = filterDocOS3.getIdDocumento097();
				}
			}
		}

		ManejadorTareas manejadorTareas = this
				.obtenerManejadorTareas(procedureId);

		// Actualizamos los datos de la tarea ejecutada
		manejadorTareas.continuarEjecucionTareaEsperaTransformacion(idTarea,
				idDocumento);

	}

	/**
	 * Gestionar solicitud telematica.
	 * 
	 * contextSubmission ContextSubmissionEvent
	 * 
	 * @param contextSubmission
	 *            the context submission
	 * @throws AB04BException
	 *             the AB 04 B exception
	 */
	public void gestionarSolicitudTelematica(
			ContextSubmissionEvent contextSubmission) throws AB04BException {
		try {

			// obtenemos el documento de tipo solicitud (PRE)
			List<DocumentEvent> listaDocumentos = contextSubmission
					.getDocumentsEvent().getDocumentEvent();
			DocumentEvent documentoSolicitud = this.buscarDocumentoPorTipo(
					listaDocumentos,
					ConstantesPlateaTramitacion.PPS_DOC_TYPE_SOLICITUD);

			// convertimos su contenido hexadecimal a texto
			// String contenidoHex = new
			// String(documentoSolicitud.getSourceBinary());
			// String contenidoDocumento = Utilities.getInstance()
			// .parseHexAsString(contenidoHex);

			// El contenido hexadecimal se parsea a String automáticamente
			String contenidoDocumento = new String(
					documentoSolicitud.getSourceBinary(), "UTF-8");

			// obtenemos el xml comentado en su interior
			String xmlSolicitud = this
					.getXmlFromEjgvDocument(contenidoDocumento);

			// añadimos el namespace para que JAXB sea capaz de parsearlo
			xmlSolicitud = xmlSolicitud.replaceAll("<ejgvDocument>",
					"<ejgvDocument xmlns=\"com/ejie/r02k/xml\">");
			/*****************************/
			xmlSolicitud = xmlSolicitud.replaceAll(
					"<ejgvDocument xmlns:ns2='com/ejie/r02k/xml' xmlns='com/ejie/platea/generic/xml'>",
					"<ejgvDocument xmlns=\"com/ejie/r02k/xml\">");
			/*****************************/
			// añadimos <![CDATA[]]> al detailInfo
			/*
			 * xmlSolicitud = xmlSolicitud .replaceAll("<detailInfo>",
			 * "<detailInfo><![CDATA[<detailInfo xmlns=\"com/ejie/detailInfo/aperturassoltel/xml\">"
			 * ) .replaceAll("</detailInfo>", "</detailInfo>]]></detailInfo>");
			 */
			xmlSolicitud = xmlSolicitud.replaceFirst(
					"<detailInfo xmlns:ns2='com/ejie/detailInfo/generic/xml' xmlns='com/ejie/detailInfo/solicaperturas/xml'>",
					"<detailInfo xmlns=\"com/ejie/detailInfo/aperturassoltel/xml\">");

			xmlSolicitud = xmlSolicitud
					.replaceFirst("<detailInfo>", "<detailInfo><![CDATA[")
					.replaceFirst("</detailInfo>", "</detailInfo>]]>");

			// parseamos el xml como objeto ejgvdocument
			EjgvDocument ejgvDocument = null;
			ejgvDocument = (EjgvDocument) new MessageParserSax<EjgvDocument>(
					EjgvDocument.class.getPackage().getName(),
					ConstantesPlateaTramitacion.NAMESPACE_PLATEA_GENERIC)
							.parse(xmlSolicitud);

			// obtenemos el detail info
			String detailInfo = ejgvDocument.getBody().getDetailInfo();

			ManejadorTareas manejadorTareas = this
					.obtenerManejadorTareas(contextSubmission.getProcedureID());

			// creamos el expediente en base de datos
			manejadorTareas.crearExpediente(detailInfo, contextSubmission);

			// creamos manualmente el trámite de apertura para poder asociar los
			// documentos.
			// Cuando recibamos el evento de tarea de apertura sugerida, habrá
			// que
			// tener en cuenta que el trámite ya estará creado
			Long idTramite = manejadorTareas
					.generarYObtenerIdTramiteApertura(contextSubmission);

			// almacenamos los documentos de la solicitud
			manejadorTareas.guardarDocumentosSolicitud(
					contextSubmission.getDocumentsEvent(),
					contextSubmission.getRegistryTimestamp(), idTramite);
		} catch (AB04BException e) {
			throw e;

		} catch (Exception e) {
			throw new AB04BException(e, e.getMessage());
		}

	}

	/**
	 * Obtener manejador tareas.
	 * 
	 * procedureId String ManejadorTareas
	 * 
	 * @param procedureId
	 *            the procedure id
	 * @return the manejador tareas
	 */
	private ManejadorTareas obtenerManejadorTareas(String procedureId) {

		if (Utilities.getInstance().obtenerProcedureIdApertura()
				.equals(procedureId)) {
			return this.manejadorTareaAperturas;
		} else if (Utilities.getInstance().obtenerProcedureIdOs2()
				.equals(procedureId)) {
			return this.manejadorTareaOS2;
		} else if (Utilities.getInstance().obtenerProcedureIdOs3()
				.equals(procedureId)) {
			return this.manejadorTareaOS3;
		}
		return null;
	}

	/**
	 * Devuelve el primer documento encontrado del tipo indicado. Si no existe
	 * ninguno, devuelve null
	 * 
	 * listaDocumentos List<DocumentEvent> tipo String DocumentEvent
	 * 
	 * @param listaDocumentos
	 *            the lista documentos
	 * @param tipo
	 *            the tipo
	 * @return the document event
	 */
	private DocumentEvent buscarDocumentoPorTipo(
			List<DocumentEvent> listaDocumentos, String tipo) {

		for (DocumentEvent document : listaDocumentos) {
			if (tipo.equals(document.getDocumentType())) {
				return document;
			}
		}
		return null;
	}

	/**
	 * Extrae el xml de la solicitud del ejgv document que se pasa como
	 * parámetro.
	 * 
	 * ejgvdocument el EJGV Document el xml de la solicitud
	 * 
	 * @param ejgvdocument
	 *            the ejgvdocument
	 * @return the xml from ejgv document
	 */
	private String getXmlFromEjgvDocument(String ejgvdocument) {
		return ejgvdocument.split("<!-- ejgvDocument")[1]
				.split("ejgvDocument -->")[0];
	}

	/**
	 * Gestionar solicitud presencial.
	 * 
	 * contextSubmission ContextSubmissionEvent
	 * 
	 * @param contextSubmission
	 *            the context submission
	 * @throws AB04BException
	 *             the AB 04 B exception
	 */
	public void gestionarSolicitudPresencial(
			ContextSubmissionEvent contextSubmission) throws AB04BException {
		try {

			ManejadorTareas manejadorTareas = this
					.obtenerManejadorTareas(contextSubmission.getProcedureID());

			// creamos manualmente el trámite de apertura para poder asociar los
			// documentos.
			// Cuando recibamos el evento de tarea de apertura sugerida, habrá
			// que
			// tener en cuenta que el trámite ya estará creado
			Long idTramite = manejadorTareas
					.generarYObtenerIdTramiteApertura(contextSubmission);

			// // consolidamos el evento y los documentos

			// // almacenamos los documentos temporales
			manejadorTareas.guardarDocumentosSolicitud(
					contextSubmission.getDocumentsEvent(),
					contextSubmission.getRegistryTimestamp(), idTramite);

			if (Utilities.getInstance().obtenerProcedureIdApertura()
					.equals(contextSubmission.getProcedureID())) {
				// consolidamos el evento y los documentos
				this.consolidarEventoService
						.consolidarEventoSolPresencialApertura(
								contextSubmission, idTramite);

			} else if (Utilities.getInstance().obtenerProcedureIdOs2()
					.equals(contextSubmission.getProcedureID())) {

				// consolidamos el evento y los documentos
				this.consolidarEventoService.consolidarEventoSolPresencialOS2(
						contextSubmission, idTramite);

			} else if (Utilities.getInstance().obtenerProcedureIdOs3()
					.equals(contextSubmission.getProcedureID())) {
				this.consolidarEventoService.consolidarEventoSolPresencialOS3(
						contextSubmission, idTramite);
			}

		} catch (Exception e) {
			throw new AB04BException(e, e.getMessage());
		}
	}

	/**
	 * Gestionar aportacion.
	 * 
	 * contextSubmission ContextSubmissionEvent
	 * 
	 * @param contextSubmission
	 *            the context submission
	 * @throws AB04BException
	 *             the AB 04 B exception
	 */

	public void gestionarAportacion(ContextSubmissionEvent contextSubmission)
			throws AB04BException {
		try {

			ManejadorTareas manejadorTareas = this
					.obtenerManejadorTareas(contextSubmission.getProcedureID());

			// creamos manualmente el trámite de apertura para poder asociar los
			// documentos.
			// Cuando recibamos el evento de tarea de apertura sugerida, habrá
			// que
			// tener en cuenta que el trámite ya estará creado
			Long idTramite = manejadorTareas
					.generarYObtenerIdTramiteYTareaAportacion(
							contextSubmission);

			// almacenamos los documentos de la solicitud
			manejadorTareas.guardarDocumentosSolicitud(
					contextSubmission.getDocumentsEvent(),
					contextSubmission.getRegistryTimestamp(), idTramite);
		} catch (Exception e) {
			throw new AB04BException(e, e.getMessage());
		}
	}

	/**
	 * Gestionar aportacion presencial.
	 * 
	 * contextSubmission ContextSubmissionEvent
	 * 
	 * @param contextSubmission
	 *            the context submission
	 * @throws AB04BException
	 *             the AB 04 B exception
	 */

	public void gestionarAportacionPresencial(
			ContextSubmissionEvent contextSubmission) throws AB04BException {
		try {

			ManejadorTareas manejadorTareas = this
					.obtenerManejadorTareas(contextSubmission.getProcedureID());

			// creamos manualmente el trámite de apertura para poder asociar los
			// documentos.
			// Cuando recibamos el evento de tarea de apertura sugerida, habrá
			// que
			// tener en cuenta que el trámite ya estará creado
			Long idTramite = manejadorTareas
					.generarYObtenerIdTramiteYTareaAportacion(
							contextSubmission);

			// almacenamos los documentos de la solicitud
			manejadorTareas.guardarDocumentosSolicitud(
					contextSubmission.getDocumentsEvent(),
					contextSubmission.getRegistryTimestamp(), idTramite);

			// consolidamos el evento y los documentos

			if (Utilities.getInstance().obtenerProcedureIdApertura()
					.equals(contextSubmission.getProcedureID())) {

				// consolidamos el evento y los documentos
				this.consolidarEventoService
						.consolidarEventoSolPresencialApertura(
								contextSubmission, idTramite);

			} else if (Utilities.getInstance().obtenerProcedureIdOs2()
					.equals(contextSubmission.getProcedureID())) {

				// consolidamos el evento y los documentos
				this.consolidarEventoService.consolidarEventoSolPresencialOS2(
						contextSubmission, idTramite);

			} else if (Utilities.getInstance().obtenerProcedureIdOs3()
					.equals(contextSubmission.getProcedureID())) {
				this.consolidarEventoService.consolidarEventoSolPresencialOS3(
						contextSubmission, idTramite);
			}
		} catch (Exception e) {
			throw new AB04BException(e, e.getMessage());
		}
	}
}
