/*
 * Created on 29-apr-2004
 */
package jaCop.nodeStatus;

import convFramework.domain.*;

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

import java.util.*;
import java.net.*;

/**
 * @author Lompa
 */
public class StatusStore {
	
	/* flag di istanziazione */
	//private static boolean instantiated = false;
	
	/* campi */
	private Node currentNode = null;
	private TreeMap communitiesStatus = new TreeMap();
	
	
	/**
	 * @param currentNode
	 */
	public StatusStore(Node currentNode) throws InstantiationRuleBrokenException{
		//if (instantiated)
		//	throw new InstantiationRuleBrokenException("Cannot create more than one Status store");
		
		this.currentNode = currentNode;
	}
	
	/**
	 * @return
	 */
	//private static boolean isInstantiated(){
	//	return instantiated;
	//}
	
	/**
	 * Aggiunge una comunità, se non eisste già, altrimenti non fa nulla
	 * @param community
	 */
	public synchronized void addCommunity(String community, ILoadFactorCalculator calc, int connectionRank){
		if (!this.communitiesStatus.containsKey(community))
			this.communitiesStatus.put(community, new CommunityStatusStore(community, calc, connectionRank));
	}
	
	/**
	 * @param community
	 * @return
	 */
	public synchronized boolean existsCommunity(String community){
		return this.communitiesStatus.containsKey(community);
	}
	
	/**
	 * @param community
	 */
	public synchronized void removeCommunity(String community){
		this.communitiesStatus.remove(community);
	}
	
	/**
	 * @return
	 */
	public String[] getCommunities(){
		return (String[]) communitiesStatus.keySet().toArray(new String[communitiesStatus.size()]);
	}
	
	/**
	 * @param community
	 * @return
	 * @throws BadInvocationArgumentException
	 */
	public synchronized COPNode getCurrentNode(String community) {
		InetAddress address = this.currentNode.getAddress();
		int port = this.currentNode.getPort();
		float loadFactor =  existsCommunity(community) ? getCommunityStatusStore(community).getCurrentLoadFactor() : 0;
		try { return new COPNode(address, port, loadFactor, false); }
		catch(convFramework.exceptions.BadInvocationArgumentException e){
			throw new JaCOPError(e.getMessage());
		}
	}
	
	/* metodi privati ************************************************************************/
	
	private synchronized CommunityStatusStore getCommunityStatusStore(String community) {
		if (!this.communitiesStatus.containsKey(community))
			return null;
		else
			return (CommunityStatusStore) this.communitiesStatus.get(community);
	}
	
	/* metodi di delega **********************************************************************/
	
	/**
	 * @param node
	 * @param isJoined
	 */
	public synchronized void addNeighbor(String community, COPNode node, boolean isJoined, boolean isStructure) {
		getCommunityStatusStore(community).addNeighbor(node, isJoined, isStructure);
	}

	public synchronized COPNode getNeighbor(String community, Node node) {
		if (existsCommunity(community))
			return getCommunityStatusStore(community).getNeighbor(node);
		else return null;
	}
	/**
	 * @return
	 */
	public synchronized COPNode[] getNeighbors(String community) {
		if (existsCommunity(community))
			return getCommunityStatusStore(community).getNeighbors();
		else return new COPNode[0];
	}
	/**
	 * @return
	 */
	public synchronized COPNode[] getStructureNeighbors(String community) {
		if (existsCommunity(community))
			return getCommunityStatusStore(community).getStructureNeighbors();
		else return new COPNode[0];
	}
	/**
	 * @return
	 */
	public synchronized COPNode[] getJoinedNeighbors(String community) {
		if (existsCommunity(community))
			return getCommunityStatusStore(community).getJoinedNeighbors();
		else return new COPNode[0];
	}
	/**
	 * @return
	 */
	public synchronized float getCurrentLoadFactor(String community) {
		return getCommunityStatusStore(community).getCurrentLoadFactor();
	}
	/**
	 * @return
	 */
	public synchronized COPNode getJuncturePoint(String community) {
		return getCommunityStatusStore(community).getJuncturePoint();
	}
	/**
	 * @param node
	 * @return
	 * @throws jaCop.exceptions.BadInvocationArgumentException
	 */
	public synchronized boolean isJoined(String community, COPNode node)  {
		return getCommunityStatusStore(community).isJoined(node);
	}
	/**
	 * @param node
	 * @return
	 * @throws jaCop.exceptions.BadInvocationArgumentException
	 */
	public synchronized boolean isStructure(String community, COPNode node)  {
		return getCommunityStatusStore(community).isStructure(node);
	}
	/**
	 * @param node
	 * @return
	 */
	public synchronized boolean isNeighbor(String community, COPNode node) {
		return getCommunityStatusStore(community).isNeighbor(node);
	}
	/**
	 * @param node
	 */
	public synchronized void removeNeighbor(String community, COPNode node) {
		getCommunityStatusStore(community).removeNeighbor(node);
	}
	/**
	 * @param node
	 * @param joined
	 * @throws jaCop.exceptions.BadInvocationArgumentException
	 */
	public synchronized void setJoined(String community, COPNode node, boolean joined) {
		getCommunityStatusStore(community).setJoined(node, joined);
	}
	/**
	 * @param node
	 * @param joined
	 * @throws jaCop.exceptions.BadInvocationArgumentException
	 */
	public synchronized void setStructure(String community, COPNode node, boolean isStructure) {
		getCommunityStatusStore(community).setStructure(node, isStructure);
	}
	/**
	 * @param node
	 * @throws jaCop.exceptions.BadInvocationArgumentException
	 */
	public synchronized void setJuncturePoint(String community, COPNode node) {
		getCommunityStatusStore(community).setJuncturePoint(node);
	}
	/**
	 * @param node
	 * @param loadFactor
	 * @throws jaCop.exceptions.BadInvocationArgumentException
	 */
	public synchronized void setLoadFactor(String community, COPNode node, float loadFactor) {
		getCommunityStatusStore(community).setLoadFactor(node, loadFactor);
	}
	
	public synchronized COPNode[] getStructureNeighbors(String community, COPNode node){
		if (existsCommunity(community))
			return getCommunityStatusStore(community).getStructureNeighbors(node);
		else return new COPNode[0];		
	}

	public synchronized void addStructureNeighbor(String community, COPNode node, COPNode newNode){
		getCommunityStatusStore(community).addStructureNeighbor(node, newNode);
	}
	
	public synchronized void setStructureNeighbors(String community, COPNode node, COPNode[] nodes){
		getCommunityStatusStore(community).setStructureNeighbors(node, nodes);
	}

	public synchronized void removeStructureNeighbor(String community, COPNode node, COPNode oldNode){
		getCommunityStatusStore(community).removeStructureNeighbor(node, oldNode);
	}

	public boolean hasCompleteStructure(String community){
		return getCommunityStatusStore(community).hasCompleteStructure();
	}

	public void breakStructure(String community){
		getCommunityStatusStore(community).breakStructure();
	}
	
	public void repairStructure(String community, int breaks){
		getCommunityStatusStore(community).repairStructure(breaks);
	}
	
	public int getStructureBreaksNumber(String community){
		return getCommunityStatusStore(community).getStructureBreaksNumber();
	}
	
	public ILoadFactorCalculator getLoadFactorCalculator(String community){
		return getCommunityStatusStore(community).getLoadFactorCalcuclator();
	}
	
	public int getConnectionRank(String community){
		return getCommunityStatusStore(community).getConnectionRank();
	}
	
	public boolean isCoreNode(String community){
		return getCommunityStatusStore(community).isCoreNode();
	}
}
