/*
 * Created on 28-apr-2004
 */
package jaCop.traffic;

import jaCop.domain.*;
import jaCop.exceptions.*;

import convFramework.facade.*;
import convFramework.domain.*;

import jaCop.nodeStatus.*;

/**
 * @author Lompa
 */
public class COPPacketManager {
	
	/* flag di istanziazione */
	//private static boolean instantiated = false;
	
	/* campi */
	private TrafficManager trafficMan = null;
	private COPPacketTranslator translator = null;
	private StatusStore store = null;
	
	/**
	 * @param trafficMan
	 */
	public COPPacketManager(TrafficManager trafficMan, StatusStore store){
		this.trafficMan = trafficMan;
		this.translator = new COPPacketTranslator(new COPXMLEncoder(), new COPXMLDecoder());
		this.store = store;
	}
	
	
	public synchronized JoinRequest newJoinRequest(IConversationID convID, String community){
		ContentPacket packet = trafficMan.newPacket(convID);
		COPNode sender = null;
		try {
			/* una richiesta di join può essere anche relativa ad una comunità non esistente */
			float loadFactor = store.existsCommunity(community) ? store.getCurrentLoadFactor(community) : 0;
			sender = new COPNode(trafficMan.getCurrentNode().getAddress(), trafficMan.getCurrentNode().getPort(), loadFactor, false);
		}
		catch(convFramework.exceptions.BadInvocationArgumentException e){ throw new JaCOPError("Invailid port for current node"); }
		return new JoinRequest(community, sender, convID, packet.getPacketID());
	}
	
	public synchronized NewNeighbor newNewNeighbors(IConversationID convID, String community){
		ContentPacket packet = trafficMan.newPacket(convID);
		COPNode sender = null;
		try {
			float loadFactor = store.existsCommunity(community) ? store.getCurrentLoadFactor(community) : 0;
			sender = new COPNode(trafficMan.getCurrentNode().getAddress(), trafficMan.getCurrentNode().getPort(), loadFactor, false);
		}
		catch(convFramework.exceptions.BadInvocationArgumentException e){ throw new JaCOPError("Invailid port for current node"); }
		return new NewNeighbor(community, sender, convID, packet.getPacketID());
	}
	
	public synchronized NewStructure newNewStructure(IConversationID convID, String community){
		ContentPacket packet = trafficMan.newPacket(convID);
		COPNode sender = null;
		try {
			float loadFactor = store.existsCommunity(community) ? store.getCurrentLoadFactor(community) : 0;
			sender = new COPNode(trafficMan.getCurrentNode().getAddress(), trafficMan.getCurrentNode().getPort(), loadFactor, false);
		}
		catch(convFramework.exceptions.BadInvocationArgumentException e){ throw new JaCOPError("Invalid port for current node"); }
		return new NewStructure(community, sender, convID, packet.getPacketID());
	}
	
	public synchronized Confirmation newConfirmation(IConversationID convID, String community){
		ContentPacket packet = trafficMan.newPacket(convID);
		COPNode sender = null;
		try {
			float loadFactor = store.existsCommunity(community) ? store.getCurrentLoadFactor(community) : 0;
			sender = new COPNode(trafficMan.getCurrentNode().getAddress(), trafficMan.getCurrentNode().getPort(), loadFactor, false);
		}
		catch(convFramework.exceptions.BadInvocationArgumentException e){ throw new JaCOPError("Invalid port for current node"); }
		return new Confirmation(community, sender, convID, packet.getPacketID());
	}
	
	public synchronized Refusal newRefusal(IConversationID convID, String community){
		ContentPacket packet = trafficMan.newPacket(convID);
		COPNode sender = null;
		try {
			float loadFactor = store.existsCommunity(community) ? store.getCurrentLoadFactor(community) : 0;
			sender = new COPNode(trafficMan.getCurrentNode().getAddress(), trafficMan.getCurrentNode().getPort(), loadFactor, false);
		}
		catch(convFramework.exceptions.BadInvocationArgumentException e){ throw new JaCOPError("Invailid port for current node"); }
		return new Refusal(community, sender, convID, packet.getPacketID());
	}
	
	public synchronized Heartbeat newHeartbeat(IConversationID convID, String community){
		ContentPacket packet = trafficMan.newPacket(convID);
		COPNode sender = null;
		try {
			float loadFactor = store.existsCommunity(community) ? store.getCurrentLoadFactor(community) : 0;
			sender = new COPNode(trafficMan.getCurrentNode().getAddress(), trafficMan.getCurrentNode().getPort(), loadFactor, false);
		}
		catch(convFramework.exceptions.BadInvocationArgumentException e){ throw new JaCOPError("Invailid port for current node"); }
		return new Heartbeat(community, sender, convID, packet.getPacketID());
	}
	
	public synchronized FaultNotification newFaultNotification(IConversationID convID, String community){
		ContentPacket packet = trafficMan.newPacket(convID);
		COPNode sender = null;
		try {
			float loadFactor = store.existsCommunity(community) ? store.getCurrentLoadFactor(community) : 0;
			sender = new COPNode(trafficMan.getCurrentNode().getAddress(), trafficMan.getCurrentNode().getPort(), loadFactor, false);
		}
		catch(convFramework.exceptions.BadInvocationArgumentException e){ throw new JaCOPError("Invailid port for current node"); }
		return new FaultNotification(community, sender, convID, packet.getPacketID());
	}
	
	public synchronized Delegation newDelegation(IConversationID convID, String community){
		ContentPacket packet = trafficMan.newPacket(convID);
		COPNode sender = null;
		try {
			float loadFactor = store.existsCommunity(community) ? store.getCurrentLoadFactor(community) : 0;
			sender = new COPNode(trafficMan.getCurrentNode().getAddress(), trafficMan.getCurrentNode().getPort(), loadFactor, false);
		}
		catch(convFramework.exceptions.BadInvocationArgumentException e){ throw new JaCOPError("Invailid port for current node"); }
		return new Delegation(community, sender, convID, packet.getPacketID());
	}
	
	public synchronized void send(COPPacket packet) throws TranslationException{
		trafficMan.sendPacket(translator.translate(packet));
	}
	
	public COPPacket receive(IConversationID convID) throws TranslationException, InterruptedException{
		ContentPacket packet = trafficMan.receivePacket(convID);
		synchronized(this){
			COPPacket p = translator.translate(packet);
			return p;
		}
	}
	
	public synchronized IConversation newConversation(){
		return this.trafficMan.newConversation();
	}
	
	public synchronized void removeConversation(IConversationID convID){
		trafficMan.removeConversation(convID);
	}
	
	/**
	 * @param packet
	 * @return
	 * @throws TranslationException
	 */
	public synchronized COPPacket translate(ContentPacket packet)
			throws TranslationException {
		return translator.translate(packet);
	}
}
