/*
 * Created on 5-mag-2004
 */
package a3.protocol;

import jaCop.domain.*;
import jaCop.protocol.*;

import a3.traffic.*;
import a3.domain.*;
import a3.exceptions.*;

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

/**
 * @author Lompa
 */
public class SoundStructureServer extends A3Task{
	
	/* NOTA: si assume che il servizio A3 sia aperto sulla porta con numero immediatamente successivo a
	 * quella di JaCOP */
	
	/**
	 * @param community
	 * @param conv
	 * @param packetMan
	 * @param statusStore
	 * @param convGraveyard
	 * @param waitingTimeout
	 * @param connectionRank
	 * @param maxDelegationsNumber
	 */
	public SoundStructureServer(ConfigurationSet conf,
			A3PacketManager packetMan, A3EventListenerManager listenerMan,
			ConversationGraveyard convGraveyard, ControlQueue queue, ProtocolManager jaCOPMan) {
		super(conf, packetMan, convGraveyard, listenerMan, queue, jaCOPMan);
	}
	
	
	/* metodo body */
	protected void body() throws TranslationException, InterruptedException{
		//System.out.println("SERVER PER SONDAGGIO STRUTTURA");
		
		/* RICEZIONE RISPOSTA */
		/* ricezione */
		A3Packet ans = receiveAndStart();
		/* controllo del tipo */
		if (!ans.getType().equals(A3StructureRequest.getTypeDescription())){
			/* se il tipo è sbagliato no faccio nulla */
			return;
		}
		/* casting */
		A3StructureRequest req = (A3StructureRequest) ans;  
		/* recupero info */
		A3Node requester = req.getRequester();
		A3Node excludedNode = null; 
		try { excludedNode = new A3Node(req.getSender().getAddress(), req.getSender().getPort()+1); }
		catch(convFramework.exceptions.BadInvocationArgumentException e){
			throw new A3Error(e.getMessage());
		}
		
		/* INVIO STRUTTURA */
		/* preparazione pacchetto */
		A3Structure structurePacket = packetMan.newA3Structure(convID, community);
		structurePacket.setSenderCOPNode(jaCOPMan.getCurrentNode(community));
		structurePacket.setStructureNeighbors(jaCOPMan.getStructureNeighbors(community));
		structurePacket.setReceiver(requester);
		/* invio */
		try { send(structurePacket); }
		catch(TranslationException e){
			throw new A3Error(e.getMessage());
		}
		
		/* INOLTRO DELLA RICHIESTA LUNGO BACKWARD LINKS */
		/* recupero dei backward neighbors */
		COPNode[] backwardNeighbors = jaCOPMan.getJoinedNeighbors(community);
		for(int i = 0; i < backwardNeighbors.length; i++){
			if (!backwardNeighbors[i].isSame(excludedNode)){
				/* preparazione del pacchetto di inoltro */
				A3StructureRequest forwardedReq = packetMan.newA3StructureRequest(req.getConvID(), community);
				forwardedReq.setRequester(req.getRequester());
				A3Node receiver = null;
				try { receiver = new A3Node(backwardNeighbors[i].getAddress(), backwardNeighbors[i].getPort()-1); }
				catch(BadInvocationArgumentException e){
					throw new A3Error(e.getMessage());
				}
				forwardedReq.setReceiver(receiver);
				/* invio */
				try { send(forwardedReq); }
				catch(TranslationException e){
					throw new A3Error(e.getMessage());
				}
			}
		}
		
		/* INOLTRO DELLA RICHIESTA LUNGO IL FORWARD LINK */
		COPNode forwardNeighbor = jaCOPMan.getJuncturePoint(community);
		if (forwardNeighbor != null && !forwardNeighbor.isSame(excludedNode)){
			/* preparazione del pacchetto di inoltro */
			A3StructureRequest forwardedReq = packetMan.newA3StructureRequest(req.getConvID(), community);
			forwardedReq.setRequester(req.getRequester());
			A3Node receiver = null;
			try { receiver = new A3Node(forwardNeighbor.getAddress(), forwardNeighbor.getPort()-1); }
			catch(BadInvocationArgumentException e){
				throw new A3Error(e.getMessage());
			}
			forwardedReq.setReceiver(receiver);
			/* invio */
			try { send(forwardedReq); }
			catch(TranslationException e){
				throw new A3Error(e.getMessage());
			}			
		}
		
	}
	
	public static class ConfigurationSet extends A3Task.ConfigurationSet{
		
		public ConfigurationSet(String community, IConversationID convID){
			super(community, convID);
		}
	}
}
