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

import jaCop.nodeStatus.*;
import jaCop.traffic.*;
import jaCop.domain.*;
import jaCop.exceptions.*;
import jaCop.heartbeat.*;

import convFramework.domain.*;

import java.util.*;

/**
 * @author Lompa
 */
public class NewNeighborsServer extends COPTask{
	
	/**
	 * @param community
	 * @param conv
	 * @param packetMan
	 * @param statusStore
	 * @param convGraveyard
	 * @param waitingTimeout
	 * @param connectionRank
	 * @param maxDelegationsNumber
	 */
	public NewNeighborsServer(ConfigurationSet conf, COPPacketManager packetMan, StatusManager statusMan, COPEventListenerManager listenerMan,
			ConversationGraveyard convGraveyard, ControlSystem queue, TaskConversersList taskList, 
			boolean isClient, boolean priority) {
		super(conf , packetMan, listenerMan, statusMan, convGraveyard, queue, taskList, isClient, priority);
	}
	
	
	/* metodo body */
	protected void body() throws InterruptedException, TranslationException{
		jaCop.Debug.print("\nNEW NEIGHBORS SERVER: "+convID.encode());
		jaCop.Debug.print("struttura: " + (statusMan.hasCompleteStructure(community) ? "completa" : "rotta"));		
		
		
		/* RICEZIONE NOTIFICA */
		//System.out.println("SERVER DI NOTIFICA NUOVI VICINI");
		/* ricezione pacchetto */
		COPPacket packet = receive();
		/* controllo tipo */
		if (!packet.getType().equals(NewNeighbor.getTypeDescription())){
			terminate();
			return;
		}
		/* casting */
		NewNeighbor notification = (NewNeighbor) packet;
		/* recupero dati */
		COPNode notifier = notification.getSender();
		COPNode[] neighborStructure = notification.getNeighborStructure();
		COPNode newNeighbor = notification.getNeighbor();
		
		/* REGISTRAZIONE */
		registerConverser(notifier);
		
		/* CONTROLLI */
		/* controllo che la comunità sia esistente */
		if (!statusMan.existsCommunity(community)){
			return;
		}
		/* se la notifica non viene da un vicino è ignorata */
		if (!statusMan.isNeighbor(community, notifier)){
			return;
		}
		
		//System.out.println("notifica ricevuta");
		
		/* INVIO CONFERMA */
		/* preparazione */
		Confirmation confirmation = packetMan.newConfirmation(convID, community);
		confirmation.setReceiver(notifier);
		/* invio */
		send(confirmation);
		
		/* ATTESA DEL COMMIT */
		/* ricezione */
		COPPacket commit = receive();
		/* controllo del tipo */
		if (!commit.getType().equals(Confirmation.getTypeDescription())){
			return;
		}
		
		/* AGGIORNAMENTI */
		/* se il nodo non  era tra i vicini lo agggiungo */
		boolean isNew = false;
		if (!statusMan.isNeighbor(community, newNeighbor)) {
			statusMan.addNeighbor(community, newNeighbor, false, false);
			isNew = true;
		}
		
		/* AGGIUNTA DELLA STRUTTURA PER IL NUOVO VICINO */
		/* in ogni caso il notficatore è un nodo di struttura per il nuovo vicino */
		/* calcolo i vicini del nodo corente che sono struttura per il nuovo vicino */
		/* aggiunta */
		statusMan.setStructureNeighbors(community, newNeighbor, neighborStructure);
		
		/* notifica dei vicini aggiunti */
		if (isNew) this.notifyNewNeighbor(community, newNeighbor);
		
		//System.out.println("vicini aggiunti");
	}
	
	public static class ConfigurationSet extends COPTask.ConfigurationSet{
		
		public ConfigurationSet(String community, IConversationID convID){
			super(community, convID);
		}
	}
	
}
