import transport.*;
import java.net.*;
import java.io.*;

public class SAWReceiver2 extends Receiver implements TimeoutAction
{
    private static final int R0 = 0;
    private static final int R1 = 1;
    private static final int CLOSED = 2;

    private byte[] ack1;
    private byte[] ack0;
    private byte[] ackfin;
    private int state;

    public SAWReceiver2() {
	ack0 = new byte[1];
	ack0[0] = 0;

	ack1 = new byte[1];
	ack1[0] = 1;

	ackfin = new byte[1];
	ackfin[0] = 2;

	state = R0;
    }

    public void timeoutAction() {
	try {
	    disconnect();
	} catch (java.lang.InterruptedException ex) {
	    System.out.println("Thread interrupted.  Exiting directly.");
	    System.exit(0);
	}
    }

    private static void print_packet(byte[] buffer, int offset, int length) {
	int end = offset + length;
	System.out.print("\n[");
	while(offset < end) 
	    System.out.print(buffer[offset++] + " ");
	System.out.print("]");
    }

    public void unreliableReceive(byte[] buffer, int offset, int length) {
	//	print_packet(buffer, offset, length);
	cancelTimeout(this);
	setTimeout(20000, this);
	//	try { Thread.sleep(1000); } catch (InterruptedException ignored) { }
	switch(state) {
	case R0:
	    System.out.print("R0:");
	    if (length > 0 && buffer[offset] == 0) {
		System.out.print("->R1 ");
		state = R1;
		deliver(buffer, offset + 1, length - 1);
		unreliableSend(ack0, 0, 1);
	    } else if (length > 0 && buffer[offset] == 2) {
		System.out.print("->CLOSED ");
		state = CLOSED;
		deliver(buffer, offset + 1, length - 1);
		unreliableSend(ackfin, 0, 1);
		deliver(null, 0, END_OF_STREAM);
	    } else {
		System.out.print("!->R0 ");
		unreliableSend(ack1, 0, 1);
	    }
	    return;
	case R1:
	    System.out.print("R1:");
	    if (length > 0 && buffer[offset] == 1) {
		System.out.print("->R0 ");
		state = R0;
		deliver(buffer, offset + 1, length - 1);
		unreliableSend(ack1, 0, 1);
	    } else if (length > 0 && buffer[offset] == 2) {
		System.out.print("->CLOSED ");
		state = CLOSED;
		unreliableSend(ackfin, 0, 1);
		deliver(null, 0, END_OF_STREAM);
	    } else {
		System.out.print("!->R1 ");
		unreliableSend(ack0, 0, 1);
	    }
	    return;
	}
    }
}
