package anastore.net.test;

import anastore.net.*;
import anastore.util.*;
import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;

/**
 * Simple test of the channel system. This models the traffic pattern
 * seen by our block store: the client periodically sends synchronous
 * query messages, to which the server replies with a response
 * message. Also, the server periodically sends invalidation
 * messages. Of course, in the test, these messages have no meaning
 * and no payload other than an integer id.
 *
 * The server listens for connections on the specified port. When it
 * receives one, it starts a timer thread that sends out invalidations
 * on the root send channel every 10 seconds, and another thread that
 * reads the root receive channel continually and responds to any send
 * messages with response messages.
 *
 * Prints a message to stdout every time a message is sent or
 * received.
 */
public class TestServer {

    private static ChannelServer server;
    
    /**
     * Start running the test. The first argument is the port
     * to listen on. Should not terminate.
     */
    public static final void main(final String[] args)
        throws IOException, InterruptedException {
        server = new ChannelServer(Integer.parseInt(args[0]));

        server.listen(new ChannelServerListener() {
                public void connectionEstablished(final String hostname,
                                                  final int port,
                                                  final SendChannel send,
                                                  final ReceiveChannel recv) {
                    /*
                     * When a connection is established, start a timer
                     * that sends out invalidation messages.
                     */
                    Timer timer = new Timer();
                    timer.scheduleAtFixedRate(new TimerTask() {
                            private int lastInvalidation = 0;

                            public void run() {
                                lastInvalidation += 1;
                                InvalidationMessage imsg =
                                    new InvalidationMessage(lastInvalidation);
                                System.out.println("Sending invalidation " +
                                                   "message " +
                                                   imsg.payload);
                                try {
                                    send.send(imsg);
                                } catch (IOException e) {
                                    System.out.println("IOException: " +
                                                       e.toString());
                                    cancel();
                                }
                            }
                        }, 1000, 1000);

                    /*
                     * Also start a thread that waits for query
                     * messages and responds to them.
                     */
                    (new Thread() {
                        public void run() {
                            boolean done = false;
                            
                            while (!done) {
                                try {
                                    QueryMessage qmsg;
                                    Pair<Message, SendChannel> received
                                        = recv.receive();
                                    qmsg = (QueryMessage) received.first;
                                    System.out.println("Got query message " +
                                                       qmsg.payload);
                                    ResponseMessage rmsg =
                                        new ResponseMessage(qmsg.payload);
                                    System.out.println("Sending response " +
                                                       "message " +
                                                       rmsg.payload);
                                    received.second.send(rmsg);
                                } catch (IOException e) {
                                    System.out.println("IOException: " +
                                                       e.toString());
                                    done = true;
                                } catch (InterruptedException e) {
                                    System.out.println("InterruptedException: "
                                                       + e.toString());
                                }
                            }
                        }
                        }).start();
                }
            });
    }
}
