/*
 * Created on 19-apr-2004
 */
package convFramework.traffic;

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

import convFramework.domain.*;
import convFramework.exceptions.*;

/**
 * @author Lompa
 */
public class InGate {
	
	private DatagramSocket inSocket = null;
	private IUnMarshaller unMarshaller = null;
	private Node currentNode = null;
	private int inBufferSize = 0;
	
	
	/**
	 * Costruttore unico per un inGate
	 * @param inSocket la socket UDP su cui si ricevono i pacchetti
	 * @param unMarshaler la classe che effettual'unMarshalling
	 */
	public InGate(Node currentNode, DatagramSocket inSocket, IUnMarshaller unMarshaller, int inBufferSize){
		this.inSocket = inSocket;
		this.unMarshaller = unMarshaller;
		this.currentNode = currentNode;
		this.inBufferSize = inBufferSize;
	}
	
	/**
	 * Metodo per la ricezione di un pacchetto
	 * @return
	 */
	public Packet receive() throws ReceptionErrorException, MarshallingException{
		/* campi */
		byte[] inBuffer = new byte[inBufferSize];
		DatagramPacket receivedMessage = new DatagramPacket(inBuffer, inBufferSize);
		
		try {
			/* attesa di un nuovo pacchetto */
			inSocket.receive(receivedMessage);
			
			/* creazione di un oggetto di class packet a partire dal contenuto del messaggio */
			byte[] content = new byte[receivedMessage.getLength()];
			for(int i = 0; i < content.length; i++)
				content[i] = inBuffer[i];
			Packet receivedPacket = unMarshaller.unMarshall(content);
			
			/* controllo di consistenza */
			if (receivedPacket.getAcknowledgedPacket() != null && !receivedPacket.isAck())
				throw new ReceptionErrorException("Only answer ackets can have referred packet id");
			if (receivedPacket.getPreviousPacket() != null && !receivedPacket.isSequence())
				throw new ReceptionErrorException("Only sequence packet can have previous packet id");
			
			/* impostazione del campo destinatario */
			receivedPacket.setReceiver(currentNode);
			
			/* recupero del mittente */
			InetAddress senderAddress = receivedMessage.getAddress();
			int senderPort = receivedMessage.getPort();
			Node sender = new UDPNode(senderAddress, senderPort);
			receivedPacket.setSender(sender);
			
			/* restituzione del pachetto */
			return receivedPacket;
		}
		catch(IOException e){
			throw new ReceptionErrorException("Error receiving packet on input socket");
		}
		catch(BadInvocationArgumentException e){
			throw new ReceptionErrorException("Bad value for a packet element");
		}
	}
	
}
