/*
 * $RCSfile: NotifDelegate.java,v $
 * $Date: 2006/01/26 14:48:59 $
 * $Revision: 1.1.2.2 $
 * $Author: andreys $
 */

/*
 * Copyright (c) 2002-2003 IST-2004-2006-511731 ModelWare - ModelBus.
 * All rights reserved.
 *
 * This software is published under the terms of the ModelBus Software License
 * 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.
 * A copy of ModelBus Software License is provided with this distribution in
 * doc/LICENSE.txt file.
 */

/*
 * NotifDelegate.java Add description 
 * 
 * @author Prawee Sriplakich (LIP6)
 * @version $Revision: 1.1.2.2 $ $Date: 2006/01/26 14:48:59 $
 * @see Add references
 *
 * TODO Add description
 * TODO Add references
 */
package org.eclipse.mddi.modelbus.adapter.infrastructure.notification;

import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;

import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;

import org.apache.log4j.Logger;
import org.eclipse.mddi.modelbus.adapter.infrastructure.transport.server.AbstractServer;
import org.eclipse.mddi.modelbus.adapter.infrastructure.transport.server.ws.EndPoint;
import org.eclipse.mddi.modelbus.adapter.infrastructure.transport.server.ws.EndPointManagerImpl;
import org.eclipse.mddi.modelbus.adapter.infrastructure.transport.server.ws.ServerManager;
import org.eclipse.mddi.modelbus.adapter.user.notification.Notification;
import org.eclipse.mddi.modelbus.adapter.user.notification.NotificationConsumer;

/**
 * Receives notifications from NotificationService and forward them to a
 * specific tool.
 * 
 * 
 * 
 * @author Prawee Sriplakich, Andrey Sadovykh (LIP6)
 * 
 * 
 */
public class NotifDelegate implements EndPoint {

    /**
     * The beginning part of the relative path that belongs to this end point.
     */
    public static final String END_POINT_ID = "notification";

    /**
     * Mappings between the URI and the Consumer. The notification messages for
     * each consumer is sent to different URI.
     * 
     */
    Map consumerMap = new Hashtable();

    boolean isServerStarted = false;

    private static Logger logger = Logger.getLogger(NotifDelegate.class);

    NotifDelegate() {
        EndPointManagerImpl.getInstance().putEndPoint(END_POINT_ID, this);
    }

    /**
     * Binds the consumer to the web server. So, The consumer can receive
     * notifications via this server.
     * 
     * @param con
     * @return the URL for connecting to this consumer.
     * @throws Exception
     * @throws NotifServiceNotAvailableException
     * @throws Exception
     * 
     */
    public String bindConsumerToServer(int port, NotificationConsumer con)
            throws Exception {

        if (consumerMap.containsValue(con)) {
            Iterator it = consumerMap.keySet().iterator();
            while (it.hasNext()) {
                String relativePath = (String) it.next();
                if (consumerMap.get(relativePath) == con) {
                    return relativePath;
                }
            }
        }
        // start a server if not already started
        AbstractServer s = ServerManager.getInstance().getServer(port);
        String relativePath = createRelativePath(con);
        consumerMap.put(relativePath, con);
        String url = "http://" + ServerManager.getHost() + ":" + port + "/"
                + s.getContext() + "/" + relativePath;

        return url;

    }

    /**
     * Creates a unique URI for this consumer. For example /mytool.MyConsumer.
     * 
     * @param con
     * @return the relativePath
     * 
     */
    String createRelativePath(NotificationConsumer con) {
        String base = END_POINT_ID + "/" + con.getClass().getName();
        int i = 0;
        while (consumerMap.containsKey(base + i)) {
            i++;
        }
        String uri = base + i;
        return uri;
    }

    /**
     * Unbind the consumer to the web server. The consumer can no longer receive
     * notifications.
     * 
     * @param con
     * 
     */
    public void unbindConsumerToServer(NotificationConsumer con) {
        consumerMap.values().remove(con);
    }

    public NotificationConsumer getConsumer(String uri) {
        return (NotificationConsumer) consumerMap.get(uri);
    }

    public void execute(String urlpath, SOAPEnvelope req, SOAPEnvelope resp)
            throws SOAPException {
        // String
        // serviceName=AxisEngine.getCurrentMessageContext().getTargetService();
        // String uri="/axis/services/"+serviceName;
        NotificationConsumer con = this.getConsumer(urlpath);
        if (con == null) {
            logger
                    .info("Adapter: received notification for unknown consumer. uri="
                            + urlpath);
            return;
        }
        SerializedNotification[] rawNotifs = NotificationServiceUtil
                .extractNotifications(req.getBody());
        for (int i = 0; i < rawNotifs.length; i++) {
            Notification notif = new Notification(rawNotifs[i]);
            con.consume(notif);
        }
    }

}
