package org.mwc.debrief.dis.providers.network;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.mwc.debrief.dis.listeners.IDISGeneralPDUListener;
import org.mwc.debrief.dis.providers.IPDUProvider;

import edu.nps.moves.dis.Pdu;
import edu.nps.moves.disutil.PduFactory;

/**
 * data provider that listens for data on a network multicast socket
 * 
 * @author Ian
 * 
 */
public class NetworkDISProvider implements IPDUProvider
{
  private final IDISNetworkPrefs _myPrefs;
  private List<IDISGeneralPDUListener> _gen =
      new ArrayList<IDISGeneralPDUListener>();
  private boolean _running;

  /**
   * Max size of a PDU in binary format that we can receive. This is actually somewhat
   * outdated--PDUs can be larger--but this is a reasonable starting point
   */
  public static final int MAX_PDU_SIZE = 8192;

  public NetworkDISProvider(IDISNetworkPrefs prefs)
  {
    _myPrefs = prefs;
  }

  @Override
  public void addListener(IDISGeneralPDUListener listener)
  {
    _gen.add(listener);
  }

  /**
   * get the network preferences
   * 
   * @return
   */
  public IDISNetworkPrefs getPrefs()
  {
    return _myPrefs;
  }

  /**
   * start listening
   * 
   */
  public void attach()
  {

    Job job = new Job("Handle incoming")
    {
      @Override
      protected IStatus run(IProgressMonitor monitor)
      {
        startListening();

        // use this to open a Shell in the UI thread
        return Status.OK_STATUS;
      }

    };
    job.setUser(false);
    job.schedule();
  }

  /**
   * stop listening
   * 
   */
  public void detach()
  {
    // set the flag, so we naturally stop
    _running = false;
  }

  /**
   * start listening
   * 
   */
  private void startListening()
  {
    // set the running flag to true
    _running = true;

    MulticastSocket socket = null;
    DatagramPacket packet;
    InetAddress address = null;
    PduFactory pduFactory = new PduFactory();

    try
    {
      // Specify the socket to receive data
      socket = new MulticastSocket(_myPrefs.getPort());
      address = InetAddress.getByName(_myPrefs.getIPAddress());
      socket.joinGroup(address);

      // Loop infinitely, receiving datagrams
      while (_running)
      {
        byte buffer[] = new byte[MAX_PDU_SIZE];
        packet = new DatagramPacket(buffer, buffer.length);

        socket.receive(packet);

        Pdu pdu = pduFactory.createPdu(packet.getData());

        if (pdu != null)
        {
          // share the good news
          Iterator<IDISGeneralPDUListener> gIter = _gen.iterator();
          while (gIter.hasNext())
          {
            IDISGeneralPDUListener git = (IDISGeneralPDUListener) gIter.next();
            git.logPDU(pdu);
          }
        }
        else
        {
          System.err.println("PDU not recognised");
        }

      } // end while

    } // End try
    catch (Exception e)
    {
      e.printStackTrace();
    }
    finally
    {
      if (socket != null)
      {
        // ok, we've finished
        try
        {
          if (address != null)
          {
            socket.leaveGroup(address);
          }
        }
        catch (IOException e)
        {
          e.printStackTrace();
        }
        finally
        {
          socket.close();
        }
      }
    }
  }

  //
  // public static void main(String[] args)
  // {
  //
  // IDISPreferences prefs = new TestPrefs(true, "file.txt");
  // IDISModule subject = new DISModule(prefs);
  // IDISNetworkPrefs netPrefs = new CoreNetPrefs(
  // EspduSender.DEFAULT_MULTICAST_GROUP, EspduSender.PORT);
  // IPDUProvider provider = new NetworkDISProvider(netPrefs);
  // subject.setProvider(provider);
  //
  // // tell the network provider to start
  // provider.attach();
  // }

}
@@ -159,24 +159,57 @@
 castSocket;%0A
+import java.net.SocketException;%0A
 import java.
@@ -224,16 +224,16 @@
 ayList;%0A
-
 import j
@@ -954,16 +954,59 @@
 running;
+%0A  private MulticastSocket _listenerSocket;
 %0A%0A  /**%0A
@@ -2037,16 +2037,83 @@
 = false;
+%0A%0A    // and force the socket to close%0A    _listenerSocket.close();
 %0A  %7D%0A%0A  
@@ -2251,25 +2251,18 @@
     
-MulticastSocket s
+_listenerS
 ocke
@@ -2437,25 +2437,34 @@
  data%0A      
-s
+_listenerS
 ocket = new 
@@ -2566,25 +2566,34 @@
 s());%0A      
-s
+_listenerS
 ocket.joinGr
@@ -2797,25 +2797,34 @@
 );%0A%0A        
-s
+_listenerS
 ocket.receiv
@@ -3328,24 +3328,159 @@
  // End try%0A
+    catch (SocketException se)%0A    %7B%0A      // ok - this happens when the socket is killed.%0A      // we don't need to do anything%0A    %7D%0A
     catch (E
@@ -3558,17 +3558,26 @@
     if (
-s
+_listenerS
 ocket !=
@@ -3573,32 +3573,63 @@
 erSocket != null
+ && !_listenerSocket.isClosed()
 )%0A      %7B%0A      
@@ -3725,25 +3725,34 @@
             
-s
+_listenerS
 ocket.leaveG
@@ -3905,17 +3905,26 @@
         
-s
+_listenerS
 ocket.cl

correct network socket disconnection