/*
 * 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 NewJoinClient extends JoinRequestClient{
	
	/* campi */
	private COPNode fallenNode = null;
	private boolean optimizedReJoin = false;
	
	/**
	 * @param community
	 * @param conv
	 * @param packetMan
	 * @param statusStore
	 * @param convGraveyard
	 * @param waitingTimeout
	 * @param connectionRank
	 * @param maxDelegationsNumber
	 */
	public NewJoinClient(ConfigurationSet conf, COPPacketManager packetMan, StatusManager statusMan, COPEventListenerManager listenerMan,
			ConversationGraveyard convGraveyard, ControlSystem queue, TaskConversersList taskList,
			boolean isClient, boolean priority) {
		super(conf.sConf, packetMan, statusMan, listenerMan, convGraveyard, queue, taskList, isClient, priority);
		this.fallenNode = conf.fallenNode;
		this.optimizedReJoin = conf.isOptimizedReJoin();
	}
	
	
	/* metodo body */
	protected void body() throws InterruptedException, TranslationException{
		//System.out.println("CLIENT PER NUOVO JOIN");
		jaCop.Debug.print("\nNEW JOIN CLIENT: "+convID.encode());
		//jaCop.Debug.print("\nstruttura: " + (statusMan.hasCompleteStructure(community) ? "completa" : "rotta"));
		
		/* NOTIFICA DI USCITA DALLA COMUNITA' */
		//WARNING questo non dovrebbe essere possibile (vedi ProtocolTrigger)
		//if (statusMan.getNeighbors(community).length == 0){
		//	this.notifyCommunityLeft(community);
			//System.out.println("comunità abbandonata: " + community);
		//	return;
		//}
		
		/* ELABORAZIONE */
		COPNode newJuncture = null;
		/* ricerca del nuovo punto di giunzione */
		COPNode[] neighbors = COPNode.sort(statusMan.getStructureNeighbors(community));
		for(int i = 0; i < neighbors.length; i++){
			if (newJuncture == null){
				newJuncture = neighbors[i];
			}
		}
		/* se non sono stato in grado di determinare un nuovo punto di giunzione */
		if (newJuncture == null){
			//System.out.println("impossibile detrminare un nuovo punto di giunzione");
			return;
		}
		
		//WARNING elimino la notifica di caduta
		/* REGISTRAZIONE DEL CLIENT */
		//registerConverser(newJuncture);
		
		//System.out.println("nuovo punto di giunzione determinato: "+newJuncture.getPort());
		
		//if (fallenNode != null){
			/* NOTIFICA DI CADUTA AL NUOVO PUNTO DI GIUNZIONE */
			/* preparazione pacchetto */
		//	FaultNotification faultNotification = packetMan.newFaultNotification(convID, community);
		//	COPNode[] fallenNodes = { fallenNode };
		//	faultNotification.setFallenNodes(fallenNodes);
		//	faultNotification.setReceiver(newJuncture);
			/* invio */
		//	send(faultNotification);
			
			//System.out.println("notifica di caduta inviata al nodo remoto");
			
			/* ATTESA DI CONFERMA DI OPERAZIONE EFFETTUATA */
			/* ricezione */
		//	COPPacket packet = receive();
			//COPPacket packet = this.receive();
			/* controllo di tipo */
		//	if (!packet.getType().equals(Confirmation.getTypeDescription())){
		//		return;
		//	}
		//}
		
		/* PREPARAZIONE NUOVA RICHIESTA */
		/* terminazione vecchia conversazione */
		//convGraveyard.bury(convID);
		/* cambio id della conversazione */
		//convID = packetMan.newConversation().getConversationID();
		
		/* recupero il calcolatore di fattore di carico */
		ILoadFactorCalculator calc = statusMan.getLoadFactorCalculator(community);
		/* inizializzo gli  attributi del client per richiesta di join */
		this.loadFactorCalculator = calc;
		this.maxDelegationsNumber = this.optimizedReJoin ? JoinRequestClient.UNBOUNDED : JoinRequestClient.FORCE;
		this.receiver = newJuncture;
		/* esecuzione */
		super.body();
	}
	
	public static class ConfigurationSet extends COPTask.ConfigurationSet{
		
		private COPNode fallenNode = null;
		private boolean optimizedReJoin = false;
		private JoinRequestClient.ConfigurationSet sConf = null;
		
		public ConfigurationSet(String community, IConversationID convID){
			super(community, convID);
			sConf = new JoinRequestClient.ConfigurationSet(community, convID);
		}
		
		/**
		 * @return Returns the falleNode.
		 */
		public COPNode getFallenNode() {
			return fallenNode;
		}
		/**
		 * @param falleNode The falleNode to set.
		 */
		public void setFallenNode(COPNode fallenNode) {
			this.fallenNode = fallenNode;
		}
		/**
		 * @return Returns the optimizedReJoin.
		 */
		public boolean isOptimizedReJoin() {
			return optimizedReJoin;
		}
		/**
		 * @param optimizedReJoin The optimizedReJoin to set.
		 */
		public void setOptimizedReJoin(boolean optimizedReJoin) {
			this.optimizedReJoin = optimizedReJoin;
		}
		/* (non-Javadoc)
		 * @see jaCop.protocol.A3ServerTask.ConfigurationSet#setWaitingTimeout(long)
		 */
		public void setWaitingTimeout(long waitingTimeout) {
			super.setWaitingTimeout(waitingTimeout);
			sConf.setWaitingTimeout(waitingTimeout);
		}
	}
	
}
