package com.ejie.m62fb.notificacion;

import javax.ejb.ActivationConfigProperty;
import javax.ejb.ApplicationException;
import javax.ejb.EJBException;
import javax.ejb.MessageDriven;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.ejb.TransactionManagement;
import javax.ejb.TransactionManagementType;
import javax.interceptor.Interceptors;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathFactory;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ejb.interceptor.SpringBeanAutowiringInterceptor;
import org.w3c.dom.Document;

import com.ejie.m62fb.service.registroVPP.IntegracionService;
import com.ejie.m62fb.utils.constants.AppConstantes;
import com.ejie.m62fb.utils.sql.Utilidades;

/**
 * NotificacionMDB
 * 
XXXX
 */
@MessageDriven(messageListenerInterface = javax.jms.MessageListener.class, name = "m62fbNotificacionQueue", mappedName = "m62fb.m62fbNotificacionQueue", activationConfig = {
        @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
        @ActivationConfigProperty(propertyName = "connectionFactoryJndiName", propertyValue = "m62fb.m62fbConnectionFactory") })
@TransactionManagement(value = TransactionManagementType.CONTAINER)
@TransactionAttribute(value = TransactionAttributeType.NOT_SUPPORTED)
@ApplicationException(rollback = true)
@Interceptors(value = SpringBeanAutowiringInterceptor.class)
public class NotificacionMDB implements MessageListener {

    // Veces que se puede reenviar como maximo
    private static final int MAX_REINTENTOS = 15;

    private static final String PATH_PLATEA_TYPE = "/NotificationBody/Property[Name='PlateaType']/Value";
    private static final String PATH_XML_VALUE = "/NotificationBody/xmlValue";
    private static final String PROPERTY_EVENT_WHAT = "EventWhat";

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

    @Autowired
    private IntegracionService integracionService;

    /**
     * Gestiona los mensajes que llegan de la cola de Notificacion
     * 
     * @param msg
     *            Message
     */
    @Override
    public void onMessage(Message msg) {
        NotificacionMDB.logger.trace("onMessage INI");
        try {
            // Para evitar el reenvio masivo de mensajes jms:
            int deliveryCount = 0;
            try {
                NotificacionMDB.logger.debug("Mensaje recibido: {}", msg);
                if (msg.getJMSRedelivered()) {
                    deliveryCount = msg.getIntProperty("JMSXDeliveryCount");
                }
                NotificacionMDB.logger.debug("Reintento: {}", deliveryCount);
            } catch (JMSException e) {
                NotificacionMDB.logger
                        .error("Error al obtener parametro 'JMSXDeliveryCount' del mensaje jms.",
                                e);
            }

            // Se valida que, en caso de fallar algo, no se reenvie el mensaje
            // indefinidamente, sino que se reenvie un maximo de veces.
            if (deliveryCount > NotificacionMDB.MAX_REINTENTOS) {
                // Se han superado los reintentos
                NotificacionMDB.logger
                        .error("Se ha superado el maximo permitido de reintentos definido en la aplicacion ({}) para el mensaje {}",
                                new Object[] { NotificacionMDB.MAX_REINTENTOS,
                                        msg.getJMSMessageID() });
            } else {
                // Tratar Mensaje:
                NotificacionMDB.logger.debug("Texto Mensaje Recibido: {}",
                        ((TextMessage) msg).getText());

                Document xmlDocument = Utilidades
                        .parseStringToDocument(((TextMessage) msg).getText());
                XPath xPath = XPathFactory.newInstance().newXPath();

                // Recuperar EventWhat
                String eventWhat = msg.getStringProperty(PROPERTY_EVENT_WHAT);
                NotificacionMDB.logger.debug("eventWhat: {}", eventWhat);

                // Recuperamos el Texto del mensaje
                String xmlValue = xPath.compile(PATH_XML_VALUE).evaluate(
                        xmlDocument);
                NotificacionMDB.logger.debug(
                        "Texto Evento Recibido (xmlValue): {}", xmlValue);

                // Comprobar el "tipo" de evento
                if (AppConstantes.EVENTO_REQUEST.equals(eventWhat)) {
                    NotificacionMDB.logger.debug("EVENTO SOLICITUD: ",
                            eventWhat);
                    // InformarSolicitudReserva
                    this.integracionService.informarSolicitudReserva(xmlValue);
                } else if (AppConstantes.EVENTO_TASK.equals(eventWhat)) {
                    String plateaType = xPath.compile(PATH_PLATEA_TYPE)
                            .evaluate(xmlDocument);
                    if (AppConstantes.PLATEA_TYPE_APERTURA.equals(plateaType)) {
                        NotificacionMDB.logger.debug(
                                "EVENTO TIPO APERTURA: {}", plateaType);
                        // InformarApertura
                        this.integracionService.informarApertura(xmlValue);
                    } else if (AppConstantes.PLATEA_TYPE_NOTIF
                            .equals(plateaType)) {
                        NotificacionMDB.logger.debug(
                                "EVENTO TIPO NOTIFICACION: {}", plateaType);
                        // InformarNotificacion
                        this.integracionService.informarNotificacion(xmlValue);
                    } else {
                        NotificacionMDB.logger.debug("EVENTO TIPO: {}",
                                plateaType);
                    }
                } else {
                    NotificacionMDB.logger.debug("EVENTO DESCONOCIDO: {}",
                            eventWhat);
                }
            }
        } catch (Exception e) {
            NotificacionMDB.logger.error(
                    "Error al tratar el evento en la cola.", e);
            throw new EJBException("Error al tratar el evento en la cola.", e);
        }

        NotificacionMDB.logger.trace("onMessage FIN");
    }
}