package com.paritytrading.nassau.binaryfile.recorder;

import static org.jvirtanen.util.Applications.*;

import com.paritytrading.nassau.MessageListener;
import com.paritytrading.nassau.binaryfile.BinaryFILEWriter;
import com.paritytrading.nassau.moldudp64.MoldUDP64Client;
import com.paritytrading.nassau.moldudp64.MoldUDP64ClientState;
import com.paritytrading.nassau.moldudp64.MoldUDP64ClientStatusListener;
import com.typesafe.config.Config;
import com.typesafe.config.ConfigException;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.NetworkInterface;
import java.net.StandardProtocolFamily;
import java.net.StandardSocketOptions;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import org.jvirtanen.config.Configs;

class Recorder {

    private static volatile boolean receive = true;

    public static void main(String[] args) {
        if (args.length != 2)
            usage("nassau-binaryfile-recorder <configuration-file> <output-file>");

        try {
            main(config(args[0]), new File(args[1]));
        } catch (ConfigException | FileNotFoundException e) {
            error(e);
        } catch (IOException e) {
            fatal(e);
        }
    }

    private static void main(Config config, File file) throws IOException {
        NetworkInterface multicastInterface = Configs.getNetworkInterface(config, "session.multicast-interface");
        InetAddress      multicastGroup     = Configs.getInetAddress(config, "session.multicast-group");
        int              multicastPort      = Configs.getPort(config, "session.multicast-port");
        InetAddress      requestAddress     = Configs.getInetAddress(config, "session.request-address");
        int              requestPort        = Configs.getPort(config, "session.request-port");

        DatagramChannel channel = DatagramChannel.open(StandardProtocolFamily.INET);

        channel.setOption(StandardSocketOptions.SO_REUSEADDR, true);
        channel.bind(new InetSocketAddress(multicastPort));
        channel.join(multicastGroup, multicastInterface);
        channel.configureBlocking(false);

        DatagramChannel requestChannel = DatagramChannel.open(StandardProtocolFamily.INET);

        requestChannel.configureBlocking(false);

        final BinaryFILEWriter writer = BinaryFILEWriter.open(file);

        MessageListener listener = new MessageListener() {

            @Override
            public void message(ByteBuffer buffer) throws IOException {
                writer.write(buffer);
            }

        };

        MoldUDP64ClientStatusListener statusListener = new MoldUDP64ClientStatusListener() {

            @Override
            public void state(MoldUDP64Client session, MoldUDP64ClientState next) {
            }

            @Override
            public void downstream(MoldUDP64Client session) {
            }

            @Override
            public void request(MoldUDP64Client session, long sequenceNumber, int requestedMessageCount) {
            }

            @Override
            public void endOfSession(MoldUDP64Client session) {
                receive = false;
            }

        };

        MoldUDP64Client client = new MoldUDP64Client(channel, requestChannel,
                new InetSocketAddress(requestAddress, requestPort), listener, statusListener);

        addShutdownHook();

        Selector selector = Selector.open();

        SelectionKey key = channel.register(selector, SelectionKey.OP_READ);

        SelectionKey requestKey = requestChannel.register(selector, SelectionKey.OP_READ);

        while (receive) {
            int numKeys = selector.select();
            if (numKeys > 0) {
                if (selector.selectedKeys().contains(key))
                    client.receive();

                if (selector.selectedKeys().contains(requestKey))
                    client.receiveResponse();

                selector.selectedKeys().clear();
            }
        };

        writer.close();
        client.close();
    }

    private static void addShutdownHook() {
        final Thread main = Thread.currentThread();

        Runtime.getRuntime().addShutdownHook(new Thread() {

            @Override
            public void run() {
                receive = false;

                try {
                    main.join();
                } catch (InterruptedException e) {
                }
            }

        });
    }

}

@@ -1453,32 +1453,590 @@
 s IOException %7B%0A
+        addShutdownHook();%0A%0A        final BinaryFILEWriter writer = BinaryFILEWriter.open(file);%0A%0A        MessageListener listener = new MessageListener() %7B%0A%0A            @Override%0A            public void message(ByteBuffer buffer) throws IOException %7B%0A                writer.write(buffer);%0A            %7D%0A%0A        %7D;%0A%0A        MoldUDP64Client client = join(config, listener);%0A%0A        receive(client);%0A%0A        client.close();%0A        writer.close();%0A    %7D%0A%0A    private static MoldUDP64Client join(Config config, MessageListener listener) throws IOException %7B%0A
         NetworkI
@@ -2999,297 +2999,8 @@
 );%0A%0A
-        final BinaryFILEWriter writer = BinaryFILEWriter.open(file);%0A%0A        MessageListener listener = new MessageListener() %7B%0A%0A            @Override%0A            public void message(ByteBuffer buffer) throws IOException %7B%0A                writer.write(buffer);%0A            %7D%0A%0A        %7D;%0A%0A
     
@@ -3611,32 +3611,14 @@
     
-MoldUDP64Client client =
+return
  new
@@ -3758,36 +3758,91 @@
 r);%0A
-%0A
     
+%7D%0A%0A
     
-addShutdownHook();%0A
+private static void receive(MoldUDP64Client client) throws IOException %7B
 %0A   
@@ -3912,22 +3912,34 @@
  key = c
+lient.getC
 hannel
+()
 .registe
@@ -4008,17 +4008,27 @@
 stKey = 
-r
+client.getR
 equestCh
@@ -4032,16 +4032,18 @@
 tChannel
+()
 .registe
@@ -4478,38 +4478,16 @@
     
-writer.close();%0A        client
+selector
 .clo

Refactor BinaryFILE recorder