// ----------------------------------------------------------------------------
// CERTI - HLA RunTime Infrastructure
// Copyright (C) 2002-2005  ONERA
//
// This file is part of CERTI
//
// CERTI is free software ; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation ; either version 2 of the License, or
// (at your option) any later version.
//
// CERTI is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY ; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program ; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// $Id: Federation.cc,v 3.137 2010/11/09 22:24:26 erk Exp $
// ----------------------------------------------------------------------------

#include <config.h>
#include "Federation.hh"
#include "NM_Classes.hh"
#include <cstring>
#include <cerrno>
#include <memory>
#include <sys/stat.h>
#include <time.h>

#include "fed.hh"
#include "XmlParser.hh"
#include "Object.hh"
#include "ObjectAttribute.hh"
#include "ObjectSet.hh"
#include "ObjectClassSet.hh"
#include "InteractionSet.hh"

#include "ObjectClassAttribute.hh"
#include "PrettyDebug.hh"
#include "LBTS.hh"
#include "NM_Classes.hh"

using std::pair ;
using std::ifstream ;
using std::ios ;
using std::cout ;
using std::endl ;
using std::string ;
using std::list ;
using std::cerr ;
using std::vector ;

// Definitions
#ifdef HAVE_XML
#define ROOT_NODE (const xmlChar*) "rtigSaveData"
#define NODE_FEDERATION (const xmlChar*) "federation"
#define NODE_FEDERATE (const xmlChar*) "federate"
#endif // HAVE_XML

#ifdef _WIN32
# define strcasecmp stricmp
#endif

namespace certi {

class XmlParser ;

namespace rtig {

static PrettyDebug D("FEDERATION", __FILE__);
static PrettyDebug G("GENDOC",__FILE__);

/**
 * \defgroup certi_FOM_FileSearch CERTI FOM file search algorithm
 * RTIG tries to open FOM file from different
 * predefined places:
 *
 * -# bare filename considered as a path provided through FEDid_name
 * -# getenv(CERTI_HOME)+"/share/federations"+ FEDid_name
 * -# installation place plus FEDid_name
 *     PACKAGE_INSTALL_PREFIX + "/share/federation/" + FEDid_name
 * -# on Unix "/usr/local/share/federation/" + FEDid_name
 *    for backward compatibility reason.
 */

#ifdef FEDERATION_USES_MULTICAST

Federation::Federation(const std::string& federation_name,
		FederationHandle federation_handle,
		SocketServer &socket_server,
		AuditFile &audit_server,
		SocketMC *mc_link,
		int theVerboseLevel)
#else
	Federation::Federation(const std::string& federation_name,
			Handle federation_handle,
			SocketServer &socket_server,
			AuditFile &audit_server,
			const std::string& FEDid_name,
			int theVerboseLevel)
#endif
throw (CouldNotOpenFED, ErrorReadingFED, MemoryExhausted, SecurityError,
		RTIinternalError)
		: federateHandles(1), objectHandles(1), saveInProgress(false),
		  restoreInProgress(false), saveStatus(true), restoreStatus(true),
		  verboseLevel(theVerboseLevel)

{
	//    fedparser::FedParser *fed_reader ;
	STAT_STRUCT file_stat;

#ifdef FEDERATION_USES_MULTICAST // -----------------
	// Initialize Multicast
	if (mc_link == NULL) {
		D.Out(pdExcept, "Null Multicast socket for new Federation.");
		throw RTIinternalError("NULL Multicast socket for new Federation.");
	}

	D.Out(pdInit, "New Federation %d will use Multicast.", federation_handle);
	MCLink = mc_link ;
#endif // FEDERATION_USES_MULTICAST // --------------

	G.Out(pdGendoc,"enter Federation::Federation");
	// Allocates Name
	if (federation_name.empty() || (federation_handle == 0))
		throw RTIinternalError("Null init parameter in Federation creation.");

	name = federation_name;

	// Default Attribute values
	handle = federation_handle;
	FEDid  = FEDid_name;

	D.Out(pdInit, "New Federation created with Handle %d, now reading FOM.",
			handle);

	// Initialize the Security Server.
	server = new SecurityServer(socket_server, audit_server, handle);

	// Read FOM File to initialize Root Object.
	root = new RootObject(server);

	if (verboseLevel>0) {
		cout << "New federation: " << name << endl ;
	}

	// We should try to open FOM file from different
	// predefined places:
	//
	// 1 - bare filename considered as a path provided through FEDid_name
	//
	// 2 - getenv(CERTI_HOME)+"/share/federations"+ FEDid_name
	//
	// 3 - Installation place plus FEDid_name
	//     PACKAGE_INSTALL_PREFIX + "/share/federation/" + FEDid_name
	//
	// 4 - "/usr/local/share/federation/" +  FEDid_name
	//     last resort Unix-only case [for backward compatibility]
	//
	string filename   = FEDid;
	bool   filefound  = false;
	if (verboseLevel>0) {
		cout << "Looking for FOM file... " << endl ;

		cout << "   Trying... " << filename;
	}
	filefound = (0==STAT_FUNCTION(filename.c_str(),&file_stat));

#ifdef _WIN32
	if (!filefound) {
		char temp[260];
		if (verboseLevel>0) {
			cout << " --> cannot access." <<endl;
		}
		GetCurrentDirectory(260,temp);
		filename = string(temp);
		filename = filename + "\\share\\federations\\"+FEDid_name;
		if (verboseLevel>0) {
			cout << "   Now trying..." << filename;
		}
		filefound = (0==STAT_FUNCTION(filename.c_str(),&file_stat));
	}

	if (!filefound && (NULL!=getenv("CERTI_HOME"))) {
		if (verboseLevel>0) {
			cout << " --> cannot access." <<endl;
		}
		filename = string(getenv("CERTI_HOME"))+"\\share\\federations\\"+FEDid_name;
		if (verboseLevel>0) {
			cout << "   Now trying..." << filename;
		}
		filefound = (0==STAT_FUNCTION(filename.c_str(),&file_stat));
	}

	if (!filefound) {
		if (verboseLevel>0) {
			cout << " --> cannot access." <<endl;
		}
		filename = PACKAGE_INSTALL_PREFIX "\\share\\federations\\"+FEDid_name;
		if (verboseLevel>0) {
			cout << "   Now trying..." << filename;
		}
		filefound = (0==STAT_FUNCTION(filename.c_str(),&file_stat));
	}
#else
	if (!filefound && (NULL!=getenv("CERTI_HOME"))) {
		if (verboseLevel>0) {
			cout << " --> cannot access." <<endl;
		}
		filename = string(getenv("CERTI_HOME"))+"/share/federations/"+FEDid_name;
		if (verboseLevel>0) {
			cout << "   Now trying..." << filename;
		}
		filefound = (0==STAT_FUNCTION(filename.c_str(),&file_stat));
	}

	if (!filefound) {
		if (verboseLevel>0) {
			cout << " --> cannot access." << endl;
		}
		filename = PACKAGE_INSTALL_PREFIX "/share/federations/"+FEDid_name;
		if (verboseLevel>0) {
			cout << "   Now trying..." << filename;
		}
		filefound = (0==STAT_FUNCTION(filename.c_str(),&file_stat));
	}

	if (!filefound) {
		if (verboseLevel>0) {
			cout << " --> cannot access." << endl;
		}
		filename = "/usr/local/share/federations/"+FEDid_name;
		if (verboseLevel>0) {
			cout << "   Now trying..." << filename;
		}
		filefound = (0==STAT_FUNCTION(filename.c_str(),&file_stat));
	}
#endif

	if (!filefound) {
		if (verboseLevel>0) {
			cout << " --> cannot access." <<endl;
		}
		cerr << "Next step will fail"<<endl;
		G.Out(pdGendoc,"exit Federation::Federation on exception CouldNotOpenFED");
		throw CouldNotOpenFED("RTIG cannot find FED file.");
	}

	// now really assign FEDid
	FEDid = filename;

	// Try to open to verify if file exists
	std::ifstream fedTry(FEDid.c_str());
	if (!fedTry.is_open())
	{
		if (verboseLevel>0) {
			cout << "... failed : ";
		}
		G.Out(pdGendoc,"exit Federation::Federation on exception CouldNotOpenFED");
		throw CouldNotOpenFED("RTIG have found but cannot open FED file");
	}
	else {
		if (verboseLevel>0) {
			cout << "... opened." << endl ;
		}
		fedTry.close();
	}

	int  nbcar_filename = filename.length() ;
	bool is_a_fed       = false ;
	bool is_an_xml      = false ;

	// hope there is a . before fed or xml
	if ( filename[nbcar_filename-4] != '.' )
	{
		G.Out(pdGendoc,"exit Federation::Federation on exception CouldNotOpenFED");
		throw CouldNotOpenFED("Incorrect FED file name, cannot find "
				"extension (character '.' is missing [or not in reverse 4th place])");
	}

	string extension = filename.substr(nbcar_filename-3,3) ;
	D.Out(pdTrace,"filename is: %s (extension is <%s>",filename.c_str(),extension.c_str());
	if ( !strcasecmp(extension.c_str(),"fed") )
	{
		is_a_fed = true ;
		D.Out(pdTrace, "Trying to use .fed file");
	}
	else if  ( !strcasecmp(extension.c_str(),"xml") )
	{
		is_an_xml = true ;
		D.Out(pdTrace, "Trying to use .xml file");
	}
	else {
		G.Out(pdGendoc,"exit Federation::Federation on exception CouldNotOpenFED");
		throw CouldNotOpenFED("Incorrect FED file name : nor .fed nor .xml file");
	}

	std::ifstream fedFile(filename.c_str());

	if (fedFile.is_open())
	{
		fedFile.close();
		if ( is_a_fed )
		{
			// parse FED file and show the parse on stdout if verboseLevel>=2
			int err = fedparser::build(filename.c_str(), root, (verboseLevel>=2));
			if (err != 0 )
			{
				G.Out(pdGendoc,"exit Federation::Federation on exception ErrorReadingFED");
				throw ErrorReadingFED("fed parser found error in FED file");
			}

			// Retrieve the FED file last modification time(for Audit)
			STAT_STRUCT StatBuffer ;
#if defined(_WIN32) && _MSC_VER >= 1400
			char MTimeBuffer[26];
#else
			char *MTimeBuffer ;
#endif

			if (STAT_FUNCTION(filename.c_str(), &StatBuffer) == 0) {
#if defined(_WIN32) && _MSC_VER >= 1400
				ctime_s(&MTimeBuffer[0],26,&StatBuffer.st_mtime);
#else
				MTimeBuffer = ctime(&StatBuffer.st_mtime);
#endif
				MTimeBuffer[strlen(MTimeBuffer) - 1] = 0 ; // Remove trailing \n
				server->audit << "(Last modified " << MTimeBuffer << ")" ;
			}
			else
				server->audit << "(could not retrieve last modif time, errno "
				<< errno << ")." ;
		}
		else if ( is_an_xml )
		{
			if (XmlParser::exists()) {
				XmlParser *parser = new XmlParser(root);
				server->audit << ", XML File : " << filename ;

				try {
					parser->parse(filename);
				}
				catch (Exception *e) {
					delete parser ;
					delete server ;
					server = NULL ;
					delete root ;
					root = NULL ;
					throw e ;
				}
				delete parser ;
			}
			else {
				cout << "Compiled without XML support" << endl ;
				G.Out(pdGendoc,"exit Federation::Federation on exception CouldNotOpenFED");
				throw CouldNotOpenFED("Could not parse XML file. (Compiled without XML lib.)");
			}
		}
	}

	minNERx.setZero();
	G.Out(pdGendoc,"exit Federation::Federation");

}

// ----------------------------------------------------------------------------
// Destructor
Federation::~Federation()
{
	D.Out(pdInit, "Destroying Federation %d...", handle);

	// If there are Federates, delete them all!
	//     for (list<Federate *>::const_iterator i = begin(); i != end(); i++) {
	//         delete(*i);
	//     }
	//     clear();

	// Free local allocations
	delete root ;
	delete server ;

#ifdef FEDERATION_USES_MULTICAST
	FermerConnexion(mc_link);
	delete mc_link ;
#endif

}

// ----------------------------------------------------------------------------
//! Returns the number of federates in federation.
int
Federation::getNbFederates() const
{
	return _handleFederateMap.size();
}

// ----------------------------------------------------------------------------
//! Return true if federation is being synchronized.
bool
Federation::isSynchronizing() const
{
	return !synchronizationLabels.empty();
}

// ----------------------------------------------------------------------------
//! Returns the federation handle.
Handle
Federation::getHandle() const
{
	return handle ;
}

// ----------------------------------------------------------------------------
//! Returns the federation name given in 'Create Federation Execution'.
const std::string&
Federation::getName() const
{
	return name;
}

// ----------------------------------------------------------------------------
//! Returns the number of federates regulator.
int
Federation::getNbRegulators() const
{
	return regulators.size();
}

// ----------------------------------------------------------------------------
//! Returns the FEDid name given in 'Create Federation Execution'.
const std::string&
Federation::getFEDid() const
{
	return FEDid;
}

// ----------------------------------------------------------------------------
/*! Add the Federate to the Federation, and return its new federate handle.
  Also send
  Null messages from all others federates to initialize its LBTS, and
  finally a RequestPause message if the Federation is already paused.
 */
FederateHandle
Federation::add(const std::string& federate_name, SocketTCP *tcp_link)
throw (FederateAlreadyExecutionMember, MemoryExhausted, RTIinternalError)
{
	try {
		getFederate(federate_name);
		throw FederateAlreadyExecutionMember("");
	}
	catch (FederateNotExecutionMember &e) {
		// Nothing to do.
	}

	FederateHandle federate_handle = federateHandles.provide();
	_handleFederateMap.insert(HandleFederateMap::value_type(federate_handle, Federate(federate_name, federate_handle)));
	Federate& federate = getFederate(federate_handle);
	D.Out(pdInit, "Federate %d joined Federation %d.", federate_handle, handle);

	// Send, to the newly added federate, a Null message from each regulating
	// federate (i) with their logical time h(i). This permits to calculate
	// its LBTS.
	NM_Message_Null nullMessage;
	NM_Announce_Synchronization_Point ASPMessage;
	try {
		std::vector<LBTS::FederateClock> v ;
		regulators.get(v);

		for (unsigned int i = 0 ; i < v.size(); ++i) {
			nullMessage.setFederation(handle);
			nullMessage.setFederate(v[i].first);
			nullMessage.setDate(v[i].second);
			D.Out(pdTerm,
					"Sending NULL message(type %d) from %d to new federate.",
					nullMessage.getMessageType(), nullMessage.getFederate());

			nullMessage.send(tcp_link,NM_msgBufSend);
		}

		// If federation is synchronizing, put federate in same state.
		if (isSynchronizing()) {
			ASPMessage.setFederate(federate_handle);
			ASPMessage.setFederation(handle);

			std::map<std::string, std::string>::const_iterator i ;
			i = synchronizationLabels.begin();
			for (; i != synchronizationLabels.end(); i++) {
				ASPMessage.setLabel((*i).first);
				ASPMessage.setTag((*i).second);
				D.Out(pdTerm, "Sending synchronization message %s (type %d)"
						" to the new Federate.", (*i).first.c_str(), ASPMessage.getMessageType());

				ASPMessage.send(tcp_link,NM_msgBufSend);
				federate.addSynchronizationLabel((*i).first);
			}
		}
	}
	catch (NetworkError) {
		throw RTIinternalError("Network Error while initializing federate.");
	}

	return federate_handle ;
}

// ----------------------------------------------------------------------------
// Set Federate's attribute IsConstrained to true.
/*! FIXME: name/ merge with removeConstrained.
 */
void
Federation::addConstrained(FederateHandle federate_handle)
throw (FederateNotExecutionMember,
		SaveInProgress,
		RestoreInProgress,
		RTIinternalError)
		{
	// It may throw FederateNotExecutionMember
	Federate &federate = getFederate(federate_handle);

	if (federate.isConstrained()) {
		D.Out(pdExcept, "Federate %d already constrained.", federate_handle);
		throw RTIinternalError("Time Constrained already enabled.");
	}

	federate.setConstrained(true);
	D.Out(pdTerm, "Federation %d: Federate %d is now constrained.",
			handle, federate_handle);
		}

// ----------------------------------------------------------------------------
// Set Class Relevance Advisory Switch
void
Federation::setClassRelevanceAdvisorySwitch(FederateHandle federate_handle)
throw (FederateNotExecutionMember,
		SaveInProgress,
		RestoreInProgress,
		RTIinternalError)
		{
	// It may throw FederateNotExecutionMember
	Federate &federate = getFederate(federate_handle);

	if (federate.isClassRelevanceAdvisorySwitch()) {
		D.Out(pdExcept, "Federate %d already set CRA switch.", federate_handle);
		throw RTIinternalError("CRA switch already enabled.");
	}

	federate.setClassRelevanceAdvisorySwitch(true);
	D.Out(pdTerm, "Federation %d: Federate %d sets CRA switch.",
			handle, federate_handle);
		}

// ----------------------------------------------------------------------------
// Set Interaction Relevance Advisory Switch
void
Federation::setInteractionRelevanceAdvisorySwitch(FederateHandle federate_handle)
throw (FederateNotExecutionMember,
		SaveInProgress,
		RestoreInProgress,
		RTIinternalError)
		{
	// It may throw FederateNotExecutionMember
	Federate &federate = getFederate(federate_handle);

	if (federate.isInteractionRelevanceAdvisorySwitch()) {
		D.Out(pdExcept, "Federate %d already set IRA switch.", federate_handle);
		throw RTIinternalError("IRA switch already enabled.");
	}

	federate.setInteractionRelevanceAdvisorySwitch(true);
	D.Out(pdTerm, "Federation %d: Federate %d sets IRA switch.",
			handle, federate_handle);
		}

// ----------------------------------------------------------------------------
// Set Attribute Relevance Advisory Switch
void
Federation::setAttributeRelevanceAdvisorySwitch(FederateHandle federate_handle)
throw (FederateNotExecutionMember,
		SaveInProgress,
		RestoreInProgress,
		RTIinternalError)
		{
	// It may throw FederateNotExecutionMember
	Federate &federate = getFederate(federate_handle);

	if (federate.isAttributeRelevanceAdvisorySwitch()) {
		D.Out(pdExcept, "Federate %d already set ARA switch.", federate_handle);
		throw RTIinternalError("ARA switch already enabled.");
	}

	federate.setAttributeRelevanceAdvisorySwitch(true);
	D.Out(pdTerm, "Federation %d: Federate %d sets ARA switch.",
			handle, federate_handle);
		}

// ----------------------------------------------------------------------------
// Set Attribute Scope Advisory Switch
void
Federation::setAttributeScopeAdvisorySwitch(FederateHandle federate_handle)
throw (FederateNotExecutionMember,
		SaveInProgress,
		RestoreInProgress,
		RTIinternalError)
		{
	// It may throw FederateNotExecutionMember
	Federate &federate = getFederate(federate_handle);

	if (federate.isAttributeScopeAdvisorySwitch()) {
		D.Out(pdExcept, "Federate %d already set ASA switch.", federate_handle);
		throw RTIinternalError("ASA switch already enabled.");
	}

	federate.setAttributeScopeAdvisorySwitch(true);
	D.Out(pdTerm, "Federation %d: Federate %d sets ASA switch.",
			handle, federate_handle);
		}

// ----------------------------------------------------------------------------
// Clear Class Relevance Advisory Switch
void
Federation::unsetClassRelevanceAdvisorySwitch(FederateHandle federate_handle)
throw (FederateNotExecutionMember,
		SaveInProgress,
		RestoreInProgress,
		RTIinternalError)
		{
	// It may throw FederateNotExecutionMember
	Federate &federate = getFederate(federate_handle);

	if (!federate.isClassRelevanceAdvisorySwitch()) {
		D.Out(pdExcept, "Federate %d did not set CRA switch.", federate_handle);
		throw RTIinternalError("CRA switch not enabled.");
	}

	federate.setClassRelevanceAdvisorySwitch(false);
	D.Out(pdTerm, "Federation %d: Federate %d clears CRA switch.",
			handle, federate_handle);
		}

// ----------------------------------------------------------------------------
// Clear Interaction Relevance Advisory Switch
void
Federation::unsetInteractionRelevanceAdvisorySwitch(FederateHandle federate_handle)
throw (FederateNotExecutionMember,
		SaveInProgress,
		RestoreInProgress,
		RTIinternalError)
		{
	// It may throw FederateNotExecutionMember
	Federate &federate = getFederate(federate_handle);

	if (!federate.isInteractionRelevanceAdvisorySwitch()) {
		D.Out(pdExcept, "Federate %d did not set IRA switch.", federate_handle);
		throw RTIinternalError("IRA switch not enabled.");
	}

	federate.setInteractionRelevanceAdvisorySwitch(false);
	D.Out(pdTerm, "Federation %d: Federate %d clears IRA switch.",
			handle, federate_handle);
		}

// ----------------------------------------------------------------------------
// Clear Attribute Relevance Advisory Switch
void
Federation::unsetAttributeRelevanceAdvisorySwitch(FederateHandle federate_handle)
throw (FederateNotExecutionMember,
		SaveInProgress,
		RestoreInProgress,
		RTIinternalError)
		{
	// It may throw FederateNotExecutionMember
	Federate &federate = getFederate(federate_handle);

	if (!federate.isAttributeRelevanceAdvisorySwitch()) {
		D.Out(pdExcept, "Federate %d did not set ARA switch.", federate_handle);
		throw RTIinternalError("ARA switch not enabled.");
	}

	federate.setAttributeRelevanceAdvisorySwitch(false);
	D.Out(pdTerm, "Federation %d: Federate %d clears ARA switch.",
			handle, federate_handle);
		}

// ----------------------------------------------------------------------------
//  Clear Attribute Scope Advisory Switch
void
Federation::unsetAttributeScopeAdvisorySwitch(FederateHandle federate_handle)
throw (FederateNotExecutionMember,
		SaveInProgress,
		RestoreInProgress,
		RTIinternalError)
		{
	// It may throw FederateNotExecutionMember
	Federate &federate = getFederate(federate_handle);

	if (!federate.isAttributeScopeAdvisorySwitch()) {
		D.Out(pdExcept, "Federate %d did not set ASA switch.", federate_handle);
		throw RTIinternalError("ASA switch not enabled.");
	}

	federate.setAttributeScopeAdvisorySwitch(false);
	D.Out(pdTerm, "Federation %d: Federate %d clears ASA switch.",
			handle, federate_handle);
		}

// ----------------------------------------------------------------------------
//! Add the Federate to the Regulators List.
/*! Check if it's already present, but not if the Time 'theTime' is allowed
  or not.
 */
void
Federation::addRegulator(FederateHandle federate_handle, FederationTime time)
throw (FederateNotExecutionMember,
		SaveInProgress,
		RestoreInProgress,
		RTIinternalError)
		{
	// It may throw FederateNotExecutionMember
	Federate &federate = getFederate(federate_handle);

	// It may throw RTIinternalError if Federate was not regulators.
	regulators.insert(federate_handle, time);
	federate.setRegulator(true);

	D.Out(pdTerm, "Federation %d: Federate %d is now a regulator(Time=%f).",
			handle, federate_handle, time.getTime());

	NM_Set_Time_Regulating msg ;
	msg.setException(e_NO_EXCEPTION);
	msg.setFederation(handle);
	msg.setFederate(federate_handle);
	msg.regulatorOn();
	msg.setDate(time);

	this->broadcastAnyMessage(&msg, 0,false);
}

void
Federation::getFOM(NM_Join_Federation_Execution& objectModelData)
{
	root->convertToSerializedFOM(objectModelData);
}

bool
Federation::updateLastNERxForFederate(FederateHandle federate, FederationTime date)
throw (FederateNotExecutionMember) {
	bool retval = false;
	FederationTime newMin;
	Federate& f = getFederate(federate);

	f.setLastNERxValue(date);
	Debug(D,pdDebug) << "Federate <"<<f.getName()<<"> has new NERx value="<<date.getTime() << std::endl;
	newMin = computeMinNERx();
	if (newMin > minNERx) {
		Debug(D,pdDebug) << "New minNERx =" << newMin << std::endl;
		retval = true;
		minNERx = newMin;
		/* if a new Min is found then we shall reset the NERx status of ALL NERing federates
		 * Rationale: an Anonymous NULL MESSAGE dated with newMin will be sent to them.
		 *            after that a NERing Federate which remains in its NERing loop should
		 *            send a new NULL PRIME message.
		 */
		for (HandleFederateMap::iterator i = _handleFederateMap.begin(); i != _handleFederateMap.end(); ++i) {
			if (i->second.isUsingNERx()) {
				//i->second.setLastNERxValue(FedTime(0.0)); // not needed
				i->second.setIsUsingNERx(false);
				Debug(D,pdDebug) << "Federate <" << i->second.getName() <<"> not NERing anymore." <<  std::endl;
			}
		}
	}
	return retval;
} /* end of updateLastNERxForFederate */

FederationTime
Federation::computeMinNERx() {
	FederationTime retval;
	uint32_t       nbFed;
	LBTS           NER_regulators;
	std::vector<LBTS::FederateClock> clocks;
	retval.setZero();
	nbFed = 0;
	regulators.get(clocks);

	/* Build a set of clocks */
	for (std::vector<LBTS::FederateClock>::iterator it = clocks.begin(); it!=clocks.end(); ++it) {
		FederateHandle h=it->first;
		HandleFederateMap::iterator f = _handleFederateMap.find(h);
		if (f->second.isUsingNERx()) {
			nbFed++;
			NER_regulators.insert(h,f->second.getLastNERxValue());
		} else {
			NER_regulators.insert(h,it->second);
		}
	}

	/* compute the new NERx LBTS (minimum) */
	NER_regulators.compute();
	retval = NER_regulators.getLBTSValue();
	Debug(D,pdDebug) << "MinNERx =" << retval.getTime() << std::endl;

	/* the minimum is different from 0 iff more than 2 federate use NERx */
	if (nbFed<2) {
		retval.setZero();
	}

	Debug(D,pdDebug) << "computeMinNERx ="<<retval.getTime() << std::endl;
	return retval;
} /* end of computeMinNERx */

void
Federation::broadcastAnyMessage(NetworkMessage *msg,
		FederateHandle except_federate, bool anonymous)
{
	Socket *socket = NULL ;

	// Broadcast the message 'msg' to all Federates in the Federation
	// except to Federate whose Handle is 'Except_Federate'.
	for (HandleFederateMap::iterator i = _handleFederateMap.begin(); i != _handleFederateMap.end(); ++i) {
		if (anonymous || (i->first != except_federate)) {
			try {
#ifdef HLA_USES_UDP
				socket = server->getSocketLink(i->second.getHandle(), BEST_EFFORT);
#else
				socket = server->getSocketLink(i->second.getHandle());
#endif
				msg->send(socket,NM_msgBufSend);
			}
			catch (RTIinternalError &e) {
				Debug(D, pdExcept) << "Reference to a killed Federate while "
						<< "broadcasting." << endl ;
			}
			catch (NetworkError &e) {
				D.Out(pdExcept, "Network error while broadcasting, ignoring.");
			}
		}
	}

	// BUG: If except = 0, could use Multicast.
}

// ----------------------------------------------------------------------------
//! Broadcast 'msg' to some Federates except the specified one
void
Federation::broadcastSomeMessage(NetworkMessage *msg,
		FederateHandle except_federate,
		const std::vector <FederateHandle> &fede_array,
		uint32_t nbfed)
{
	uint32_t ifed ;
	Socket *socket = NULL ;

	if ( fede_array.size() != 0 || nbfed == 0)
	{
		// Broadcast the message 'msg' to some Federates (done in fede_array)
		// in the Federation
		// except to Federate whose Handle is 'Except_Federate'.
		for (HandleFederateMap::iterator i = _handleFederateMap.begin(); i != _handleFederateMap.end(); ++i)
		{
			if (i->second.getHandle() != except_federate)
			{
				ifed = 0 ;
				while ( ifed < nbfed )
				{
					if ( i->second.getHandle() == fede_array[ifed] )
						// Federate i has to be informed because into fede_array
						{
						try
						{
#ifdef HLA_USES_UDP
							socket = server->getSocketLink(i->second.getHandle(), BEST_EFFORT);
#else
							socket = server->getSocketLink(i->second.getHandle());
#endif
							msg->send(socket,NM_msgBufSend);
						}
						catch (RTIinternalError &e)
						{
							Debug(D, pdExcept) << "Reference to a killed Federate while "
									<< "broadcasting." << endl ;
						}
						catch (NetworkError &e)
						{
							D.Out(pdExcept, "Network error while broadcasting, ignoring.");
						}
						}
					ifed++;
				}
			}
		}
	}

	// BUG: If except = 0, could use Multicast.
}

// ----------------------------------------------------------------------------
//! broadcastInteraction with time
void
Federation::broadcastInteraction(FederateHandle federate_handle,
		InteractionClassHandle interaction,
		const std::vector <ParameterHandle> &parameter_handles,
		const std::vector <ParameterValue_t> &parameter_values,
		uint16_t list_size,
		FederationTime time,
		RegionHandle region_handle,
		const std::string& tag)
throw (FederateNotExecutionMember,
		FederateNotPublishing,
		InteractionClassNotDefined,
		InteractionParameterNotDefined,
		SaveInProgress,
		RestoreInProgress,
		RTIinternalError)
		{

	G.Out(pdGendoc,"enter Federation::broadcastInteraction with time");

	// It may throw FederateNotExecutionMember.
	this->check(federate_handle);

	const RTIRegion *region = 0 ;
	if (region_handle != 0)
		region = root->getRegion(region_handle);

	root->Interactions->broadcastInteraction(federate_handle,
			interaction,
			parameter_handles,
			parameter_values,
			list_size,
			time,
			region,
			tag);
	D.Out(pdRequest, "Federation %d: Broadcasted Interaction %d from Federate "
			"%d nb params %d.", handle, interaction, federate_handle, list_size);
	for (int i=0 ; i < list_size ; i++)
		D.Out(pdRequest,
				" Param %d Value %s",
				parameter_handles[i],
				parameter_values[i].c_str());

	G.Out(pdGendoc,"exit Federation::broadcastInteraction with time");

		}

// ----------------------------------------------------------------------------
//! broadcastInteraction without time
void
Federation::broadcastInteraction(FederateHandle federate_handle,
		InteractionClassHandle interaction,
		const std::vector <ParameterHandle> &parameter_handles,
		const std::vector <ParameterValue_t> &parameter_values,
		uint16_t list_size,
		RegionHandle region_handle,
		const std::string& tag)
throw (FederateNotExecutionMember,
		FederateNotPublishing,
		InteractionClassNotDefined,
		InteractionParameterNotDefined,
		SaveInProgress,
		RestoreInProgress,
		RTIinternalError)
		{

	G.Out(pdGendoc,"enter Federation::broadcastInteraction without time");

	// It may throw FederateNotExecutionMember.
	this->check(federate_handle);

	const RTIRegion *region = 0 ;
	if (region_handle != 0)
		region = root->getRegion(region_handle);

	root->Interactions->broadcastInteraction(federate_handle,
			interaction,
			parameter_handles,
			parameter_values,
			list_size,
			region,
			tag);
	D.Out(pdRequest, "Federation %d: Broadcasted Interaction %d from Federate "
			"%d nb params %d.", handle, interaction, federate_handle, list_size);
	for (int i=0 ; i < list_size ; i++)
		D.Out(pdRequest,
				" Param %d Value %s",
				parameter_handles[i],
				parameter_values[i].c_str());

	G.Out(pdGendoc,"exit Federation::broadcastInteraction without time");

		}

// ----------------------------------------------------------------------------
/** Removes an object instance from federation.
    @param federate Federate requesting removal
    @param id Object handle
    @param theTime Federation Time
    @param tag Label for this operation
 */
void
Federation::deleteObject(FederateHandle federate,
		ObjectHandle id,
		FederationTime theTime,
		const std::string& tag)
throw (FederateNotExecutionMember,
		DeletePrivilegeNotHeld,
		ObjectNotKnown,
		SaveInProgress,
		RestoreInProgress,
		InvalidFederationTime,
		RTIinternalError)
		{
	// It may throw FederateNotExecutionMember.
	this->check(federate);

	D.Out(pdRegister, "Federation %d: Federate %d destroys object %d.",
			this->handle, federate, id);

	root->deleteObjectInstance(federate, id, theTime, tag);
	objectHandles.free(id);
		}
// ----------------------------------------------------------------------------
/** Removes an object instance from federation.
    @param federate Federate requesting removal
    @param id Object handle
    @param tag Label for this operation
 */
void
Federation::deleteObject(FederateHandle federate,
		ObjectHandle id,
		const std::string& tag)
throw (FederateNotExecutionMember,
		DeletePrivilegeNotHeld,
		ObjectNotKnown,
		SaveInProgress,
		RestoreInProgress,
		RTIinternalError)
		{
	// It may throw FederateNotExecutionMember.
	this->check(federate);

	D.Out(pdRegister, "Federation %d: Federate %d destroys object %d.",
			this->handle, federate, id);

	root->deleteObjectInstance(federate, id, tag);
	objectHandles.free(id);
		}

// ----------------------------------------------------------------------------
//! Add a new synchronization point to federation.
void
Federation::registerSynchronization(FederateHandle federate,
		const std::string& label,
		const std::string& tag)
throw (FederateNotExecutionMember,
		FederationAlreadyPaused,
		SaveInProgress,
		RestoreInProgress,
		RTIinternalError)
		{

	G.Out(pdGendoc,"enter Federation::registerSynchronization for all federates");

	this->check(federate); // It may throw FederateNotExecutionMember.

	if (label.empty())
		throw RTIinternalError("Bad pause label(null).");

	// Verify label does not already exists
	std::map<std::string, std::string>::const_iterator i = synchronizationLabels.find(label);
	if (i != synchronizationLabels.end()) {
		throw FederationAlreadyPaused("Label already pending"); // Label already pending.
	}

	// If not already in pending labels, insert to list.
	synchronizationLabels.insert(pair<const std::string, std::string>(label, tag));

	// Add label to each federate (may throw RTIinternalError).
	for (HandleFederateMap::iterator i = _handleFederateMap.begin(); i != _handleFederateMap.end(); ++i) {
		i->second.addSynchronizationLabel(label);
	}

	Debug(D, pdTerm) << "Federation " << handle << " is now synchronizing for label "
			<< label << endl ;

	G.Out(pdGendoc,"exit  Federation::registerSynchronization for all federates");
		} /* end of Federation::registerSynchronization */

// ----------------------------------------------------------------------------
//! Add a new synchronization point (with federates set) to federation.
void
Federation::registerSynchronization(FederateHandle federate,
		const std::string& label,
		const std::string& tag,
		unsigned short federate_setSize,
		const std::vector <FederateHandle> &federate_set)
throw (FederateNotExecutionMember,
		FederationAlreadyPaused,
		SaveInProgress,
		RestoreInProgress,
		RTIinternalError)
		{

	G.Out(pdGendoc,"enter Federation::registerSynchronization for federate set");

	this->check(federate); // It may throw FederateNotExecutionMember.

	if (label.empty())
		throw RTIinternalError("Bad pause label(null).");

	// Verify label does not already exists
	std::map<std::string, std::string>::const_iterator i = synchronizationLabels.find(label);
	if (i != synchronizationLabels.end()) {
		throw FederationAlreadyPaused(""); // Label already pending.
	}

	// If not already in pending labels, insert to list.
	synchronizationLabels.insert(pair<const std::string, std::string>(label, tag));

	// Add label to each federate into the set only (may throw RTIinternalError).
	for (int i=0 ; i < federate_setSize  ;i++ )
	{
		for (HandleFederateMap::iterator j = _handleFederateMap.begin(); j != _handleFederateMap.end(); ++j)
		{
			if ( (federate_set[i] == j->second.getHandle()) || (federate == j->second.getHandle()) )
				j->second.addSynchronizationLabel(label);
		}
	}

	Debug(D, pdTerm) << "Federation " << handle << " is now synchronizing for label "
			<< label << endl ;

	G.Out(pdGendoc,"exit  Federation::registerSynchronization for federate set");

		}

// ----------------------------------------------------------------------------
/*! Broadcast an 'Announce Synchronization Point' when registering a new
  synchronization point.
 */
void
Federation::broadcastSynchronization(FederateHandle federate,
		const std::string& label,
		const std::string& tag)
throw (RTIinternalError)
{

	G.Out(pdGendoc,"enter Federation::broadcastSynchronization");

	this->check(federate); // It may throw FederateNotExecutionMember.

	if (label.empty())
		throw RTIinternalError("Bad pause label(null).");

	// broadcast announceSynchronizationPoint() to all federates in federation.
	NM_Announce_Synchronization_Point msg ;
	msg.setFederate(federate);
	msg.setFederation(handle);
	msg.setLabel(label);
	msg.setTag(tag);

	G.Out(pdGendoc,"      broadcastSynchronization is calling broadcastAnyMessage for all federates");

	broadcastAnyMessage(&msg, 0,false);

	G.Out(pdGendoc,"exit  Federation::broadcastSynchronization");

}

// ----------------------------------------------------------------------------
/*! Broadcast an 'Announce Synchronization Point' when registering a new
  synchronization point onto a set of federates
 */
void
Federation::broadcastSynchronization(FederateHandle federate,
		const std::string& label,
		const std::string& tag,
		unsigned short federate_setSize,
		const std::vector <FederateHandle> &federate_set)
throw (RTIinternalError)
{

	G.Out(pdGendoc,"enter Federation::broadcastSynchronization to some federates");

	this->check(federate); // It may throw FederateNotExecutionMember.

	if (label.empty())
		throw RTIinternalError("Bad pause label(null or too long).");

	// broadcast announceSynchronizationPoint() to all federates in federation.
	NM_Announce_Synchronization_Point msg ;
	msg.setFederate(federate) ;
	msg.setFederation(handle);
	msg.setLabel(label);
	msg.setTag(tag);

	G.Out(pdGendoc,"      broadcastSynchronization is calling broadcastSomeMessage");

	broadcastSomeMessage(&msg, 0, federate_set, federate_setSize);

	G.Out(pdGendoc,"exit  Federation::broadcastSynchronization to some federates");

}


// ----------------------------------------------------------------------------
//! Request a federation save with time.
/*! This service puts each federate from federation in saving state.
  !! the_time is not managed yet.
 */
void
Federation::requestFederationSave(FederateHandle the_federate,
		const std::string& the_label,
		FederationTime time )
throw (FederateNotExecutionMember, SaveInProgress)
{
	G.Out(pdGendoc,"enter Federation::requestFederationSave with time");

	check(the_federate);

	if (saveInProgress)
		throw SaveInProgress("Already in saving state.");

	for (HandleFederateMap::iterator j = _handleFederateMap.begin(); j != _handleFederateMap.end(); ++j) {
		j->second.setSaving(true);
	}

	saveStatus = true ;
	saveInProgress = true ;
	saveLabel = the_label ;

	NM_Initiate_Federate_Save msg ;
	msg.setFederate(the_federate);
	msg.setFederation(handle);
	msg.setLabel(the_label);
	// timed message
	msg.setDate(time);

	G.Out(pdGendoc,"      requestFederationSave====>broadcast I_F_S to all");

	broadcastAnyMessage(&msg, 0, false);

	G.Out(pdGendoc,"exit  Federation::requestFederationSave with time");
}

// ----------------------------------------------------------------------------
//! Request a federation save without time.
/*! This service puts each federate from federation in saving state.
  !! the_time is not managed yet.
 */
void
Federation::requestFederationSave(FederateHandle the_federate,
		const std::string& the_label)
throw (FederateNotExecutionMember, SaveInProgress)
{
	G.Out(pdGendoc,"enter Federation::requestFederationSave without time");

	check(the_federate);

	if (saveInProgress)
		throw SaveInProgress("Already in saving state.");

	for (HandleFederateMap::iterator j = _handleFederateMap.begin(); j != _handleFederateMap.end(); ++j) {
		j->second.setSaving(true);
	}

	saveStatus = true ;
	saveInProgress = true ;
	saveLabel = the_label ;

	NM_Initiate_Federate_Save msg ;
	msg.setFederate(the_federate);
	msg.setFederation(handle);
	msg.setLabel(the_label);

	G.Out(pdGendoc,"                  requestFederationSave====>broadcast I_F_S"
			" to all");

	broadcastAnyMessage(&msg, 0, false);

	G.Out(pdGendoc,"exit  Federation::requestFederationSave without time");
}
// ----------------------------------------------------------------------------
/*! Received from a federate to inform a save has been received and is being
  processed.
  Maybe, a timeout should be set to determine if federate still alive.
 */
void
Federation::federateSaveBegun(FederateHandle the_federate)
throw (FederateNotExecutionMember)
{
	G.Out(pdGendoc,"enter Federation::federateSaveBegun");
	check(the_federate);
	G.Out(pdGendoc,"exit  Federation::federateSaveBegun");
}

// ----------------------------------------------------------------------------
//! Informs that a federate returns a save end message (with success or not!).
void
Federation::federateSaveStatus(FederateHandle the_federate, bool the_status)
throw (FederateNotExecutionMember)
{
	G.Out(pdGendoc,"enter Federation::federateSaveStatus");

	Federate &federate = getFederate(the_federate);
	federate.setSaving(false);

	if (!the_status)
		saveStatus = false ;

	// Verify that all federates save ended (complete or not).
	for (HandleFederateMap::iterator j = _handleFederateMap.begin(); j != _handleFederateMap.end(); ++j) {
		if (j->second.isSaving())
		{
			G.Out(pdGendoc,"exit  Federation::federateSaveStatus one federate has not save ended");
			return ;
		}
	}

	// Save RTIG Data for future restoration.
	if (saveStatus) {
		saveStatus = saveXmlData();
	}

	// Send end save message.
	std::auto_ptr<NetworkMessage> msg(NM_Factory::create(saveStatus ? NetworkMessage::FEDERATION_SAVED : NetworkMessage::FEDERATION_NOT_SAVED )) ;

	msg->setFederate(the_federate);
	msg->setFederation(handle);

	broadcastAnyMessage(msg.get(), 0,false);

	G.Out(pdGendoc,"            =======> broadcast F_S or F_N_S");

	// Reinitialize state.
	saveStatus = true ;
	saveInProgress = false ;

	G.Out(pdGendoc,"exit  Federation::federateSaveStatus");
}

// ----------------------------------------------------------------------------
//! Informs that a federate is requesting a save.
void
Federation::requestFederationRestore(FederateHandle the_federate,
		const std::string& the_label)
throw (FederateNotExecutionMember)
{
	G.Out(pdGendoc,"enter Federation::requestFederationRestore");

	check(the_federate);

	if (restoreInProgress)
		throw RestoreInProgress("Already in restoring state.");

	Socket * socket ;
	NetworkMessage *msg;


	// Informs sending federate of success/failure in restoring.
	// At this point, only verify that file is present.
	bool success = true ;
#ifdef HAVE_XML
	string filename = name + "_" + the_label + ".xcs" ;
	doc = xmlParseFile(filename.c_str());

	// Did libXML manage to parse the file ?
	if (doc == 0) {
		cerr << "XML restore file not parsed successfully" << endl ;
		xmlFreeDoc(doc);
		success = false ;
	}
	if (success) {
		success = restoreXmlData();
	}
#else
	success = false ;
#endif // HAVE_XML

	// JYR Note : forcing success to true to skip xmlParseFile (not compliant ?)
	success = true ;

	if (success) {
		msg = NM_Factory::create(NetworkMessage::REQUEST_FEDERATION_RESTORE_SUCCEEDED);
	} else {
		msg = NM_Factory::create(NetworkMessage::REQUEST_FEDERATION_RESTORE_FAILED);
	}

	msg->setFederate(the_federate);
	msg->setFederation(handle);
	msg->setLabel(the_label);

	socket = server->getSocketLink(msg->getFederate());

	if (success)
		G.Out(pdGendoc,"             =====> send message R_F_R_S to RTIA");
	else
		G.Out(pdGendoc,"             =====> send message R_F_R_F to RTIA");

	msg->send(socket,NM_msgBufSend);
	delete msg ;

	// Reading file failed: not restoring !
	if (!success)
	{
		G.Out(pdGendoc,"exit  Federation::requestFederationRestore on success false");
		return ;
	}

	// Otherwise...
	for (HandleFederateMap::iterator i = _handleFederateMap.begin(); i != _handleFederateMap.end(); ++i) {
		i->second.setRestoring(true);
	}
	restoreStatus = true ;
	restoreInProgress = true ;

	// Informs federates a new restore is being done.
	msg = NM_Factory::create(NetworkMessage::FEDERATION_RESTORE_BEGUN);
	msg->setFederate(the_federate);
	msg->setFederation(handle);

	G.Out(pdGendoc,"             =====> broadcast message F_R_B");

	broadcastAnyMessage(msg, 0, false);
	delete msg ;

	// For each federate, send an initiateFederateRestore with correct handle.
	msg = NM_Factory::create(NetworkMessage::INITIATE_FEDERATE_RESTORE);
	msg->setFederation(handle) ;
	msg->setLabel(the_label);

	for (HandleFederateMap::iterator i = _handleFederateMap.begin(); i != _handleFederateMap.end(); ++i) {
		msg->setFederate(i->second.getHandle());

		// send message.
		socket = server->getSocketLink(msg->getFederate());
		G.Out(pdGendoc,"             =====> send message I_F_R to federate %d",msg->getFederate());
		msg->send(socket,NM_msgBufSend);
	}
	delete msg;
	G.Out(pdGendoc,"exit  Federation::requestFederationRestore");
}

// ----------------------------------------------------------------------------
//! Informs that a federate has ended a restore.
/*! If each federate in federation has ended restoring, this service send a
  federation restore status.
 */
void
Federation::federateRestoreStatus(FederateHandle the_federate,
		bool the_status)
throw (FederateNotExecutionMember)
{
	G.Out(pdGendoc,"enter Federation::federateRestoreStatus");
	Federate &federate = getFederate(the_federate);
	federate.setRestoring(false);

	if (!the_status)
		restoreStatus = false ;

	// Verify that all federates save ended (complete or not).
	for (HandleFederateMap::iterator i = _handleFederateMap.begin(); i != _handleFederateMap.end(); ++i) {
		if (i->second.isRestoring())
			return ;
	}

	// Send end restore message.
	std::auto_ptr<NetworkMessage> msg(NM_Factory::create(restoreStatus ? NetworkMessage::FEDERATION_RESTORED : NetworkMessage::FEDERATION_NOT_RESTORED)) ;

	msg->setFederate(the_federate);
	msg->setFederation(handle);

	broadcastAnyMessage(msg.get(), 0, false);

	// Reinitialize state.
	restoreStatus = true ;
	restoreInProgress = false ;
	G.Out(pdGendoc,"exit  Federation::federateRestoreStatus");
}

// ----------------------------------------------------------------------------
//! Return the Federate whose Handle is theHandle, if found.
Federate &
Federation::getFederate(FederateHandle federate_handle)
throw (FederateNotExecutionMember)
{
	HandleFederateMap::iterator i = _handleFederateMap.find(federate_handle);
	if (i == _handleFederateMap.end())
		throw FederateNotExecutionMember("Federate Handle not found.");
	return i->second;
}

// ----------------------------------------------------------------------------
//! Return the Federate whose Name is theName, if found.
Federate &
Federation::getFederate(const std::string& federate_name)
throw (FederateNotExecutionMember)
{
	for (HandleFederateMap::iterator i = _handleFederateMap.begin(); i != _handleFederateMap.end(); ++i) {
		if (i->second.getName() == federate_name)
			return i->second;
	}

	throw FederateNotExecutionMember(stringize() <<
			"Federate <"<<federate_name<<"> not [yet] member of Federation <" << getName() <<">.");
}

// ----------------------------------------------------------------------------
//! Return true if no federates are in federation.
/*! Return true if there are no Federates left in the Federation, else throw
  FederatesCurrentlyJoined.
 */
bool
Federation::empty() const
throw (FederatesCurrentlyJoined)
{
	if (_handleFederateMap.empty())
		return true ;
	else
		throw FederatesCurrentlyJoined("");
}

// ----------------------------------------------------------------------------
// Return true if federate is in federation.

bool
Federation::check(FederateHandle federate_handle) const
throw (FederateNotExecutionMember)
{
	HandleFederateMap::const_iterator i = _handleFederateMap.find(federate_handle);
	if (i == _handleFederateMap.end())
		throw FederateNotExecutionMember("Federate Handle not found.");
	return true;
}

// ----------------------------------------------------------------------------
/** Make a federate resign the federation. This function tries to
    remove all references to this federate in the federation. To be used
    when a Federate is supposed to have crashed.
    @param federate Handle of the federate to kill
 */
void
Federation::kill(FederateHandle federate)
throw ()
{
	// NOTE: Connection to the federate is already closed.
	D.Out(pdInit, "Killing Federate %d.", federate);

	// is regulator ?
	try {
		removeRegulator(federate);
		D.Out(pdInit, "Regulator Federate %d removed...", federate);
	} catch (Exception &e) {}

	// is constrained ?
	try {
		removeConstrained(federate);
		D.Out(pdInit, "Constrained Federate %d removed...", federate);
	} catch (Exception &e) {}

	// Remove references to this federate in root object
	root->killFederate(federate);
	Debug(D, pdTrace) << "Federate " << federate << " removed from the Root Object "
			<< endl ;

	// delete from federations list
	try {
		remove(federate);
		D.Out(pdInit, "Federate %d removed...", federate);
	} catch (Exception &e) {}
}

// ----------------------------------------------------------------------------
// publishInteraction

void
Federation::publishInteraction(FederateHandle federate,
		InteractionClassHandle interaction,
		bool pub)
throw (InteractionClassNotDefined,
		FederateNotExecutionMember,
		SaveInProgress,
		SecurityError,
		RestoreInProgress,
		RTIinternalError)
		{
	// It may throw FederateNotExecutionMember.
	this->check(federate);

	// It may throw InteractionClassNotDefined
	root->Interactions->publish(federate, interaction, pub);
	D.Out(pdRequest,
			"Federation %d: Federate %d has(un)published Interaction %d.",
			handle, federate, interaction);
		}

// ----------------------------------------------------------------------------
// publishObject

void
Federation::publishObject(FederateHandle federate,
		ObjectClassHandle object,
		const std::vector <AttributeHandle> &attributes,
		uint16_t list_size,
		bool pub)
throw (ObjectClassNotDefined,
		AttributeNotDefined,
		FederateNotExecutionMember,
		SaveInProgress,
		SecurityError,
		RestoreInProgress,
		RTIinternalError)
		{
	G.Out(pdGendoc,"enter Federation::publishObject");
	// It may throw FederateNotExecutionMember.
	this->check(federate);

	// It may throw *NotDefined
	root->ObjectClasses->publish(federate, object, attributes, list_size, pub);

	D.Out(pdRegister,
			"Federation %d: Federate %d(un)publishes %d attrib. of ObjClass %d.",
			handle, federate, list_size, object);
	G.Out(pdGendoc,"exit  Federation::publishObject");
		}


void 
Federation::reserveObjectInstanceName(FederateHandle theFederateHandle,
	                           std::string newObjName)
	throw (IllegalName,
	       SaveInProgress,
	       RestoreInProgress,
	       RTIinternalError)
{
	Socket * socket ;
	NetworkMessage *msg;

	bool reservation_ok = false;

	reservation_ok = root->reserveObjectInstanceName(theFederateHandle, newObjName);

	if (reservation_ok)
	{
		msg = NM_Factory::create(NetworkMessage::RESERVE_OBJECT_INSTANCE_NAME_SUCCEEDED);
		NM_Reserve_Object_Instance_Name_Succeeded *okMsg = dynamic_cast<NM_Reserve_Object_Instance_Name_Succeeded *>(msg);

		okMsg->setObjectName(newObjName);
		G.Out(pdGendoc,"             =====> send message R_O_I_N_S to federate %d",msg->getFederate());
	} else {
		msg = NM_Factory::create(NetworkMessage::RESERVE_OBJECT_INSTANCE_NAME_FAILED);
		NM_Reserve_Object_Instance_Name_Failed *nokMsg = dynamic_cast<NM_Reserve_Object_Instance_Name_Failed *>(msg);

		nokMsg->setObjectName(newObjName);
		G.Out(pdGendoc,"             =====> send message R_O_I_N_F to federate %d",msg->getFederate());
	}

	msg->setFederation(handle);
	msg->setFederate(theFederateHandle);
	// send message.
	socket = server->getSocketLink(msg->getFederate());
	msg->send(socket,NM_msgBufSend);

	delete msg;
}


// ----------------------------------------------------------------------------
//! Adds a new object instance to federation.
ObjectHandle
Federation::registerObject(FederateHandle federate,
		ObjectClassHandle class_handle,
		const std::string& object_name)
throw (FederateNotExecutionMember,
		FederateNotPublishing,
		ObjectAlreadyRegistered,
		ObjectClassNotDefined,
		ObjectClassNotPublished,
		SaveInProgress,
		RestoreInProgress,
		RTIinternalError)
		{

	ObjectHandle new_id = objectHandles.provide();

	G.Out(pdGendoc,"enter Federation::registerObject");
	D.Out(pdRegister,
			"Federation %d: Federate %d registering Object %d of Class %d.",
			handle, federate, new_id, class_handle);

	string strname;
	if (!object_name.empty()) {
		strname = object_name;
	} else {
		// create a name if necessary
		strname = stringize() << "HLAObject_" << new_id;
	}

	// Register Object.
	try
	{
		root->registerObjectInstance(federate, class_handle, new_id, strname);
	}
	catch(...)
	{   //If an exception was thrown, the object instance was not added
		//and we can free the object handle id for future use and rethrow
		//the exception
		objectHandles.free(new_id);
		throw;
	}
	G.Out(pdGendoc,"exit Federation::registerObject");
	return new_id ;
		}

// ----------------------------------------------------------------------------
/** Remove a federate.
    @param federate_handle Handle of the federate to remove.
    @bug Currently does not check if Federate owns attributes. The
    Federate Object is deleted.
 */
void
Federation::remove(FederateHandle federate_handle)
throw (FederateOwnsAttributes, FederateNotExecutionMember)
{
	HandleFederateMap::iterator i = _handleFederateMap.find(federate_handle);
	if (i != _handleFederateMap.end()) {
		// BUG: RemoveFederate: Should see if Federate owns attributes
		federateHandles.free(federate_handle);
		_handleFederateMap.erase(i);

		D.Out(pdInit, "Federation %d: Removed Federate %d.", handle,
				federate_handle);
		return;
	}

	D.Out(pdExcept, "Federation %d could not remove unknown federate %d.",
			handle, federate_handle);
	throw FederateNotExecutionMember("");
}

// ----------------------------------------------------------------------------
//! Set Federate's IsConstrained to false.
void
Federation::removeConstrained(FederateHandle federate_handle)
throw (FederateNotExecutionMember,
		SaveInProgress,
		RestoreInProgress,
		RTIinternalError)
		{
	// It may throw FederateNotExecutionMember
	Federate &federate = getFederate(federate_handle);

	if (!federate.isConstrained()) {
		D.Out(pdExcept, "Federate %d was not constrained.", federate_handle);
		throw RTIinternalError("Time constrained not enabled.");
	}

	federate.setConstrained(false);
	D.Out(pdTerm, "Federation %d: Federate %d is not constrained anymore.",
			handle, federate_handle);
		}

// ----------------------------------------------------------------------------
//! Remove the Federate from the Regulators' list.
void
Federation::removeRegulator(FederateHandle federate_handle)
throw (FederateNotExecutionMember,
		SaveInProgress,
		RestoreInProgress,
		RTIinternalError)
		{
	// It may throw FederateNotExecutionMember
	Federate &federate = getFederate(federate_handle);

	// It may throw RTIinternalError if Federate was not regulators.
	regulators.remove(federate_handle);

	federate.setRegulator(false);

	D.Out(pdTerm, "Federation %d: Federate %d is not a regulator anymore.",
			handle, federate_handle);

	NM_Set_Time_Regulating msg ;
	msg.setFederation(handle);
	msg.setFederate(federate_handle);
	msg.regulatorOff();

	broadcastAnyMessage(&msg, 0, false);
		}

// ----------------------------------------------------------------------------
//! unregisterSynchronization.
void
Federation::unregisterSynchronization(FederateHandle federate_handle,
		const std::string& label)
throw (FederateNotExecutionMember,
		FederationNotPaused,
		SaveInProgress,
		RestoreInProgress,
		RTIinternalError)
		{

	G.Out(pdGendoc,"enter Federation::unregisterSynchronization");

	this->check(federate_handle); // It may throw FederateNotExecutionMember.

	if (label.empty())
		throw RTIinternalError("Bad pause label(null).");

	// Set federate synchronized on this label.
	Federate &federate = getFederate(federate_handle);
	federate.removeSynchronizationLabel(label);

	// Test in every federate is synchronized. Otherwise, quit method.
	for (HandleFederateMap::iterator i = _handleFederateMap.begin(); i != _handleFederateMap.end(); ++i) {
		if (i->second.isSynchronizationLabel(label))
			return;
	}

	// All federates from federation has called synchronizationPointAchieved.

	D.Out(pdTerm, "Federation %d is not Paused anymore.", handle);
	// Remove label from federation list.
	std::map<std::string, std::string>::iterator i = synchronizationLabels.find(label);
	if (i != synchronizationLabels.end()) {
		synchronizationLabels.erase(i);
	}

	// send a federationSynchronized().
	NM_Federation_Synchronized msg ;
	msg.setFederation(handle);
	msg.setFederate(federate_handle);
	msg.setLabel(label);

	broadcastAnyMessage(&msg, 0, false);

	D.Out(pdTerm, "Federation %d is synchronized on %s.", handle, label.c_str());

	G.Out(pdGendoc,"exit  Federation::unregisterSynchronization");

		}

// ----------------------------------------------------------------------------
// subscribeInteraction

void
Federation::subscribeInteraction(FederateHandle federate,
		InteractionClassHandle interaction,
		bool sub)
throw (InteractionClassNotDefined,
		FederateNotExecutionMember,
		SaveInProgress,
		SecurityError,
		RestoreInProgress,
		RTIinternalError)
		{
	// It may throw FederateNotExecutionMember.
	this->check(federate);

	// It may throw *NotDefined
	root->Interactions->subscribe(federate, interaction, 0, sub);
	D.Out(pdRegister,
			"Federation %d: Federate %d(un)subscribes to Interaction %d.",
			handle, federate, interaction);
		}

// ----------------------------------------------------------------------------
// subscribeObject

void
Federation::subscribeObject(FederateHandle federate,
		ObjectClassHandle object,
		const std::vector <AttributeHandle> &attributes,
		uint16_t list_size)
throw (ObjectClassNotDefined,
		AttributeNotDefined,
		FederateNotExecutionMember,
		SaveInProgress,
		SecurityError,
		RestoreInProgress,
		RTIinternalError)
		{
	G.Out(pdGendoc,"enter Federation::subscribeObject");
	// It may throw FederateNotExecutionMember.
	this->check(federate);

	// It may throw *NotDefined
	root->ObjectClasses->subscribe(federate, object, attributes, list_size);

	/*
	 * The subscription process in CERTI:
	 * In RTIG.cc the network messages SUBSCRIBE_OBJECT_CLASS and UNSUBSCRIBE_
	 * OBJECT_CLASS are both mapped to the method processSubscribeObject within
	 * RTIG_processing.cc. RTIG_proccessing invokes this method
	 * (subscribeObject).
	 * The above code line (root->ObjectClasses->subscribe(...) calls the
	 * subscription within the CERTI library in ObjectClassSet.cc. Further on,
	 * ObjectClassSet::subscribe invokes ObjectClass::subscribe. That method
	 * first unsubscribes all attributes, afterwards the subscription is
	 * done in a for loop til list_size.
	 * This means: Unsubscription and subscription are realized by the same
	 * method. Only the list_size parameter controls the
	 * unsubscription/subscription process.
	 *
	 * Do we need a cleaner solution, e.g. separate methods for subscription/
	 * unsubscription?
	 */

	if (list_size!=0) {  // do only for subscription
		// get object class from object class handle
		ObjectClass *objectClass = root->ObjectClasses->getObjectFromHandle(object);

		// get attributes of object class
		ObjectClassAttribute::PublishersList_t publishers;

		// get publishers of attributes
		// first for: iterate through the attribute list and get publishers of
		//            each attribtue
		// second for: iterate through the temporal publishers list and store
		//             non-duplicate entries in publishers
		ObjectClassAttribute::PublishersList_t tmp_publishers;

		const ObjectClass::HandleClassAttributeMap& attributeMap = objectClass->getHandleClassAttributeMap();
		for (ObjectClass::HandleClassAttributeMap::const_iterator i = attributeMap.begin();
				i != attributeMap.end(); ++i) {
			tmp_publishers = i->second->getPublishers();
			for (ObjectClassAttribute::PublishersList_t::const_iterator
					j=tmp_publishers.begin();
					j!=tmp_publishers.end();
					j++) {
				// insert only non-duplicate entries ->
				// pair<iterator, bool> set::insert(const TYPE& val);
				publishers.insert(*j);
			}
			tmp_publishers.clear();
		}

		// notify all publishers
		std::set<FederateHandle> federate_set;

		for (ObjectClassAttribute::PublishersList_t::const_iterator
				k=publishers.begin();
				k!=publishers.end();
				k++) {

			if (getFederate(*k).isClassRelevanceAdvisorySwitch()) {
				federate_set.insert(*k);
			}
		}

		// broadcastSomeMessage needs a vector, no set -> conversion
		vector<FederateHandle> federate_vector(federate_set.size());
		std::copy(federate_set.begin(), federate_set.end(), federate_vector.begin());

		NM_Start_Registration_For_Object_Class msg ;
		msg.setFederate(federate);
		msg.setFederation(handle);
		msg.setObjectClass(object);

		this->broadcastSomeMessage(&msg, 0, federate_vector, (unsigned short)federate_vector.size());

		publishers.clear();
		federate_set.clear();
		federate_vector.clear();
	}
	else {	// unsubscribe branch
		/* test if objectclass is subscribed by anyone else
		 * -> yes : do nothing
		 * -> no : test if publisher sets its CRA switch
		 *  	-> no : do nothing
		 *  	-> yes : inform publisher with federate service stopRegistrationForObjectClass
		 */

	}

	D.Out(pdRegister,
			"Federation %d: Federate %d(un)sub. to %d attrib. of ObjClass %d.",
			handle, federate, list_size, object);
	G.Out(pdGendoc,"exit  Federation::subscribeObject");
		}

// ----------------------------------------------------------------------------
// updateAttributeValues with time

void
Federation::updateAttributeValues(FederateHandle federate,
		ObjectHandle objectHandle,
		const std::vector <AttributeHandle>  &attributes,
		const std::vector <AttributeValue_t> &values,
		uint16_t list_size,
		FederationTime time,
		const std::string& tag)
throw (FederateNotExecutionMember,
		ObjectNotKnown,
		AttributeNotDefined,
		AttributeNotOwned,
		SaveInProgress,
		RestoreInProgress,
		RTIinternalError)
		{
	G.Out(pdGendoc,"enter Federation::updateAttributeValues with time");
	// It may throw FederateNotExecutionMember.
	this->check(federate);

	// Get the object pointer by id from the root object
	Object *object = root->objects->getObject(objectHandle);

	// It may throw *NotDefined
	root->ObjectClasses->updateAttributeValues(federate, object, attributes, values, time, tag);

	D.Out(pdRegister,
			"Federation %d: Federate %d updated attributes of Object %d.",
			handle, federate, objectHandle);
	G.Out(pdGendoc,"exit  Federation::updateAttributeValues with time");
		}

// ----------------------------------------------------------------------------
// updateAttributeValues without time

void
Federation::updateAttributeValues(FederateHandle federate,
		ObjectHandle objectHandle,
		const std::vector <AttributeHandle> &attributes,
		const std::vector <AttributeValue_t> &values,
		uint16_t list_size,
		const std::string& tag)
throw (FederateNotExecutionMember,
		ObjectNotKnown,
		AttributeNotDefined,
		AttributeNotOwned,
		SaveInProgress,
		RestoreInProgress,
		RTIinternalError)
		{
	G.Out(pdGendoc,"enter Federation::updateAttributeValues without time");
	// It may throw FederateNotExecutionMember.
	this->check(federate);

	// Get the object pointer by id from the root object
	Object *object = root->objects->getObject(objectHandle);

	// It may throw *NotDefined
	root->ObjectClasses->updateAttributeValues(federate, object, attributes, values, tag);

	D.Out(pdRegister,
			"Federation %d: Federate %d updated attributes of Object %d.",
			handle, federate, objectHandle);
	G.Out(pdGendoc,"exit  Federation::updateAttributeValues without time");
		}
// ----------------------------------------------------------------------------
//! Update the current time of a regulator federate.
void
Federation::updateRegulator(FederateHandle federate_handle,
		FederationTime time, bool anonymous)
throw (FederateNotExecutionMember,
		RTIinternalError)
		{

	/* if it is an anonymous update (from NULL PRIME message)
	 * no need to check federate.
	 */
	if (!anonymous) {
		// It may throw FederateNotExecutionMember
		Federate &federate = getFederate(federate_handle);

		if (!federate.isRegulator()) {
			D.Out(pdExcept, "Federate %d is not a regulator.", federate_handle);
			throw RTIinternalError("Time regulation not enabled.");
		}

		D.Out(pdDebug, "Federation %d: Federate %d's new time is %f.",
				handle, federate_handle, time.getTime());
		regulators.update(federate_handle, time);
	}

	NM_Message_Null msg ;
	msg.setFederation(handle);
	if (anonymous) {
		msg.setFederate(0);
	} else {
		msg.setFederate(federate_handle);
	}
	msg.setDate(time);
	broadcastAnyMessage(&msg, federate_handle, anonymous);
}

// ----------------------------------------------------------------------------
// isOwner (isAttributeOwnedByFederate)
bool
Federation::isOwner(FederateHandle federate,
		ObjectHandle id,
		AttributeHandle attribute)
throw (FederateNotExecutionMember,
		ObjectNotKnown,
		AttributeNotDefined,
		SaveInProgress,
		RestoreInProgress,
		RTIinternalError)
		{
	// It may throw FederateNotExecutionMember.
	this->check(federate);

	D.Out(pdDebug, "Owner of Object %u Atrribute %u", id, attribute);

	// It may throw *NotDefined
	return root->objects->isAttributeOwnedByFederate(id, attribute, federate);
		}

// ----------------------------------------------------------------------------
// queryAttributeOwnership

void
Federation::queryAttributeOwnership(FederateHandle federate,
		ObjectHandle id,
		AttributeHandle attribute)
throw (FederateNotExecutionMember,
		ObjectNotKnown,
		AttributeNotDefined,
		SaveInProgress,
		RestoreInProgress,
		RTIinternalError)
		{
	// It may throw FederateNotExecutionMember.
	this->check(federate);

	D.Out(pdDebug, "Owner of Object %u Atrribute %u", id, attribute);

	// It may throw *NotDefined
	root->objects->queryAttributeOwnership(id, attribute, federate);
		}

// ----------------------------------------------------------------------------
// negotiateDivestiture (negotiatedAttributeOwnershipDivestiture)

void
Federation::negotiateDivestiture(FederateHandle federate,
		ObjectHandle objectHandle,
		const std::vector <AttributeHandle> &attribs,
		uint16_t list_size,
		const std::string& tag)
throw (FederateNotExecutionMember,
		ObjectNotKnown,
		AttributeNotDefined,
		AttributeNotOwned,
		AttributeAlreadyBeingDivested,
		SaveInProgress,
		RestoreInProgress,
		RTIinternalError)
		{
	// It may throw FederateNotExecutionMember.
	this->check(federate);

	// Get the object pointer by id from the root object
	Object *object = root->objects->getObject(objectHandle);

	// It may throw *NotDefined
	root->ObjectClasses->negotiatedAttributeOwnershipDivestiture(federate, object, attribs, tag);
		}

// ----------------------------------------------------------------------------
// acquireIfAvailable (attributeOwnershipAcquisitionIfAvailable)

void
Federation::acquireIfAvailable(FederateHandle federate,
		ObjectHandle objectHandle,
		const std::vector <AttributeHandle> &attribs,
		uint16_t list_size)
throw (ObjectNotKnown,
		ObjectClassNotPublished,
		AttributeNotDefined,
		AttributeNotPublished,
		FederateOwnsAttributes,
		AttributeAlreadyBeingAcquired,
		FederateNotExecutionMember,
		SaveInProgress,
		RestoreInProgress,
		RTIinternalError)
		{
	// It may throw FederateNotExecutionMember.
	this->check(federate);

	// Get the object pointer by id from the root object
	Object *object = root->objects->getObject(objectHandle);

	// It may throw *NotDefined
	root->ObjectClasses->attributeOwnershipAcquisitionIfAvailable(federate, object, attribs);
		}

// ----------------------------------------------------------------------------
// divest (unconditionalAttributeOwnershipDivestiture)

void
Federation::divest(FederateHandle federate,
		ObjectHandle objectHandle,
		const std::vector <AttributeHandle> &attrs,
		uint16_t list_size)
throw (ObjectNotKnown,
		AttributeNotDefined,
		AttributeNotOwned,
		FederateNotExecutionMember,
		SaveInProgress,
		RestoreInProgress,
		RTIinternalError)
		{
	// It may throw FederateNotExecutionMember.
	this->check(federate);

	// Get the object pointer by id from the root object
	Object *object = root->objects->getObject(objectHandle);

	// It may throw *NotDefined
	root->ObjectClasses->unconditionalAttributeOwnershipDivestiture(federate, object, attrs);
		}

// ----------------------------------------------------------------------------
// attributeOwnershipAcquisition

void
Federation::acquire(FederateHandle federate,
		ObjectHandle objectHandle,
		const std::vector <AttributeHandle> &attributes,
		uint16_t list_size,
		const std::string& tag)
throw (ObjectNotKnown,
		ObjectClassNotPublished,
		AttributeNotDefined,
		AttributeNotPublished,
		FederateOwnsAttributes,
		FederateNotExecutionMember,
		SaveInProgress,
		RestoreInProgress,
		RTIinternalError)
		{
	// It may throw FederateNotExecutionMember.
	this->check(federate);

	// Get the object pointer by id from the root object
	Object *object = root->objects->getObject(objectHandle);

	// It may throw *NotDefined
	root->ObjectClasses->attributeOwnershipAcquisition(federate, object, attributes, tag);

	D.Out(pdDebug, "Acquisition on Object %u ", objectHandle);
		}

// ----------------------------------------------------------------------------
// cancelDivestiture (cancelNegotiatedAttributeOwnershipDivestiture)

void
Federation::cancelDivestiture(FederateHandle federate,
		ObjectHandle id,
		const std::vector <AttributeHandle> &attributes,
		uint16_t list_size)
throw (ObjectNotKnown,
		AttributeNotDefined,
		AttributeNotOwned,
		AttributeDivestitureWasNotRequested,
		FederateNotExecutionMember,
		SaveInProgress,
		RestoreInProgress,
		RTIinternalError)
		{
	// It may throw FederateNotExecutionMember.
	this->check(federate);

	// It may throw *NotDefined
	root->objects->cancelNegotiatedAttributeOwnershipDivestiture(federate,
			id,
			attributes,
			list_size);

	D.Out(pdDebug, "CancelDivestiture sur Objet %u ", id);
		}

// ----------------------------------------------------------------------------
// respondRelease (attributeOwnershipRealeaseResponse)

AttributeHandleSet*
Federation::respondRelease(FederateHandle federate,
		ObjectHandle objectHandle,
		const std::vector <AttributeHandle> &attributes,
		uint16_t list_size)
throw (ObjectNotKnown,
		AttributeNotDefined,
		AttributeNotOwned,
		FederateWasNotAskedToReleaseAttribute,
		FederateNotExecutionMember,
		SaveInProgress,
		RestoreInProgress,
		RTIinternalError)
		{
	// It may throw FederateNotExecutionMember.
	this->check(federate);

	D.Out(pdDebug, "RespondRelease on Object %u.", objectHandle);

	// Get the object pointer by id from the root object
	Object *object = root->objects->getObject(objectHandle);

	// It may throw *NotDefined
	return root->ObjectClasses->attributeOwnershipReleaseResponse(federate, object, attributes);
		}

// ----------------------------------------------------------------------------
// cancelAttributeOwnershipAcquisition

void
Federation::cancelAcquisition(FederateHandle federate,
		ObjectHandle objectHandle,
		const std::vector <AttributeHandle> &attributes,
		uint16_t list_size)
throw (ObjectNotKnown,
		AttributeNotDefined,
		AttributeAlreadyOwned,
		AttributeAcquisitionWasNotRequested,
		FederateNotExecutionMember,
		SaveInProgress,
		RestoreInProgress,
		RTIinternalError)
		{
	// It may throw FederateNotExecutionMember.
	this->check(federate);

	D.Out(pdDebug, "CancelAcquisition sur Objet %u ", objectHandle);

	// Get the object pointer by id from the root object
	Object *object = root->objects->getObject(objectHandle);

	// It may throw *NotDefined
	root->ObjectClasses->cancelAttributeOwnershipAcquisition(federate, object, attributes);
		}

// ----------------------------------------------------------------------------
long
Federation::createRegion(FederateHandle federate,
		SpaceHandle space,
		long nb_extents)
throw (SpaceNotDefined, InvalidExtents, SaveInProgress, RestoreInProgress,
		RTIinternalError)
		{
	this->check(federate);

	return root->createRegion(space, nb_extents);
		}

// ----------------------------------------------------------------------------
// modifyRegion
void
Federation::modifyRegion(FederateHandle federate, RegionHandle region,
		const std::vector<Extent> &extents)
throw (RegionNotKnown, InvalidExtents, SaveInProgress, RestoreInProgress,
		RTIinternalError)
		{
	check(federate);
	root->modifyRegion(region, extents);
		}

// ----------------------------------------------------------------------------
//! deleteRegion
void
Federation::deleteRegion(FederateHandle federate,
		long region)
throw (RegionNotKnown, RegionInUse, SaveInProgress, RestoreInProgress,
		RTIinternalError)
		{
	this->check(federate);

	if (saveInProgress) {
		throw SaveInProgress("");
	}
	if (restoreInProgress) {
		throw RestoreInProgress("");
	}

	// TODO: check RegionInUse
	root->deleteRegion(region);
		}

// ----------------------------------------------------------------------------
//! associateRegion
void
Federation::associateRegion(FederateHandle federate,
		ObjectHandle object,
		RegionHandle the_handle,
		unsigned short nb,
		const std::vector <AttributeHandle> &attributes)
throw (RegionNotKnown, SaveInProgress, RestoreInProgress, RTIinternalError)
{
	check(federate);

	RTIRegion *region = root->getRegion(the_handle);

	root->getObject(object)->unassociate(region);

	for (int i = 0 ; i < nb ; ++i) {
		root->getObjectAttribute(object, attributes[i])->associate(region);
	}
}

// ----------------------------------------------------------------------------
//! unassociateRegion
void
Federation::unassociateRegion(FederateHandle federate, ObjectHandle object,
		RegionHandle the_handle)
throw (RegionNotKnown, SaveInProgress, RestoreInProgress,
		RTIinternalError)
		{
	check(federate);

	RTIRegion *region = root->getRegion(the_handle);
	root->getObject(object)->unassociate(region);
		}

// ----------------------------------------------------------------------------
//! subscribeAttributesWR
void
Federation::subscribeAttributesWR(FederateHandle federate,
		ObjectClassHandle c,
		RegionHandle region_handle,
		unsigned short nb,
		const std::vector <AttributeHandle> &attributes)
throw (RegionNotKnown,
		SaveInProgress,
		RestoreInProgress,
		RTIinternalError)
		{
	check(federate);
	root->ObjectClasses->subscribe(federate, c, attributes, nb,
			root->getRegion(region_handle));
		}

// ----------------------------------------------------------------------------
//! unsubscribeAttributesWR
void
Federation::unsubscribeAttributesWR(FederateHandle federate,
		ObjectClassHandle object_class,
		RegionHandle region_handle)
throw (RegionNotKnown,
		SaveInProgress,
		RestoreInProgress,
		RTIinternalError)
		{
	check(federate);

	RTIRegion *region = root->getRegion(region_handle);

	root->getObjectClass(object_class)->unsubscribe(federate, region);
		}

// ----------------------------------------------------------------------------
void
Federation::subscribeInteractionWR(FederateHandle federate,
		InteractionClassHandle interaction,
		RegionHandle region_handle)
throw (RegionNotKnown,
		SaveInProgress,
		RestoreInProgress,
		RTIinternalError)
		{
	check(federate);

	RTIRegion *region = root->getRegion(region_handle);

	root->getInteractionClass(interaction)->subscribe(federate, region);
		}

// ----------------------------------------------------------------------------
void
Federation::unsubscribeInteractionWR(FederateHandle federate,
		InteractionClassHandle interaction,
		RegionHandle region_handle)
throw (RegionNotKnown,
		SaveInProgress,
		RestoreInProgress,
		RTIinternalError)
		{
	check(federate);

	RTIRegion *region = root->getRegion(region_handle);

	root->getInteractionClass(interaction)->unsubscribe(federate, region);
		}

// ----------------------------------------------------------------------------
ObjectHandle
Federation::registerObjectWithRegion(FederateHandle federate,
		ObjectClassHandle class_handle,
		const std::string& object_name,
		RegionHandle region_handle,
		int nb,
		const std::vector <AttributeHandle> &attributes)
throw (ObjectClassNotDefined, ObjectClassNotPublished,
		AttributeNotDefined, AttributeNotPublished, RegionNotKnown,
		InvalidRegionContext, ObjectAlreadyRegistered,
		SaveInProgress, RestoreInProgress,
		RTIinternalError)
		{
	G.Out(pdGendoc,"enter Federation::registerObjectWithRegion");
	check(federate);

	// Register object
	ObjectHandle object = objectHandles.provide();
	Debug(D, pdDebug) << "Register object with region : Object " << object
			<< ", class " << class_handle << ", region " << region_handle
			<< std::endl ;
	string strname;
	if (!object_name.empty()) {
		strname = object_name;
	} else {
		// create a name if necessary
		strname = stringize() << "HLAObject_" << object;
	}

	root->registerObjectInstance(federate, class_handle, object, strname);

	Debug(D, pdDebug) << "- object \"" << strname
			<< "\" registered" << std::endl ;

	// Associate region
	RTIRegion *region = root->getRegion(region_handle);
	root->getObject(object)->unassociate(region);

	for (int i = 0 ; i < nb ; ++i) {
		root->getObjectAttribute(object, attributes[i])->associate(region);
	}

	Debug(D, pdDebug) << "- " << nb << " attribute(s) associated with region "
			<< region_handle << std::endl ;
	G.Out(pdGendoc,"exit  Federation::registerObjectWithRegion");
	return object ;
		}

// ----------------------------------------------------------------------------
bool
Federation::restoreXmlData()
{
#ifndef HAVE_XML
	return false ;
#else
	xmlNodePtr cur ;

	cur = xmlDocGetRootElement(doc);
	if (cur == 0) {
		cerr << "XML file is empty" << endl ;
		xmlFreeDoc(doc);
		return false ;
	}

	// Is this root element an ROOT_NODE ?
	if (xmlStrcmp(cur->name, ROOT_NODE)) {
		cerr << "Wrong XML file: not the expected root node" << endl ;
		return false ;
	}

	cur = cur->xmlChildrenNode ;
	if (xmlStrcmp(cur->name, NODE_FEDERATION)) {
		cerr << "Wrong XML file structure" << endl ;
		return false ;
	}

	if (strcmp(name.c_str(), XmlParser::CleanXmlGetProp(cur,(const xmlChar*)"name")) != 0) {
		cerr << "Wrong federation name" << endl ;
	}


	cur = cur->xmlChildrenNode ;

	bool status = false;
	while (cur != NULL) {
		if ((!xmlStrcmp(cur->name, NODE_FEDERATE))) {
			for (HandleFederateMap::iterator i = _handleFederateMap.begin(); i != _handleFederateMap.end(); ++i) {
				if (!strcmp(i->second.getName().c_str(),XmlParser::CleanXmlGetProp(cur, (const xmlChar*) "name"))) {
					// Set federate constrained status
					if (!strcmp("true", XmlParser::CleanXmlGetProp(cur, (const xmlChar*) "constrained"))) {
						status = true ;
					}
					else {
						status = false ;
					}

					i->second.setConstrained(status);

					// Set federate regulating status
					status = !strcmp("true", XmlParser::CleanXmlGetProp(cur, (const xmlChar *) "regulator"));

					i->second.setRegulator(status);

					i->second.setHandle(strtol(XmlParser::CleanXmlGetProp(cur, (const xmlChar *) "handle"), 0, 10));
					break ;
				}
			}
		}
		cur = cur->next ;
	}

	return status ;
#endif // HAVE_XML
}

// ----------------------------------------------------------------------------
bool
Federation::saveXmlData()
{
#ifndef HAVE_XML
	return false ;
#else
	doc = xmlNewDoc((const xmlChar *) "1.0");
	doc->children = xmlNewDocNode(doc, NULL, ROOT_NODE, NULL);

	xmlNodePtr federation ;
	federation = xmlNewChild(doc->children, NULL, NODE_FEDERATION, NULL);

	xmlSetProp(federation, (const xmlChar *) "name", (const xmlChar *) name.c_str());

	char t[10] ;
	sprintf(t, "%u", handle);
	xmlSetProp(federation, (const xmlChar *) "handle", (const xmlChar *) t);

	xmlNodePtr federate ;

	for (HandleFederateMap::iterator i = _handleFederateMap.begin(); i != _handleFederateMap.end(); ++i) {
		federate = xmlNewChild(federation, NULL, NODE_FEDERATE, NULL);

		xmlSetProp(federate,
				(const xmlChar *) "name",
				(const xmlChar *) i->second.getName().c_str());

		sprintf(t, "%u", i->second.getHandle());
		xmlSetProp(federate, (const xmlChar *) "handle", (const xmlChar *) t);

		xmlSetProp(federate,
				(const xmlChar *)"constrained", (const xmlChar *)
				((i->second.isConstrained()) ? "true" : "false"));
		xmlSetProp(federate, (const xmlChar *) "regulator",
				(const xmlChar *)((i->second.isRegulator()) ? "true" : "false"));
	}

	xmlSetDocCompressMode(doc, 9);

	string filename = name + "_" + saveLabel + ".xcs" ;
	xmlSaveFile(filename.c_str(), doc);

	// TODO: tests

	return true ;
#endif // HAVE_XML
}
// ----------------------------------------------------------------------------
FederateHandle
Federation::requestObjectOwner(FederateHandle theFederateHandle,
		ObjectHandle theObject,
		const std::vector <AttributeHandle> &theAttributeList,
		uint32_t theListSize)
throw (ObjectNotKnown)
{
	FederateHandle theOwnerHandle ;
	NM_Provide_Attribute_Value_Update mess ;

	G.Out(pdGendoc,"enter Federation::requestObjectOwner");

	// Request Object.
	theOwnerHandle = root->requestObjectOwner(theFederateHandle,theObject) ;

	// Send a PROVIDE_ATTRIBUTE_VALUE_UPDATE to the owner
	mess.setFederate(theFederateHandle);
	mess.setObject(theObject);
	mess.setAttributesSize(theListSize) ;
	for (uint32_t i = 0 ; i < theListSize ; ++i)
	{
		mess.setAttributes(theAttributeList[i],i) ;
	}

	// JYR : BUG if getSocketLink return NULL means
	// owner federate has been killed and so rtig don't crash
	// better development needed
	if ( server->getSocketLink(theOwnerHandle) == NULL )
	{
		throw ObjectNotKnown ( "Owner federate killed") ;
	}

	mess.send(server->getSocketLink(theOwnerHandle),NM_msgBufSend);

	G.Out(pdGendoc,"            requestObjectOwner ===> write PAVU to RTIA %d"
			,theOwnerHandle);
	G.Out(pdGendoc,"exit  Federation::requestObjectOwner");
	return(theOwnerHandle);

}

void 
Federation::requestClassAttributeValueUpdate(FederateHandle theFederateHandle,
								ObjectClassHandle theClassHandle,
								const std::vector <AttributeHandle> &theAttributeList,
								uint32_t theListSize)
		throw ( ObjectClassNotDefined, 
				RTIinternalError)
{
	G.Out(pdGendoc,"enter Federation::requestClassAttributeValueUpdate");

	// get object class 
	ObjectClass* oClass = root->getObjectClass(theClassHandle);
	if(!oClass) {
		throw ObjectClassNotDefined(certi::stringize() << "ObjectClassHandle <"<<theClassHandle<<"> is unknown.");
	}

	// send PAVU for all objects of this class
	ObjectClass::HandleObjectMap instances = oClass->getClassInstances();
	for( ObjectClass::HandleObjectMap::const_iterator it =
		 instances.begin(); it != instances.end(); ++it )
	{
		FederateHandle theOwnerHandle = it->second->getOwner();

		NM_Provide_Attribute_Value_Update mess ;

		// Send a PROVIDE_ATTRIBUTE_VALUE_UPDATE to the owner
		mess.setFederate(theFederateHandle);
		mess.setObject(it->first);
		mess.setAttributesSize(theListSize) ;
		for (uint32_t i = 0 ; i < theListSize ; ++i)
		{
			mess.setAttributes(theAttributeList[i],i) ;
		}

		// JYR : BUG if getSocketLink return NULL means
		// owner federate has been killed and so rtig don't crash
		// better development needed
		if ( server->getSocketLink(theOwnerHandle) == NULL )
		{
			throw RTIinternalError ( "Owner federate killed" ) ;
		}

		mess.send(server->getSocketLink(theOwnerHandle),NM_msgBufSend);

		G.Out(pdGendoc,"            requestClassAttributeValueUpdate ===> write PAVU to RTIA %d"
			,theOwnerHandle);
		G.Out(pdGendoc,"exit  Federation::requestClassAttributeValueUpdate");
	}
}

}} // namespace certi/rtig

// $Id: Federation.cc,v 3.137 2010/11/09 22:24:26 erk Exp $

