package fr.umlv.ir2.udp;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.util.Scanner;
import static fr.umlv.ir2.util.Converter.LONG_SIZE;
import static fr.umlv.ir2.util.Converter.longToByteArray;
import static fr.umlv.ir2.util.Converter.byteArrayToLong;

/**
 * This class offers implementations for a client of SumServer. 
 * from input lines read on the keyboard representing long values, 
 * it sends to the server these values in network order (big endian).
 * @author duris
 * @see fr.umlv.ir2.udp.SumServer
 *
 */
public class SumClient {
	
  private final byte[] sendBuffer;
  private final byte[] receiveBuffer;
  
  private final DatagramSocket ds;
  private final DatagramPacket dp; 
  
  /**
   * Creates a client for the server specified by its InetAddress and its port.
   * @param server the address of the sum server to use.
   * @param port the port of the sum server to use.
   * @throws SocketException
   */
  public SumClient(InetAddress server, int port) throws SocketException {
    this.ds = new DatagramSocket();
    this.sendBuffer = new byte[LONG_SIZE];
    this.receiveBuffer  = new byte[LONG_SIZE];
    this.dp = new DatagramPacket(sendBuffer, 0, LONG_SIZE, server, port);
    ds.setSoTimeout(10000); // if server response is lost, do not wait more than 2 seconds
  }
  
  /**
   * Send a datagram containing the representation of the specified long value, 
   * in network order (big endian).
   * @param value the long value to send.
   * @throws IOException
   */
  public void sendOperand(long value) throws IOException {
    longToByteArray(value, sendBuffer);
    dp.setData(sendBuffer);
    ds.send(dp);  
  }
  
  /**
   * Listen to receive a datagram containing the representation of a long
   * value, in network order (big endian).
   * @return the long value contained in the received datagram.
   * @throws IOException
   *    */
  public long receiveResult() throws IOException, IllegalArgumentException {
    dp.setData(receiveBuffer);
    ds.receive(dp);
    if(dp.getLength() != LONG_SIZE)
    	throw new IOException("Number of byte received incompatible with expected data: "+ dp.getLength());
    return byteArrayToLong(receiveBuffer);
  }
 
  public static void usage() {
    System.out.println("java SumClient <server> <serverPort>");
  }

  public static void main(String[] args) throws IOException {
    if (args.length < 2) {
      usage();
      System.exit(0);
    }
    InetAddress server = InetAddress.getByName(args[0]);
    int port = Integer.parseInt(args[1]);
    SumClient client = new SumClient(server, port);
    
    Scanner sc = new Scanner(System.in);
    while (sc.hasNextLong()) {
      client.sendOperand(sc.nextLong());
      System.out.println(client.receiveResult());
    }
  }
}
