package nfs;
 
import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
 
/**
 * this is used to call a server and wait for a response, taking into account that messages can be lost.
 * The calling message is supposed to be in a datagram packet and the answer itself is given back as a datagram packet
 * 
 * @author marcod
 *
 */
public class UDPServerComm {
 
	/**
	 * parameters to reach the server
	 */
	InetAddress    serverAddress = null; 
	int            serverPort = 0;
	DatagramSocket ds = null; 
 
	/** 
	 * number of retries when a message fails to get an aswer
	 */
	int retries = 10;
 
	/**
	 * timeout used to wait an answer from the server
	 */
	int timeoutSeconds = 5;
 
	/**
	 * limit of the size of the datagram packet payload (just for this exercise)
	 */
	public static final int LIMIT = 8192;
 
	/**
	 * constructor, intializes the parameters needed to communicate with the server: the address and the port
	 * @param serverName name of the machine running the server
	 * @param port port used by the server to listen messages
	 */
 
	public UDPServerComm(String serverName, int port) {
		try {
			serverAddress = InetAddress.getByName(serverName);
			serverPort = port;
			ds = new DatagramSocket();
		} catch(Exception e) {
			e.printStackTrace();
		}
		return;
	}
 
	/** 
	 * used to set the number of times we have to retransmit before actually failing 
	 * @param n number of time to retransmit
	 */
	public void setRetries(int n) {
		retries = n; 
	}
 
	/**
	 * sets the seconds used before timeouting a request
	 * @param n the number of seconds the answer is awaited before getting the timeout
	 */
	public void setTimeoutSeconds(int n) {
		timeoutSeconds = n;
	}
 
 
	/**
	 * this is the main method: sends the server the datagram packet and waits for an answer, setting proper timeouts
	 * and retransmitting, if the case
	 * @param dp the datagram to be sent to the server
	 * @return the datagram aswered by the server
	 */
	public DatagramPacket call(DatagramPacket dp) {
		DatagramPacket answer = new DatagramPacket(new byte[LIMIT], LIMIT);
		// prepare the datagram to be sent
		dp.setAddress(serverAddress);
		dp.setPort(serverPort);
		try {
			// the start waiting for an answer
			boolean done = false; 
			// set retries to default value
			int nretry = retries;
			// set timeout
			ds.setSoTimeout(timeoutSeconds*1000);
			do {
				try {
					// now send the datagram
					ds.send(dp);
					// wait for the answer
					ds.receive(answer);
					// got! we are done!
					done = true;
				} catch(InterruptedIOException e) { // if the receive timeouts ... 
					nretry--;					    // decrease retry no.
					if(nretry == 0)                 // in case we reached the limit
						return null;                // just return a null
				}
			} while(!done);
		} catch (IOException e) {
			e.printStackTrace();
		}
		return answer;
	}
 
}