package com.ejie.ad74a.service.tramitacion;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.ejie.ad74a.dao.ExpedientesDao;
import com.ejie.ad74a.dao.MaestroTareasDao;
import com.ejie.ad74a.dao.TareasTramiteDao;
import com.ejie.ad74a.dao.TramitesExpedienteDao;
import com.ejie.ad74a.exceptions.ConstantesCodeError;
import com.ejie.ad74a.exceptions.ManagerErrors;
import com.ejie.ad74a.jms.util.JMSHelper;
import com.ejie.ad74a.model.BandejaPapel0;
import com.ejie.ad74a.model.BandejaTelematica;
import com.ejie.ad74a.model.Expedientes;
import com.ejie.ad74a.model.MaestroTareas;
import com.ejie.ad74a.model.MaestroTramites;
import com.ejie.ad74a.model.TareasTramite;
import com.ejie.ad74a.model.TramitesExpediente;
import com.ejie.ad74a.tareas.service.TareaComunicacionInformeService;
import com.ejie.ad74a.tareas.service.TareaEstudioService;
import com.ejie.ad74a.tareas.service.TareasUtils;
import com.ejie.ad74a.util.comun.UtilSeguridad;
import com.ejie.ad74a.util.comun.Utilidades;
import com.ejie.ad74a.util.comun.UtilidadesFecha;
import com.ejie.ad74a.util.constantes.Constantes;
import com.ejie.ad74a.util.constantes.EstadosExpedienteEnum;
import com.ejie.ad74a.util.constantes.TareasEnum;
import com.ejie.ad74a.util.constantes.TipoTramiteExpediente;
import com.ejie.ad74a.util.constantes.TramitesEnum;
import com.ejie.ad74a.ws.client.platea.model.task.Task;
import com.ejie.ad74a.ws.client.platea.service.PlateaService;
import com.ejie.ad74a.ws.client.platea.tareasTramitacion.TBoolean;
import com.ejie.ad74a.ws.client.platea.tareasTramitacion.TMessage;
import com.ejie.ad74a.ws.client.platea.tareasTramitacion.TMessageList;
import com.ejie.ad74a.ws.client.platea.tareasTramitacion.TMessageStatus;
import com.ejie.ad74a.ws.client.platea.tareasTramitacion.TMessageTipology;
import com.ejie.ad74a.ws.client.platea.tareasTramitacion.TNiaType;
import com.ejie.ad74a.ws.client.platea.tareasTramitacion.TPersonIDName;
import com.ejie.ad74a.ws.client.platea.tareasTramitacion.TStringList;
import com.ejie.ad74a.ws.client.platea.tareasTramitacion.TStudyActionType;
import com.ejie.ad74a.ws.client.platea.tareasTramitacion.TTask;
import com.ejie.ad74a.ws.client.platea.tareasTramitacion.TTaskType;
import com.ejie.ad74a.ws.client.platea.tareasTramitacion.TWait;
import com.ejie.ad74a.ws.client.platea.tareasTramitacion.TWaitList;
import com.ejie.ad74a.ws.client.platea.tareasTramitacion.TWaitType;

/**
 * Gestión de los procesos comunes a los trámites y tareas
 * 
 * @author IBERMATICA
 */

@Service(value = "tramitacionService")
public class TramitacionServiceImpl implements TramitacionService {

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

	@Autowired
	private TramitesExpedienteDao tramitesExpedienteDao;

	@Autowired
	private TareasTramiteDao tareasTramiteDao;

	@Autowired
	private MaestroTareasDao maestroTareasDao;

	@Autowired
	private ExpedientesDao expedientesDao;

	@Autowired
	private PlateaService plateaService;

	@Autowired
	private TareaEstudioService tareaEstudioService;

	@Autowired
	private TareaComunicacionInformeService tareaComunicacionInformeService;

	/**
	 * Proceso a ejecutar al sugerirse una tarea (una vez recibido el evento de
	 * tarea sugerida). Crear el registro del trámite y el registro de la tarea en
	 * BD
	 */
	@Override
	public void tratamientoTramiteTareaSugerida(Task task, String numRegistro, Expedientes expediente)
			throws Throwable {
		TramitacionServiceImpl.logger
				.info("TramitacionServiceImpl.tratamientoTramiteTareaSugerida -" + task.getTaskID() + "- Inicio");
		TramitacionServiceImpl.logger
				.info("TramitacionServiceImpl.tratamientoTramiteTareaSugerida - folderId: " + task.getFolderID());

		// Crear Tramite
		TramitesExpediente tramiteExp = this.createTramite(expediente, TareasEnum.getEnumByTaskId(task.getTaskID()),
				UtilidadesFecha.getFechaSistema(Constantes.DATE_FORMAT_PLATEA_XML_EVENTS),
				Constantes.EstadoTramitacion.ESTADO_TRAMITE_PENDIENTE, task.getSenderID(), Boolean.TRUE);

		// Crear Tarea
		TareasTramite tarea = this.createTarea(task.getMailboxTaskID(), tramiteExp,
				TareasEnum.getEnumByTaskId(task.getTaskID()), Constantes.EstadoTramitacion.ESTADO_TAREA_ABIERTA,
				numRegistro, UtilidadesFecha.parsearFechaPlatea(task.getDoTimestamp()), task.getSenderID());

		List<TareasTramite> listTareasTramite = new ArrayList<TareasTramite>();
		listTareasTramite.add(tarea);
		tramiteExp.setTareasTramites(listTareasTramite);

		TramitacionServiceImpl.logger
				.info("TramitacionServiceImpl.tratamientoTramiteTareaSugerida -" + task.getTaskID() + "- Fin");
	}

	/**
	 * Proceso a ejecutar al sugerirse una tarea (una vez recibido el evento de
	 * tarea sugerida). Crear el registro del trámite y el registro de la tarea en
	 * BD
	 */
	@Override
	public void tratamientoTramiteTareaAutomaticaSugerida(Task task, String numRegistro, Expedientes expediente)
			throws Throwable {
		TramitacionServiceImpl.logger.info(
				"TramitacionServiceImpl.tratamientoTramiteTareaAutomaticaSugerida -" + task.getTaskID() + "- Inicio");
		TramitacionServiceImpl.logger.info(
				"TramitacionServiceImpl.tratamientoTramiteTareaAutomaticaSugerida - folderId: " + task.getFolderID());

		// Crear Tramite
		TramitesExpediente tramiteExp = this.createTramite(expediente, TareasEnum.getEnumByTaskId(task.getTaskID()),
				UtilidadesFecha.getFechaSistema(Constantes.DATE_FORMAT_PLATEA_XML_EVENTS),
				Constantes.EstadoTramitacion.ESTADO_TRAMITE_PENDIENTE,
				com.ejie.ad74a.constantes.Constantes.COD_APLICACION, Boolean.TRUE);

		// Crear Tarea
		TareasTramite tarea = this.createTarea(task.getMailboxTaskID(), tramiteExp,
				TareasEnum.getEnumByTaskId(task.getTaskID()), Constantes.EstadoTramitacion.ESTADO_TAREA_ABIERTA,
				numRegistro, UtilidadesFecha.parsearFechaPlatea(task.getDoTimestamp()),
				com.ejie.ad74a.constantes.Constantes.COD_APLICACION);

		List<TareasTramite> listTareasTramite = new ArrayList<TareasTramite>();
		listTareasTramite.add(tarea);
		tramiteExp.setTareasTramites(listTareasTramite);

		TramitacionServiceImpl.logger.info(
				"TramitacionServiceImpl.tratamientoTramiteTareaAutomaticaSugerida -" + task.getTaskID() + "- Fin");
	}

	/**
	 * Proceso a ejecutar al ejecutarse una tarea (una vez recibido el evento de
	 * tarea ejecutada). Actualiza el registro del trámite y el registro de la tarea
	 * en BD
	 */
	@Override
	public void tratamientoTramiteTareaEjecutada(Task task, Boolean automatica) throws Throwable {
		TramitacionServiceImpl.logger
				.info("TramitacionServiceImpl.tratamientoTramiteTareaEjecutada -" + task.getTaskID() + "- Inicio");

		try {
			// recuperamos la tarea a tratar
			TareasTramite tBuscar = getTareaByTaskGUID(task.getMailboxTaskID());

			tBuscar.setfFin11(UtilidadesFecha.parsearFechaPlatea(task.getDoTimestamp()));
			if (null != tBuscar.getfFin11()) {
				// tiene que llevar una fecha fin
				tBuscar.setfFin11(UtilidadesFecha.getFechaSistema());
			}
			tBuscar.setIdEstado11(Constantes.EstadoTramitacion.ESTADO_TAREA_FINALIZADA);
			tBuscar.setUsuModif11(task.getSenderID());
			// tBuscar.setIdTareaREE41(task.getTaskGUIDREE());

			/*-
			 * TAREAS Notificación: Actualizamos datos de registro y notificación y el OID de la Notificación. 
			 * [jbhg] Se agregan aquí las tareas de COMUNICACION, ya que también cuentan con un NotificationID que puede usarse en los servicios de X43Notificaciones.
			 */
			if (task.getTaskTypeID().equals(TTaskType.NOTIFICACION.value())
					|| task.getTaskTypeID().equals(TTaskType.COMUNICACION.value())) {
				tBuscar.setNumRegistro11(task.getTaskInfo().getNotifyTaskData().getRegistryNumber());
				tBuscar.setfRegistro11(UtilidadesFecha
						.parsearFechaPlatea(task.getTaskInfo().getNotifyTaskData().getRegistryTimestamp()));

				tBuscar.setfNotificacion11(UtilidadesFecha
						.parsearFechaPlatea(task.getTaskInfo().getNotifyTaskData().getRegistryTimestamp()));

				// ** OID de la notificación ** //
				if (task.getTaskInfo().getNotifyTaskData().getNotificationID() != null) {
					tBuscar.setIdNotificacion11(task.getTaskInfo().getNotifyTaskData().getNotificationID());
				}
			}
			// ** TAREAS ACUSE: Actualizamos fecha de acuse
			if (task.getTaskTypeID().equals(TTaskType.RECINOTI.value())) {
				tBuscar.setfAcuse11(UtilidadesFecha.parsearFechaPlatea(
						task.getTaskInfo().getDeliveredNotificationTaskData().getReceptionTimestamp()));

				// ** OID de la notificación ** //
				if (task.getTaskInfo().getDeliveredNotificationTaskData().getNotificationID() != null) {
					tBuscar.setIdNotificacion11(
							task.getTaskInfo().getDeliveredNotificationTaskData().getNotificationID());
				}
			}

			// ** Actualizamos tarea en BD **/
			this.tareasTramiteDao.update(tBuscar);

			// ** Si es la última tarea del trámite. FINALIZAR Trámite ** //
			if (TareasEnum.getEnumByTaskId(task.getTaskID()).isUltimaTarea()) {
				TramitesExpediente tramiteExp = new TramitesExpediente();
				List<TareasTramite> listTareasTramite = new ArrayList<TareasTramite>();
				listTareasTramite.add(new TareasTramite(tBuscar.getIdTareaTram11()));
				tramiteExp.setTareasTramites(listTareasTramite);
				List<TramitesExpediente> listaTramites = this.tramitesExpedienteDao.getTramiteByCodTarea(tramiteExp);
				tramiteExp = listaTramites.get(0);
				tramiteExp.setfRealizacion10(UtilidadesFecha.getFechaSistema());
				tramiteExp.setIdEstado10(Constantes.EstadoTramitacion.ESTADO_TRAMITE_FINALIZADO);
				if (Boolean.TRUE.equals(automatica)) {
					tramiteExp.setUsuModif10(com.ejie.ad74a.constantes.Constantes.COD_APLICACION);
				} else {
					tramiteExp.setUsuModif10(task.getSenderID());
				}
				tramiteExp.setfModif10(UtilidadesFecha.getFechaSistema());

				// tramiteExp.setIdTramiteREE40(task.getProceedingGUID());

				this.tramitesExpedienteDao.update(tramiteExp);
			}

		} catch (Exception e) {
			TramitacionServiceImpl.logger.info("TramitacionServiceImpl.tratamientoTramiteTareaEjecutada -"
					+ task.getTaskID() + "- Error: " + e.getStackTrace());
			ManagerErrors.manageException(e, ConstantesCodeError.MENSAJE_ERROR_TRATAR_TAREA_EJECUTADA, null,
					ConstantesCodeError.CODE_ERROR_TRATAR_TAREA_EJECUTADA, null);
		}
		TramitacionServiceImpl.logger
				.info("TramitacionServiceImpl.tratamientoTramiteTareaEjecutada -" + task.getTaskID() + "- Fin");

	}

	@Override
	public void tratamientoTramiteTareaCancelada(Task task) throws Throwable {
		TramitacionServiceImpl.logger.info("TramitacionServiceImpl.tratamientoTramiteTareaCancelada -"
				+ task.getTaskID() + "-" + task.getMailboxTaskID() + "- Inicio");
		TramitacionServiceImpl.logger
				.info("TramitacionServiceImpl.tratamientoTramiteTareaCancelada - folderId: " + task.getFolderID());

		// ** TAREA ** //
		TareasTramite tarea = this.getTareaByTaskGUID(task.getMailboxTaskID());
		tarea.setfFin11(UtilidadesFecha.getFechaSistema());
		tarea.setfFin11(UtilidadesFecha.getFechaSistema());

		tarea.setIdEstado11(Constantes.EstadoTramitacion.ESTADO_TAREA_CANCELADA);
		tarea.setUsuModif11(com.ejie.ad74a.constantes.Constantes.COD_APLICACION);

		this.tareasTramiteDao.update(tarea);

		// ** TRAMITE ** //
		TramitesExpediente tramiteExp = new TramitesExpediente();
		List<TareasTramite> listTareasTramite = new ArrayList<TareasTramite>();
		listTareasTramite.add(new TareasTramite(tarea.getIdTareaTram11()));
		tramiteExp.setTareasTramites(listTareasTramite);
		List<TramitesExpediente> listaTramites = this.tramitesExpedienteDao.getTramiteByCodTarea(tramiteExp);
		tramiteExp = listaTramites.get(0);
		tramiteExp.setfRealizacion10(UtilidadesFecha.getFechaSistema());
		tramiteExp.setIdEstado10(Constantes.EstadoTramitacion.ESTADO_TRAMITE_CANCELADO);
		tramiteExp.setUsuModif10(com.ejie.ad74a.constantes.Constantes.COD_APLICACION);
		tramiteExp.setfModif10(UtilidadesFecha.getFechaSistema());

		this.tramitesExpedienteDao.update(tramiteExp);

		TramitacionServiceImpl.logger.info("TramitacionServiceImpl.tratamientoTramiteTareaSugerida -" + task.getTaskID()
				+ "-" + task.getMailboxTaskID() + "- Fin");
	}

	@Override
	public TramitesExpediente tratamientoTramiteBandeja(BandejaTelematica bandeja, String idTareaFicticia,
			TareasEnum tareaE, String estado) throws Throwable {

		TramitacionServiceImpl.logger.info("TramitacionServiceImpl.tratamientoTramiteBandeja - Inicio");

		Expedientes expediente = new Expedientes();
		expediente.setIdExpediente00(bandeja.getExpediente().getIdExpediente00());
		expediente = this.expedientesDao.find(expediente);

		TramitesExpediente tramiteExp = this.createTramite(expediente, tareaE,
				UtilidadesFecha.getFechaSistema(Constantes.DATE_FORMAT_PLATEA_XML_EVENTS), estado,
				com.ejie.ad74a.constantes.Constantes.COD_APLICACION, Boolean.TRUE);

		TareasTramite tarea = this.createTarea(idTareaFicticia, tramiteExp, tareaE, estado, bandeja.getNumRegistro14(),
				bandeja.getfRegistro14(), com.ejie.ad74a.constantes.Constantes.COD_APLICACION);

		List<TareasTramite> listTareasTramite = new ArrayList<TareasTramite>();
		listTareasTramite.add(tarea);
		tramiteExp.setTareasTramites(listTareasTramite);

		TramitacionServiceImpl.logger.info("TramitacionServiceImpl.tratamientoTramiteBandeja - Fin");

		return tramiteExp;
	}

	@Override
	public TramitesExpediente tratamientoTramiteBandejaPapel0(BandejaPapel0 bandeja, String idTareaFicticia,
			TareasEnum tareaE, String estado) throws Throwable {

		TramitacionServiceImpl.logger.info("TramitacionServiceImpl.tratamientoTramiteBandejaPapleo0 - Inicio");

		Expedientes expediente = new Expedientes();
		expediente.setIdExpediente00(bandeja.getExpediente().getIdExpediente00());
		expediente = this.expedientesDao.find(expediente);

		TramitesExpediente tramiteExp = this.createTramite(expediente, tareaE,
				UtilidadesFecha.getFechaSistema(Constantes.DATE_FORMAT_PLATEA_XML_EVENTS), estado,
				com.ejie.ad74a.constantes.Constantes.COD_APLICACION, Boolean.TRUE);

		TareasTramite tarea = this.createTarea(idTareaFicticia, tramiteExp, tareaE, estado, bandeja.getNumRegistro12(),
				bandeja.getfRegistro12(), com.ejie.ad74a.constantes.Constantes.COD_APLICACION);

		List<TareasTramite> listTareasTramite = new ArrayList<TareasTramite>();
		listTareasTramite.add(tarea);
		tramiteExp.setTareasTramites(listTareasTramite);

		TramitacionServiceImpl.logger.info("TramitacionServiceImpl.tratamientoTramiteBandejaPapleo0 - Fin");

		return tramiteExp;
	}

	/**
	 * Realiza la sugerencia de una tarea no partiendo de otra tarea.
	 * 
	 */
	@Override
	public void sugerirTarea(Expedientes expediente, TareasEnum tarea) throws Throwable {
		TramitacionServiceImpl.logger.info("TramitacionServiceImpl.sugerirTarea - Inicio");

		TBoolean resTB = null;
		try {
			// ** Comprobación de que NO exista ya una tarea del mismo tipo SUGERIDA ** //
			TMessageList tMessageList = this.plateaService.getGATTask(expediente.getFolderId00(),
					TMessageStatus.PENDING, TMessageTipology.TRAMITACION);

			boolean encontrada = false;
			for (int t = 0; t < tMessageList.getMessage().size() && !encontrada; t++) {
				// Recuperar propiedades del mensaje -Datos de tarea
				Map<String, Object> mapProperties = JMSHelper
						.parsearMensajeJms(tMessageList.getMessage().get(t).getMessage());

				// ************************************************* //
				if (tarea.getTaskId().equalsIgnoreCase((String) mapProperties.get("taskID"))) {
					encontrada = true;
				}
			}

			// ** Se sugiere si no está SUGERIDA. No encontrada ** //
			if (!encontrada) {
				TPersonIDName senderID = UtilSeguridad.getSenderTramitador();

				TStringList mailboxes = new TStringList();
				mailboxes.getItem().add(0, Constantes.PLATEA_MAILBOX_ADMIN);

				// Preparamos la tarea
				resTB = this.plateaService.prepareNewTask(expediente.getIdProcedimiento00(), expediente.getFolderId00(),
						tarea.getProceedingId(), tarea.getTaskId(), senderID, mailboxes);

				TramitacionServiceImpl.logger.info("TramitacionServiceImpl.sugerirTarea - " + tarea.getTaskId() + "-"
						+ expediente.getFolderId00() + "=" + resTB.toString() + " - Fin");

			} else {
				TramitacionServiceImpl.logger
						.info("TramitacionServiceImpl.sugerirTarea -NO se sugiere por existir ya una- Fin ");
			}
		} catch (Throwable e) {
			ManagerErrors.manageException(e, ConstantesCodeError.MENSAJE_ERROR_SUGERIR_TAREA, null,
					ConstantesCodeError.CODE_ERROR_SUGERIR_TAREA, null);
		}

		TramitacionServiceImpl.logger.info("TramitacionServiceImpl.sugerirTarea - Fin");
	}

	/**
	 * Realiza la sugerencia de una tarea en base el tipoTramite y tipo tarea
	 * recibidos El objeto Task contiene la tarea ejecutada que provoca la
	 * sugerencia. La sugerencia viene de la ejecucion de otra tarea
	 * 
	 */
	@Override
	public void sugerirTarea(Task task, TareasEnum tarea) throws Throwable {
		TramitacionServiceImpl.logger.info("TramitacionServiceImpl.sugerirTarea - Inicio");

		this.sugerirTarea(task.getFolderID(), task.getProcedureID(), tarea, task.getSenderID(), task.getSenderName());

		TramitacionServiceImpl.logger.info("TramitacionServiceImpl.sugerirTarea - Fin");
	}

	/**
	 * Realiza la sugerencia de una tarea en base el tipoTramite y tipo tarea
	 * recibidos El objeto Task contiene la tarea ejecutada que provoca la
	 * sugerencia.
	 * 
	 * @param folderId        String Id carpeta electrónica
	 * @param idProcedimiento String Id del procedimiento
	 * @param tipoTramite     String tipo Trámite
	 * @param tipoTarea       String tipo de taera
	 * @param senderId        String senderId
	 * @param senderName      String senderName
	 * 
	 * @throws Throwable
	 */
	private void sugerirTarea(String folderId, String idProcedimiento, TareasEnum tarea, String senderId,
			String senderName) throws Throwable {
		TramitacionServiceImpl.logger
				.info("TramitacionServiceImpl.sugerirTarea - " + tarea.getTaskId() + "-" + folderId + " - Inicio");
		TBoolean resTB = null;
		try {
			// ** Comprobación de que NO exista ya una tarea del mismo tipo SUGERIDA ** //
			TMessageList tMessageList = this.plateaService.getGATTask(folderId, TMessageStatus.PENDING,
					TMessageTipology.TRAMITACION);

			boolean encontrada = false;
			for (int t = 0; t < tMessageList.getMessage().size() && !encontrada; t++) {
				// Recuperar propiedades del mensaje -Datos de tarea
				Map<String, Object> mapProperties = JMSHelper
						.parsearMensajeJms(tMessageList.getMessage().get(t).getMessage());

				// ************************************************* //
				if (tarea.getTaskId().equalsIgnoreCase((String) mapProperties.get("taskID"))) {
					encontrada = true;
				}
			}

			// ** Se sugiere si no está SUGERIDA. No encontrada ** //
			if (!encontrada) {
				TPersonIDName senderID = new TPersonIDName();

				TStringList mailboxes = new TStringList();

				Expedientes expediente = new Expedientes();
				expediente.setFolderId00(folderId);
				List<Expedientes> listaExpedientes = this.expedientesDao.findAll(expediente, null);

				if (null != listaExpedientes && listaExpedientes.size() > 0) {
					mailboxes.getItem().add(0, Constantes.PLATEA_MAILBOX_ADMIN);
					// se pone con tramitadaor el tecnico del expediente
					senderID.setType(TNiaType.NO_ID);
					senderID.setID(listaExpedientes.get(0).getTecnicoExpediente00());
					senderID.setName(listaExpedientes.get(0).getTecnicoExpediente00());
				} else {
					mailboxes.getItem().add(0, Constantes.PLATEA_MAILBOX_ADMIN);
					senderID.setID(senderId);
					senderID.setType(TNiaType.NO_ID);
					senderID.setName(senderName);
				}

				// Preparamos la tarea
				resTB = this.plateaService.prepareNewTask(idProcedimiento, folderId, tarea.getProceedingId(),
						tarea.getTaskId(), senderID, mailboxes);

				TramitacionServiceImpl.logger.info("TramitacionServiceImpl.sugerirTarea - " + tarea.getTaskId() + "-"
						+ folderId + "=" + resTB.toString() + " - Fin");

			} else {
				TramitacionServiceImpl.logger
						.info("TramitacionServiceImpl.sugerirTarea -NO se sugiere por existir ya una- Fin ");
			}
		} catch (Throwable e) {
			ManagerErrors.manageException(e, ConstantesCodeError.MENSAJE_ERROR_SUGERIR_TAREA, null,
					ConstantesCodeError.CODE_ERROR_SUGERIR_TAREA, null);
		}

	}

	/**
	 * Crea tramite y tarea para tramites ficticios que se quieran registrar, como
	 * la recepcion de la solicitud
	 * 
	 * @param expediente    Expedientes
	 * @param idTarea       String
	 * @param tareaE        TareasEnum
	 * @param estadoTramite String 1-Abierta 2-Finalizada 3-Cancelada 4-Anulada
	 * @param estadoTarea   String 1-Abierta 2-Finalizada 3-Cancelada 4-Anulada
	 * @param expediente    Expedientes
	 */
	public TramitesExpediente createNoPlateaTramite(Expedientes expediente, String idTarea, TareasEnum tareaE,
			String estadoTramite, String estadoTarea, String numRegistro, Date fechaRegistro) throws Throwable {

		TramitacionServiceImpl.logger
				.info("TramitacionServiceImpl.createNoPlateaTramite - Inicio Expediente: " + expediente.toString());

		// Crear Trámite
		TramitesExpediente tramiteExp = this.createTramite(expediente, tareaE,
				UtilidadesFecha.getFechaSistema(Constantes.DATE_FORMAT_PLATEA_XML_EVENTS), estadoTramite,
				com.ejie.ad74a.constantes.Constantes.COD_APLICACION, Boolean.FALSE);

		// Crear Tarea
		TareasTramite tarea = this.createTarea(idTarea, tramiteExp, tareaE, estadoTarea, numRegistro, fechaRegistro,
				com.ejie.ad74a.constantes.Constantes.COD_APLICACION);

		List<TareasTramite> listTareasTramite = new ArrayList<TareasTramite>();
		listTareasTramite.add(tarea);
		tramiteExp.setTareasTramites(listTareasTramite);

		TramitacionServiceImpl.logger.info("TramitacionServiceImpl.createNoPlateaTramite - Fin");
		return tramiteExp;
	}

	/**
	 * Crea un tramite recibido de platea. Mira el tramite al que pertenece la
	 * tarea, si hay uno creado sin finalizar, no lo vuelve a crear
	 * 
	 * @param expediente Expedientes
	 * @param tarea      TareasEnum
	 * @param fechaReg   String
	 * @param finalizado boolean
	 * @param tramitador String
	 * @return
	 */
	private TramitesExpediente createTramite(Expedientes expediente, TareasEnum tarea, String fechaReg,
			String estadoTramite, String tramitador, Boolean esTramitePlatea) {

		TramitacionServiceImpl.logger.info("TramitacionServiceImpl.createTramite - Inicio");

		// recuperamos el cod de tramite a traves del id de la tarea en la tabla 39
		MaestroTareas tareaM = new MaestroTareas();
		tareaM.setIdTarea38(tarea.getId());
		TramitacionServiceImpl.logger.info("TramitacionServiceImpl.createTramite -maestroTareasDao.findAll IM ");
		List<MaestroTareas> listaTareasM = this.maestroTareasDao.findAll(tareaM, null);
		Long codTramite = listaTareasM.get(0).getMaestroTramites().getIdTramite37();

		TramitesExpediente tramiteExp = new TramitesExpediente();
		tramiteExp.setIdExpediente10(expediente.getIdExpediente00());

		MaestroTramites tramiteM = new MaestroTramites();
		tramiteM.setIdTramite37(codTramite);
		tramiteExp.setMaestroTramites(tramiteM);

		// Si se trata de un estudio de documentación grabamos el tipo de estudio segun
		// el estado del
		// expediente (Si es estudio de Documentacion por Apertura el expediente se
		// encuentra en Pendiente de apertura)
		if (TramitesEnum.ESTUDIO_DOCUMENTACION.getId().equals(codTramite)
				&& EstadosExpedienteEnum.PEND_APERTURA.getId().equals(expediente.getEstados().getIdEstado30())) {
			tramiteExp.setTipoEstudioDoc10(TipoTramiteExpediente.tipoEstudioDoc10.ESTUDIO_DOCUMENTACION.getId());
		} else if (TramitesEnum.ESTUDIO_DOCUMENTACION.getId().equals(codTramite)
				&& tramiteExp.getTipoEstudioDoc10() == null) {
			// Cuando es un estudio documentación por desistimiento viene grabado ya

			tramiteExp.setTipoEstudioDoc10(
					TipoTramiteExpediente.tipoEstudioDoc10.ESTUDIO_DOCUMENTACION_APORTACION_SUBSANACION.getId());
		}
		boolean encontrado = false;
		int intentos = 0;
		do {
			try {
				TramitacionServiceImpl.logger
						.info("TramitacionServiceImpl.createTramite - tramitesExpedienteDao.FindAll IM");
				TimeUnit.SECONDS.sleep(3);
				List<TramitesExpediente> listaTramites = this.tramitesExpedienteDao.findAll(tramiteExp, null);

				if (!listaTramites.isEmpty()) {
					// ** Recorremos para comprobar si hay algún trámite SIN FINALIZAR ** //

					for (int t = 0; t < listaTramites.size() && !encontrado; t++) {
						if (listaTramites.get(t).getIdEstado10()
								.equalsIgnoreCase(Constantes.EstadoTramitacion.ESTADO_TRAMITE_PENDIENTE)) {
							// Encontrado
							tramiteExp = listaTramites.get(t);
							encontrado = true;
							break;
						} else if (TramitesEnum.RECEPCION_SOL_APERTURA.getId().equals(codTramite)) {
							/*
							 * Puede darse el caso en los inicios de oficio, que entre el addAdminAplication
							 * y la actualización del folderID llegue la request, dando error y programando
							 * el relanzado para 5min despues. Si se cierra el expediente en esos 5min y se
							 * lanza la retramitación de la request, deja 2 tramites de apertura, uno de
							 * ellos sin cerrar en un expediente cerrado. Por lo que en esos casos usaremos
							 * el tramite de apertura para asignar la tarea
							 */
							// Encontrado
							tramiteExp = listaTramites.get(t);
							encontrado = true;
						}
					}
				}
			} catch (InterruptedException e) {
				TramitacionServiceImpl.logger.info(
						"TramitacionServiceImpl.createTramite - tramitesExpedienteDao. error reintentando encontrar el tramite. Intento: {}/3",
						intentos);
			}
			intentos++;
			// Se ponen reintentos porque se estan ejecutando la request y la apertura a la
			// vez y por las transaccionalidades no encuentran el tramite de apertura (Sólo
			// ocurre con las papel0 y puede que inicio de oficio)
			// Hay que controlar que sólo lo reintente con la tarea de platea y no con la
			// ficticia para que no se queden ambas reintentando
		} while (intentos < 3 && !encontrado && TramitesEnum.RECEPCION_SOL_APERTURA.getId().equals(codTramite)
				&& Boolean.TRUE.equals(esTramitePlatea));

		// ** NO existen Trámites de ese tipo, se DA de alta ** //
		if (!encontrado) {
			tramiteExp.setIdEstado10(estadoTramite);
			tramiteExp.setfInicio10(UtilidadesFecha.parsearFechaPlatea(fechaReg));
			if (estadoTramite == Constantes.EstadoTramitacion.ESTADO_TRAMITE_FINALIZADO) {
				tramiteExp.setfRealizacion10(UtilidadesFecha.parsearFechaPlatea(fechaReg));
			}
			TramitacionServiceImpl.logger.info("TramitacionServiceImpl.createTramite - tramitesExpedienteDao.add IM");
			tramiteExp.setUsuAlta10(tramitador);
			tramiteExp = this.tramitesExpedienteDao.add(tramiteExp);
		}

		TramitacionServiceImpl.logger.info("TramitacionServiceImpl.createTramite - Fin");
		return tramiteExp;
	}

	/**
	 * Crea una tarea en base a los parametros recibidos
	 * 
	 * @param taskId
	 * @param tramite
	 * @param tarea
	 * @param finalizado
	 * @param numRegistro
	 * @param fechaRegistro
	 * @param tramitador
	 * @return
	 */
	private TareasTramite createTarea(String taskId, TramitesExpediente tramite, TareasEnum tarea, String estadoTarea,
			String numRegistro, Date fechaRegistro, String tramitador) {
		TramitacionServiceImpl.logger.info("TramitacionServiceImpl.createTarea - Inicio");

		TareasTramite tareaExp = new TareasTramite();
		tareaExp.setTramitesExpediente(tramite);
		tareaExp.setTaskguid11(taskId);
		/*- Comprobacion de si la tarea ya esta creada, (el evento puede haberse procesado dos veces...) */
		boolean existeTarea = false;
		TramitacionServiceImpl.logger.info("TramitacionServiceImpl.createTramite - tareasTramiteDao.findAll IM");
		List<TareasTramite> listTareas = this.tareasTramiteDao.findAll(tareaExp, null);
		if (CollectionUtils.isNotEmpty(listTareas)) {
			existeTarea = true;
			tareaExp = listTareas.get(0);
		}
		tareaExp.setIdEstado11(estadoTarea);
		if (estadoTarea.equals(Constantes.EstadoTramitacion.ESTADO_TAREA_FINALIZADA)) {
			tareaExp.setfFin11(UtilidadesFecha.getFechaSistema());
		}

		if (existeTarea) {
			tareaExp.setUsuModif11(tramitador);
			tareaExp.setfModif11(UtilidadesFecha.getFechaSistema());
			TramitacionServiceImpl.logger.info("TramitacionServiceImpl.createTarea - tareasTramiteDao.update IM");
			tareaExp = this.tareasTramiteDao.update(tareaExp);
		} else {
			MaestroTareas tareaM = new MaestroTareas();
			tareaM.setIdTarea38(tarea.getId());
			TramitacionServiceImpl.logger.info("TramitacionServiceImpl.createTarea - tareasTramiteDao.findAll IM");
			List<MaestroTareas> listaTareasM = this.maestroTareasDao.findAll(tareaM, null);
			tareaExp.setMaestroTareas(listaTareasM.get(0));
			tareaExp.setfInicio11(UtilidadesFecha.getFechaSistema());
			tareaExp.setUsuAlta11(tramitador);
			tareaExp.setNumRegistro11(numRegistro);
			tareaExp.setfRegistro11(fechaRegistro);
			TramitacionServiceImpl.logger.info("TramitacionServiceImpl.createTarea - tareasTramiteDao.add IM");
			tareaExp = this.tareasTramiteDao.add(tareaExp);
		}
		TramitacionServiceImpl.logger.info("TramitacionServiceImpl.createTarea - Fin");
		return tareaExp;
	}

	/**
	 * Recupera los datos del tipo de parea
	 * 
	 * @param taskGUID Tipo de Tarea
	 * @return TareasTramite
	 */
	private TareasTramite getTareaByTaskGUID(String taskGUID) {
		TramitacionServiceImpl.logger.info("TramitacionServiceImpl.getTareaByTaskId - Inicio: " + taskGUID);
		// recuperamos la tarea a tratar
		TareasTramite tBuscar = new TareasTramite();
		tBuscar.setTaskguid11(taskGUID);
		List<TareasTramite> listaTareas;

		listaTareas = this.tareasTramiteDao.findAll(tBuscar, null);
		if (!listaTareas.isEmpty()) {
			tBuscar = listaTareas.get(0);
		} else {
			int t = 0;
			do {
				try {
					TramitacionServiceImpl.logger
							.info("TramitacionServiceImpl.getTareaByTaskId - Espera 3 segs. " + taskGUID);
					TimeUnit.SECONDS.sleep(3);
				} catch (InterruptedException e) {
					// TODO: handle exception
				}
				listaTareas = this.tareasTramiteDao.findAll(tBuscar, null);
				t++;
			} while (t < 3 && listaTareas.isEmpty());

			// Si ha salido la lista vacía, lanzamos error
			if (listaTareas.isEmpty()) {
				ManagerErrors.manageError("No se puede recuperar la tarea :" + taskGUID);
			}
			// Carga la tarea
			TramitacionServiceImpl.logger
					.info("TramitacionServiceImpl.getTareaByTaskId - Encontrada tarea " + taskGUID);
			tBuscar = listaTareas.get(0);
		}
		TramitacionServiceImpl.logger.info("TramitacionServiceImpl.getTareaByTaskId - Fin");
		return tBuscar;
	}

	/**
	 * Metodo encargado de realizar la finalizacion de una tarea de estudio de un
	 * expediente dado ejecutandola con el estado de finalizacion recibido
	 * 
	 * @param folderId           FolderId del expediente
	 * @param estadoFinalizacion estado para la finalizacion
	 */
	@Override
	public void finalizarTareaEstudio(String folderId, String estadoFinalizacion) throws Throwable {

		TramitacionServiceImpl.logger.info("TramitacionServiceImpl.finalizarTareaEstudio - Inicio: " + folderId
				+ " Estado finalizacion: " + estadoFinalizacion);

		// ** Recuperar la lista de tareas de ESTUDIO** //
		TMessageList lista = this.plateaService.getGATTask(folderId, TMessageStatus.PENDING,
				TMessageTipology.TRAMITACION);

		String taskGUID = "";
		for (TMessage message : lista.getMessage()) {
			if (message.getTaskType().name().equalsIgnoreCase(Constantes.TiposTareaPlatea.PLATEA_ESTUDIO)) {
				taskGUID = message.getTaskGUID();
				break;
			}
		}

		if (!Utilidades.esBlancoNulo(taskGUID)) {
			TTask task = null;
			// ** PREPARAR **//
			task = this.tareaEstudioService.prepararTarea(taskGUID);

			task.getTaskStudy().setAction(TStudyActionType.ACCEPT_REVIEW);
			task.getTaskStudy().setSituationID(estadoFinalizacion);

			task.setSenderID(TareasUtils.getSenderTramitador());

			// ** EJECUTAR**//
			task = this.tareaEstudioService.ejecutarTarea(task);

		}

		TramitacionServiceImpl.logger.info("TramitacionServiceImpl.finalizarTareaEstudio - Fin ");
	}

	/**
	 * Metodo encargado de realizar la finalizacion de una tarea de COMUNICACION de
	 * un expediente dado ejecutandola con el estado de finalizacion recibido
	 * 
	 * @param folderId           FolderId del expediente
	 * @param estadoFinalizacion estado para la finalizacion
	 */
	@Override
	public void finalizarTareaComunicacionInforme(String folderId) throws Throwable {

		TramitacionServiceImpl.logger
				.info("TramitacionServiceImpl.finalizarTareaComunicacionInforme - Inicio: " + folderId);

		// ** Recuperar la lista de tareas de ESTUDIO** //
		TMessageList lista = this.plateaService.getGATTask(folderId, TMessageStatus.PENDING,
				TMessageTipology.TRAMITACION);

		String taskGUID = "";
		for (TMessage message : lista.getMessage()) {
			if (message.getTaskType().name()
					.equalsIgnoreCase(Constantes.TiposTareaPlatea.PLATEA_COMUNICACION_INFORME)) {
				taskGUID = message.getTaskGUID();
				break;
			}
		}

		if (!Utilidades.esBlancoNulo(taskGUID)) {
			TTask task = null;
			// ** PREPARAR **//
			task = this.tareaComunicacionInformeService.prepararTarea(taskGUID);

			task.setSenderID(TareasUtils.getSenderTramitador());

			// ** EJECUTAR**//
			task = this.tareaComunicacionInformeService.ejecutarTarea(task);

		}

		TramitacionServiceImpl.logger.info("TramitacionServiceImpl.finalizarTareaComunicacionInforme - Fin ");
	}

	/**
	 * Finaliza la espera determinada por el tipo de espera para el expediente
	 * recibido
	 * 
	 * @param folderId          Id de la carpeta electronica (folderID)
	 * @param tipoEspera        Identificador del tipo de espera
	 * @param valorFinalizacion Valor con el que se desea finalizar la espera
	 */
	@Override
	public void finalizarEspera(String folderId, TWaitType tipoEspera, String valorFinalizacion) {

		TramitacionServiceImpl.logger.info("TramitacionServiceImpl.finalizarEspera - Inicio: " + folderId
				+ " Valor finalizacion: " + valorFinalizacion);

		// finalizamos esperas pendientes
		TWait tWait = this.getWaitByType(folderId, tipoEspera);
		if (null != tWait) {
			this.plateaService.endWait(tWait.getWaitID(), valorFinalizacion);
		}

		TramitacionServiceImpl.logger.info("TramitacionServiceImpl.finalizarEspera - Fin");
	}

	@Override
	public TWait getWaitByType(String folderId, TWaitType tipoEspera) {
		TramitacionServiceImpl.logger.info("TramitesTareasServiceImpl.getWaitByType - Inicio");

		TWait tWaitResult = null;
		TWaitList listaEsperas = this.plateaService.getWait(folderId);
		for (TWait tWait : listaEsperas.getWait()) {
			if (tWait.getType().equals(tipoEspera)) {
				tWaitResult = tWait;
			}
		}
		TramitacionServiceImpl.logger.info("TramitesTareasServiceImpl.getWaitByType - Fin");
		return tWaitResult;
	}

	@Override
	public void cancelarTareasSugeridas(String folderId, TareasEnum tareaActual) {
		TramitacionServiceImpl.logger
				.info("TramitesTareasServiceImpl.cancelarTareasSugeridas - Inicio folderId: " + folderId);

		TMessageList tMessageList = this.plateaService.getGATTask(folderId, TMessageStatus.PENDING,
				TMessageTipology.TRAMITACION);

		for (TMessage tMessage : tMessageList.getMessage()) {
			// REcuperar propiedades del mensaje -Datos de tarea
			Map<String, Object> mapProperties = JMSHelper.parsearMensajeJms(tMessage.getMessage());

			// ** Solo se cancela si la tarea no es la actual ** //
			if (!tareaActual.getTaskId().equalsIgnoreCase((String) mapProperties.get("taskID"))) {
				this.cancelarTareaSugerida(tMessage.getTaskGUID());
			}
		}

		TramitacionServiceImpl.logger.info("TramitesTareasServiceImpl.cancelarTareasSugeridas "
				+ tMessageList.getTotalCount() + " canceladas- Fin");
	}

	@Override
	public void cancelarTareaSugerida(String taskGUID) {
		TramitacionServiceImpl.logger
				.info("TramitesTareasServiceImpl.cancelarTareaSugerida - " + taskGUID + " - Inicio");

		this.plateaService.cancelarTarea(taskGUID);

		TramitacionServiceImpl.logger.info("TramitesTareasServiceImpl.cancelaTareaSugerida - " + taskGUID + " - Fin");
	}
}
