/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 2005-2007 Bull S.A.S.
 * Contact: jonas-team@ow2.org
 *
 * 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 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.
 *
 * --------------------------------------------------------------------------
 * $Id$
 * --------------------------------------------------------------------------
 */

package org.ow2.jonas.discovery.multicast.comm;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;

import org.ow2.jonas.discovery.base.comm.DiscGreeting;
import org.ow2.jonas.discovery.multicast.manager.DiscoveryManager;
import org.ow2.jonas.discovery.multicast.utils.DiscoveryHelper;
import org.ow2.jonas.lib.util.Log;

import org.objectweb.util.monolog.api.BasicLevel;
import org.objectweb.util.monolog.api.Logger;

/**
 * This class is the first thing started by the discovery manager when
 * starting the discovery service. It listens to the multicast group for
 * greeting messages from new servers and if the message received contains
 * the same server ID as that of this instance more than once (one message from
 * the same instance at first) this class sends a response to inform the new server
 * that it violates uniqueness of the server ID.
 * @author Vivek Lakshmanan
 * @version 1.0
 */
public class DiscoveryGreetingListener extends DiscoveryGreetingResponder {
    /**
     * logger
     */
    private static Logger logger = Log.getLogger(Log.JONAS_DISCOVERY_PREFIX);


    /**
     * The number of times a message with the same server ID has been received
     * in the current run.
     */
    private int mesgsSameServerIDCount;

    /**
     * Constructs a DiscoveryGreetingListener associated to the DiscoveryManager
     *
     * @param dm
     *            DiscoveryManager to which this thread is associated
     */
    public DiscoveryGreetingListener(DiscoveryManager dm) {

        super(dm);

        mesgsSameServerIDCount = 0;

    }

    /**
     * @see java.lang.Runnable#run()
     */
    public void run() {
        // Set this to 0 so number of messages with the same server ID can be counted,
        // must not receive more than 1 such message in a run.
        mesgsSameServerIDCount = 0;

        // Join the group in order to receive multicast messages
        join();

        // Create the socket to be used for responding
        try {
            unicastSocket = new DatagramSocket();
        } catch (SocketException e3) {
            logger.log(BasicLevel.ERROR, "Socket exception", e3);
            return;
        }
        try {
            while (notStopped) {
                DatagramPacket datagram = null;
                Object objReceived = null;
                try {
                    datagram = getDatagram(RECEIVE_BUFFER_SIZE);
                    multicastSocket.receive(datagram);
                    objReceived = DiscoveryHelper.bytesToObject(datagram.getData());
                } catch (RuntimeException e) {
                    logger.log(BasicLevel.DEBUG, "Host received other packet than DataGramSocket packet. That caused following Exception: \n"+e);
                    objReceived = null;
                }catch (IOException e) {
                	logger.log(BasicLevel.DEBUG, "Host received other packet than DataGramSocket packet. That caused following Exception: \n"+e);
                    objReceived = null;
				}
                if (objReceived != null) {
                    // If received object is of type DiscGreeting
                    if (objReceived instanceof DiscGreeting) {
                        DiscGreeting request = (DiscGreeting) objReceived;
                        if (logger.isLoggable(BasicLevel.DEBUG)) {
                            logger.log(BasicLevel.DEBUG,
                                    "DiscGreeting received on multicast:\n"
                                            + request);
                        }
                        // If server ID in the message is the same as
                        // that of this instance and domain is the same, make
                        // sure that only 1 such message is encountered by
                        // the system: one from itself.
                        if (request != null
                                && request.getServerId().equals(this.serverId)
                                && request.getDomainName().equals(
                                        this.domainName)) {
                            // Got a message with the same server ID and the same
                            // domain so up the count.
                            mesgsSameServerIDCount++;
                            if (mesgsSameServerIDCount > 1) {
                                // Trust the datagram packet itself for the
                                // source address.
                                InetAddress destAddress = datagram.getAddress();
                                int destPort = request.getSourcePort();
                                DiscGreeting msg = createDiscGreeting(false);
                                sendResponse(msg, destAddress, destPort);
                            }

                        }
                    }
                }
                datagram = null;
            }
        } catch (ClassNotFoundException e) {
            logger.log(BasicLevel.ERROR, e);
        }
    }
    /**
     * Stop
     */
    public void stop() {
        Thread.interrupted();

    }

}
