package anastore.test;

import anastore.client.*;
import anastore.net.*;
import anastore.util.*;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Timer;
import java.util.TimerTask;

import static org.junit.Assert.*;

/**
 * Two-client test. This sets up two clients. First, a block is
 * created on one of them. Then the two clients alternate their
 * transactions. One increments the value in the block, and the other
 * just reads it (but still as a RW transaction, not RO).
 */
public class IncrementTwoClients {

    private static final int DELAY = 2000;
    private static final int ITERATIONS = 10;
    
    public static final void main(final String[] args) {
        try {
            if (args.length != 4) {
                System.err.println("usage: <hostname> <port> <cache-dir 1> <cache-dir 2>");
                System.exit(1);
            }

            ChannelClient client1 =
                new ChannelClient(args[0],
                                  Integer.parseInt(args[1]));
            Pair<SendChannel, ReceiveChannel> channels1 = client1.connect();
            SendChannel send1 = channels1.first;
            ReceiveChannel recv1 = channels1.second;
            File cache1 = new File(args[2]);
            final BlockStore store1 = BlockStore.connect(send1, cache1);

            ChannelClient client2 =
                new ChannelClient(args[0],
                                  Integer.parseInt(args[1]));
            Pair<SendChannel, ReceiveChannel> channels2 = client2.connect();
            SendChannel send2 = channels2.first;
            ReceiveChannel recv2 = channels2.second;
            File cache2 = new File(args[3]);
            final BlockStore store2 = BlockStore.connect(send2, cache2);

            // Create a block
            final Pair<Long, ByteBuffer> block;
            try {
                RWSnapshot snap = store1.beginRW();
                block = snap.newBlock(8);
                block.second.putLong(0,0);
                snap.commit();
            } catch (AbortedException e) {
                throw new RuntimeException(e);
            }

            Timer timer = new Timer();

            timer.schedule(new TimerTask() {
                    int i = 0;
                    
                    public void run() {
                        try {
                            System.out.println("Writer[" + i + "] start");
                            RWSnapshot snap = store1.beginRW();
                            ByteBuffer rBuf = snap.readBlock(block.first);
                            long value = rBuf.getLong(0);
                            System.out.println("Writer: read " + value);
                            assertEquals(i, value);

                            System.out.println("Writer: writing " + (i+1));
                            ByteBuffer wBuf =
                                snap.readWriteBlock(block.first);
                            wBuf.putLong(0,i+1);
                            snap.commit();
                            System.out.println("Writer[" + i + "] done");
                        } catch (AbortedException e) {
                            throw new RuntimeException(e);
                        }

                        i += 1;
                        if (i == ITERATIONS) {
                            cancel();
                            System.out.println("Writer: success!");
                            System.exit(0);
                        }
                    }   
                }, DELAY, DELAY);
        
            timer.schedule(new TimerTask() {
                    int i = 0;
                    
                    public void run() {
                        try {
                            System.out.println("Reader[" + i + "] start");
                            RWSnapshot snap = store2.beginRW();
                            ByteBuffer rBuf = snap.readBlock(block.first);
                            long value = rBuf.getLong(0);
                            System.out.println("Reader: read " + value);
                            assertEquals(i, value);
                            snap.commit();
                            System.out.println("Reader done");
                            System.out.println("Reader[" + i + "] done");
                        } catch (AbortedException e) {
                            throw new RuntimeException(e);
                        }

                        i += 1;
                        if (i == ITERATIONS) {
                            cancel();
                            System.out.println("Reader: success!");
                            return;
                        }
                    }
                    
                }, DELAY/2, DELAY);            
        } catch (IOException e) {
            e.printStackTrace();
            System.exit(1);
        }
    }
}
