
package network;

import java.io.*;
import java.net.*;
import java.util.*;


public class AliveAndRetransmitThread extends Thread {

    final int THREAD_WAIT_TIME = 1000; // in msec
    final int ALIVE_MSG_INT = 15; // in sec

    final int MAX_RETRANSMIT = 5;

    Vector nodesList = null;
    DatagramSocket socket = null;
    TransmissionTable table = null;
    BufferQueue sendBuffer = null;
    NetworkStatDataModel dataModel = null;
    boolean stopThread = false;
    int counter;

    public AliveAndRetransmitThread(DatagramSocket s, Vector addrs,
                                    TransmissionTable t, BufferQueue buffer,
                                    NetworkStatDataModel netData) {
        nodesList = addrs;
        table = t;
        socket = s;
        sendBuffer = buffer;
        dataModel = netData;

        counter = 0;  // force to send out alive message at the beginning
    }

    public void requestStop() {
        stopThread = true;
    }

    private DatagramPacket createAlivePacket(int index, boolean retransmit) {

        byte[] buf = new byte[2];

        if (!retransmit)
            buf[1] = (new Integer(table.getSeqNum(index))).byteValue();
        else
            buf[1] = (new Integer(table.getSeqNum(index) - 1)).byteValue();

        buf[0] = (new Integer(((NetworkManager.VERSION & 0xF) << 4) |
                              (NetworkManager.ALIVE & 0xF))).byteValue();

        DatagramPacket packet = new DatagramPacket(buf, buf.length);

        InetObject obj = (InetObject)nodesList.elementAt(index);
        packet.setAddress(obj.address);
        packet.setPort(obj.port);

        if (!retransmit)
            table.incrementSeqNum(index);

        dataModel.editSendRecord(index, buf.length);
        return packet;

    }


    public void run() {
        while (!stopThread) {
            table.countDown();

            // Re-transmit unack alive messages
            for (int i = 0; i < nodesList.size(); i++)
                if (table.getTimerValue(i) == 0) {
                    int retransmitCount = table.getRetransmitCount(i);
                    if (retransmitCount == MAX_RETRANSMIT) {
                        // TODO: Invoke EventBase for appropriate action - tungfai

                        table.resetRetransmitCount(i);
                    }
                    else {
                        table.setTimerValue(i, TransmissionTable.TIMEOUT);
                        table.incrementRetransmitCount(i);
                        sendBuffer.enqueue(createAlivePacket(i, true));
                        System.out.println("Retransmit Alive Message to " +
                                           ((InetObject)nodesList.elementAt(i)).address.getHostName());
                    }
                }


            // Check if it is time to send out alive messages
            if (counter == 0) {
                for (int i = 0; i < nodesList.size(); i++) {
                    if (!((InetObject)nodesList.elementAt(i)).simulationAlive)
                        continue;

                    table.setTimerValue(i, TransmissionTable.TIMEOUT);
                    sendBuffer.enqueue(createAlivePacket(i, false));
                    System.out.println("Send out Alive Message to " +
                                       ((InetObject)nodesList.elementAt(i)).address.getHostName());
                }
                counter = ALIVE_MSG_INT;
            }
            else
                counter --;

            try {
                sleep(THREAD_WAIT_TIME);
            }
            catch (InterruptedException e) {
		
            }
	    
	    // disable explicit gc call -- yhchu
	    // the profiler says it's spending more than 50% of cycle gc
            // System.gc();

        }

    }

}
