package org.jvirtanen.parity.util;

import java.io.Closeable;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.NetworkInterface;
import java.net.StandardProtocolFamily;
import java.net.StandardSocketOptions;
import java.nio.channels.DatagramChannel;
import org.jvirtanen.nassau.MessageListener;
import org.jvirtanen.nassau.moldudp64.MoldUDP64ClientState;
import org.jvirtanen.nassau.moldudp64.MoldUDP64ClientStatusListener;
import org.jvirtanen.nassau.moldudp64.SingleChannelMoldUDP64Client;

/**
 * This class implements a MoldUDP64 client.
 */
public class MoldUDP64Client implements Closeable {

    private SingleChannelMoldUDP64Client backing;

    private MoldUDP64Client(SingleChannelMoldUDP64Client backing) {
        this.backing = backing;
    }

    /**
     * Open a MoldUDP64 client.
     *
     * @param multicastInterface the multicast interface
     * @param multicastGroup the multicast group
     * @param requestAddress the request address
     * @param listener the message listener
     * @return a MoldUDP64 client
     * @throws IOException if an I/O error occurs
     */
    public static MoldUDP64Client open(NetworkInterface multicastInterface,
            InetSocketAddress multicastGroup, InetSocketAddress requestAddress,
            MessageListener listener) throws IOException {
        DatagramChannel channel = DatagramChannel.open(StandardProtocolFamily.INET);

        channel.setOption(StandardSocketOptions.SO_REUSEADDR, true);
        channel.bind(new InetSocketAddress(multicastGroup.getPort()));
        channel.join(multicastGroup.getAddress(), multicastInterface);

        MoldUDP64ClientStatusListener statusListener = new MoldUDP64ClientStatusListener() {

            @Override
            public void state(MoldUDP64ClientState next) {
            }

            @Override
            public void downstream() {
            }

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

            @Override
            public void endOfSession() {
            }

        };

        SingleChannelMoldUDP64Client backing = new SingleChannelMoldUDP64Client(channel,
                requestAddress, listener, statusListener);

        return new MoldUDP64Client(backing);
    }

    /**
     * Receive a downstream packet.
     *
     * @throws IOException if an I/O error occurs
     */
    public void receive() throws IOException {
        backing.receive();
    }

    @Override
    public void close() throws IOException {
        backing.close();
    }

}

@@ -273,16 +273,90 @@
 hannel;%0A
+import java.nio.channels.SelectionKey;%0Aimport java.nio.channels.Selector;%0A
 import o
@@ -559,22 +559,21 @@
 ldudp64.
-Single
+Multi
 ChannelM
@@ -712,113 +712,339 @@
 te S
-ingleChannelMoldUDP64Client backing;%0A%0A    private MoldUDP64Client(SingleChannelMoldUDP64Client backing) %7B
+elector selector;%0A%0A    private SelectionKey requestChannelKey;%0A%0A    private MultiChannelMoldUDP64Client backing;%0A%0A    private MoldUDP64Client(Selector selector, SelectionKey requestChannelKey,%0A            MultiChannelMoldUDP64Client backing) %7B%0A        this.selector = selector;%0A%0A        this.requestChannelKey = requestChannelKey;%0A
 %0A   
@@ -1928,16 +1928,249 @@
 erface);
+%0A        channel.configureBlocking(false);%0A%0A        DatagramChannel requestChannel = DatagramChannel.open(StandardProtocolFamily.INET);%0A%0A        requestChannel.connect(requestAddress);%0A        requestChannel.configureBlocking(false);
 %0A%0A      
@@ -2647,21 +2647,252 @@
        S
-ingle
+elector selector = Selector.open();%0A%0A        channel.register(selector, SelectionKey.OP_READ, null);%0A%0A        SelectionKey requestChannelKey = requestChannel.register(selector,%0A                SelectionKey.OP_READ, null);%0A%0A        Multi
 ChannelM
@@ -2924,14 +2924,13 @@
 new 
-Single
+Multi
 Chan
@@ -2980,23 +2980,23 @@
  request
-Address
+Channel
 , listen
@@ -3052,16 +3052,45 @@
 4Client(
+selector, requestChannelKey, 
 backing)
@@ -3125,27 +3125,12 @@
 ive 
-a downstream packet
+data
 .%0A  
@@ -3251,26 +3251,337 @@
     
-backing.receive();
+while (selector.select() == 0);%0A%0A        if (requestChannelKey.isReadable()) %7B%0A            backing.receiveResponse();%0A%0A            selector.selectedKeys().remove(requestChannelKey);%0A        %7D%0A%0A        if (selector.selectedKeys().size() %3E 0) %7B%0A            backing.receive();%0A%0A            selector.selectedKeys().clear();%0A        %7D
 %0A   
@@ -3635,32 +3635,59 @@
 s IOException %7B%0A
+        selector.close();%0A%0A
         backing.

Switch from single-channel to multi-channel MoldUDP64 client