/**
 * Petals View - Functional Supervision.
 * Copyright (c) 2010 EBM Websourcing, http://www.ebmwebsourcing.com/
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * -------------------------------------------------------------------------
 * NotificationReader.java
 * -------------------------------------------------------------------------
 */

package com.ebmwebsourcing.petalsview.service.notification;

import java.util.Date;

import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.transform.Source;
import javax.xml.transform.dom.DOMSource;

import org.apache.log4j.Logger;

import com.ebmwebsourcing.webcommons.util.XMLUtil;

/**
 * This class is in charge of processing xml notification parts (topic and
 * message) to update DB
 * 
 * @author ofabre
 */
public class NotificationReader {

    private Logger logger = null;

    private XMLInputFactory factory = null;

    public NotificationReader() {
        super();
        this.logger = Logger.getLogger(NotificationReader.class);
        this.factory = XMLInputFactory.newInstance();
        this.factory.setProperty(XMLInputFactory.IS_VALIDATING, Boolean.FALSE);
    }

    /**
     * Process xml notification message <br>
     * 
     * @param notifMessage
     *            a {@link Source} that handles an xml notification message
     * @throws NotificationProcessingException
     *             if an error occurs during notification reading
     */
    public Notification read(final Source notifMessage) throws NotificationProcessingException {
        Notification notification = null;
        if (this.logger.isDebugEnabled()) {
            this.logger.debug("a notification is read");
        }
        // Read the xml notification message
        try {
            notification = this.parseNotifMessage(notifMessage);
        } catch (final Throwable e) {
            throw new NotificationProcessingException("unable to read the notification", e);
        }
        return notification;
    }

    private Notification parseNotifMessage(final Source notifMessage) throws XMLStreamException {
        Notification notification = null;
        if (notifMessage != null) {
            // Create notif object
            notification = new Notification();
            // Create stream reader (stax)
            Source source = null;
            if (notifMessage instanceof DOMSource) {
                try {
                    source = XMLUtil.toStreamSource((DOMSource) notifMessage);
                } catch (Exception e) {
                    new NotificationProcessingException("Can't convert DOMSource to StreamSource",
                            e);
                }
            } else {
                source = notifMessage;
            }
            final XMLStreamReader parser = this.factory.createXMLStreamReader(source);
            try {
                for (int event = parser.next(); event != XMLStreamConstants.END_DOCUMENT; event = parser
                        .next()) {
                    switch (event) {
                        case XMLStreamConstants.START_ELEMENT:
                            if (Notification.NOTIF_ELEM_NAME
                                    .equalsIgnoreCase(parser.getLocalName())) {
                                this.parseNotifElement(parser, notification);
                            } else if (Notification.PARAM_ELEM_NAME.equalsIgnoreCase(parser
                                    .getLocalName())) {
                                notification.addParam(parser.getElementText());
                            }
                            break;
                        default:
                            break;
                    }
                }
            } finally {
                parser.close();
            }
        }
        return notification;
    }

    private void parseNotifElement(final XMLStreamReader parser, final Notification notification)
            throws XMLStreamException {
        notification
                .setProcessId(parser.getAttributeValue(null, Notification.PROCESS_ID_ATTR_NAME));

        final String processType = parser.getAttributeValue(null,
                Notification.PROCESS_TYPE_ATTR_NAME);
        if (processType != null && !"".equals(processType)) {
            notification.setProcessType(Integer.parseInt(processType));
        }

        final String status = parser.getAttributeValue(null, Notification.STATUS_ATTR_NAME);
        if (status != null && !"".equals(status)) {
            notification.setStatus(Integer.parseInt(status));
        }
        notification.setInterfaceName(parser.getAttributeValue(null,
                Notification.INTERFACE_ATTR_NAME));
        notification.setEndpointName(parser
                .getAttributeValue(null, Notification.ENDPOINT_ATTR_NAME));
        notification.setServiceName(parser.getAttributeValue(null, Notification.SERVICE_ATTR_NAME));
        notification.setMeUUID(parser.getAttributeValue(null, Notification.MEUUID_ATTR_NAME));

        final String notifDate = parser.getAttributeValue(null, Notification.NOTIF_DATE_ATTR_NAME);
        if (notifDate != null && !"".equals(notifDate)) {
            notification.setNotifDate(new Date(Long.parseLong(notifDate)));
        }
    }

}
