/**
 * Creates objects on remote nodes.
 * Also tests that objects on /library get created on all nodes.
 * \todo: Needs to be extended by creating objects on remote nodes with
 * parents on different remote nodes.
 */
Id testParCreate( vector< Id >& testIds )
{
	unsigned int myNode = MuMPI::INTRA_COMM().Get_rank();
	unsigned int numNodes = MuMPI::INTRA_COMM().Get_size();
	if ( myNode == 0 )
		cout << flush << "\nTest ParCreate";
	MuMPI::INTRA_COMM().Barrier();
	cout << "b" << myNode << flush;
	MuMPI::INTRA_COMM().Barrier();
	Eref shellE = Id::shellId().eref();
	assert( shellE.e != 0 );
	if ( myNode == 0 ) {
		Slot remoteCreateSlot = 
			initShellCinfo()->getSlot( "parallel.createSrc" );
		for ( unsigned int i = 1; i < numNodes; i++ ) {
			char name[20];
			sprintf( name, "tn%d", i );
			string sname = name;
			unsigned int tgt = ( i < myNode ) ? i : i - 1;
			Id newId = Id::makeIdOnNode( i );
			testIds.push_back( newId );
			// cout << "Create op: sendTo4( shellId, slot, " << tgt << ", " << "Neutral, " << sname << ", root, " << newId << endl;
			sendTo4< string, string, Nid, Nid >(
				shellE, remoteCreateSlot, tgt,
				"Neutral", sname, 
				Id(), newId
			);
		}
		Id libid = Id::localId( "/library" ); // a global
		ASSERT( libid.good(), "create libkids" );
		ASSERT( libid.isGlobal(), "create libkids" );
		SetConn c( shellE );
		Shell::staticCreate( &c, "Neutral", "foo", Id::UnknownNode, libid );
	}
	MuMPI::INTRA_COMM().Barrier();
	pollPostmaster(); // There is a barrier in the polling operation itself
	MuMPI::INTRA_COMM().Barrier();
	pollPostmaster();
	MuMPI::INTRA_COMM().Barrier();
	pollPostmaster();
	MuMPI::INTRA_COMM().Barrier();
	char name[20];
	sprintf( name, "/tn%d", myNode );
	string sname = name;
	Id kidid = Id::localId( "/library/foo" );
	ASSERT( kidid.good(), "create libkids" );
	ASSERT( kidid.isGlobal(), "create libkids" );
	bool ret = set( kidid.eref(), "destroy" );
	ASSERT( ret, "destroy libkids" );
	if ( myNode != 0 ) {
		Id tnId = Id::localId( sname );
		ASSERT( tnId.good(), "postmaster created obj on remote node" );
		return tnId;
	}
	return Id();
}
void testParSet( vector< Id >& testIds )
{
	//////////////////////////////////////////////////////////////////
	// Now test 'set' across nodes. This fits nicely as a unit test.
	//////////////////////////////////////////////////////////////////
	char name[20];
	string sname;
	unsigned int myNode = MuMPI::INTRA_COMM().Get_rank();
	unsigned int numNodes = MuMPI::INTRA_COMM().Get_size();
	Eref shellE = Id::shellId().eref();
	assert( shellE.e != 0 );
	MuMPI::INTRA_COMM().Barrier();
	if ( myNode == 0 ) {
		cout << "\ntesting parallel set" << flush;
		Slot parSetSlot = 
			initShellCinfo()->getSlot( "parallel.setSrc" );
		for ( unsigned int i = 1; i < numNodes; i++ ) {
			sprintf( name, "bar%d", i * 10 );
			sname = name;
			unsigned int tgt = ( i < myNode ) ? i : i - 1;
			// objId, field, value
			sendTo3< Id, string, string >(
				shellE, parSetSlot, tgt,
				testIds[i - 1], "name", sname
			);
		}
		Id libid = Id::localId( "/library" ); // a global
		ASSERT( libid.good(), "create libkids" );
		ASSERT( libid.isGlobal(), "create libkids" );
		SetConn c( shellE );
		Shell::staticCreate( &c, "Neutral", "foo", Id::UnknownNode, libid );
	}
	
	MuMPI::INTRA_COMM().Barrier();
	pollPostmaster();
	MuMPI::INTRA_COMM().Barrier();
	pollPostmaster();

	if ( myNode != 0 ) {
		sprintf( name, "/bar%d", myNode * 10 );
		sname = name;
		Id checkId = Id::localId( sname );
		// cout << "On " << myNode << ", checking id for " << sname << ": " << checkId << endl;
		ASSERT( checkId.good(), "parallel set" );
		cout << flush;
	}

	////////////////////////////////////////////////////////////////
	// Here we check for assignment on globals.
	////////////////////////////////////////////////////////////////
	Id kidid = Id::localId( "/library/foo" );
	ASSERT( kidid.good(), "setting libkids" );
	ASSERT( kidid.isGlobal(), "setting libkids" );
	MuMPI::INTRA_COMM().Barrier();
	if ( myNode == 0 ) {
		cout << "\ntesting global set" << flush;
		SetConn c( shellE );
		Shell::setField( &c, kidid, "name", "bar" );
	}
	MuMPI::INTRA_COMM().Barrier();
	pollPostmaster();
	MuMPI::INTRA_COMM().Barrier();
	pollPostmaster();
	
	Id newKidid = Id::localId( "/library/bar" );
	ASSERT( newKidid == kidid, "setting libkids" );
	ASSERT( newKidid.good(), "setting libkids" );
	ASSERT( newKidid.isGlobal(), "setting libkids" );
	
	bool ret = set( kidid.eref(), "destroy" );
	ASSERT( ret, "destroy libkids" );
	cout << flush;
	MuMPI::INTRA_COMM().Barrier();
}
/**
 * Copies objects on remote nodes.
 * - Create original in /library              : All nodes
 * - Create target{i} on individual nodes.    : One at a time
 * - Copy /library/orig /library/dup          : Automagically on all nodes
 * - Copy /library/dup /target{i}             : One at a time
 * - Copy /target{i}/dup /target{i}/zung      : One at a time.
 *   Cannot test this last one yet because I can't get Ids from remote node
 *
 * Also tests that objects on /library get copied on all nodes.
 * \todo: Stil don't have capability to copy across nodes.
 */
void testParCopy()
{
	unsigned int myNode = MuMPI::INTRA_COMM().Get_rank();
	unsigned int numNodes = MuMPI::INTRA_COMM().Get_size();
	if ( myNode == 0 )
		cout << flush << "\nTest ParCopy";
	MuMPI::INTRA_COMM().Barrier();
	Eref shellE = Id::shellId().eref();
	assert( shellE.e != 0 );
	if ( myNode == 0 ) {
		vector< Id > targets;
		SetConn c( shellE );
		Shell::staticCreate( &c, "Neutral", "target0", 0, Id() );
		Id temp( "/target0" );
		ASSERT( temp.good(), "Testng copy" );
		targets.push_back( temp );
		Slot remoteCreateSlot = 
			initShellCinfo()->getSlot( "parallel.createSrc" );
		for ( unsigned int i = 1; i < numNodes; i++ ) {
			char name[20];
			sprintf( name, "target%d", i );
			string sname = name;
			unsigned int tgt = ( i < myNode ) ? i : i - 1;
			Id newId = Id::makeIdOnNode( i );
			targets.push_back( newId );
			sendTo4< string, string, Nid, Nid >(
				shellE, remoteCreateSlot, tgt,
				"Neutral", sname, 
				Id(), newId
			);
		}
		Id libid = Id::localId( "/library" ); // a global
		ASSERT( libid.good(), "create libkids" );
		ASSERT( libid.isGlobal(), "create libkids" );
		Shell::staticCreate( &c, "Neutral", "orig", Id::UnknownNode, libid );
		Id origId = Id::localId( "/library/orig" );
		ASSERT( origId != Id(), "Testing copy" );
		Shell::copy( &c, origId, libid, "dup" );
		assert( targets.size() == numNodes );
		for ( unsigned int i = 0; i < numNodes; i++ ) {
			Shell::copy( &c, origId, targets[i], "dup" );
		}
	}
	MuMPI::INTRA_COMM().Barrier();
	pollPostmaster(); // There is a barrier in the polling operation itself
	MuMPI::INTRA_COMM().Barrier();
	pollPostmaster();
	MuMPI::INTRA_COMM().Barrier();
	pollPostmaster();
	MuMPI::INTRA_COMM().Barrier();
	char name[20];
	sprintf( name, "/tn%d", myNode );
	string sname = name;
	Id kidid = Id::localId( "/library/orig" );
	ASSERT( kidid.good(), "copy libkids" );
	ASSERT( kidid.isGlobal(), "copy libkids" );
	bool ret = set( kidid.eref(), "destroy" );
	ASSERT( ret, "destroy libkids" );
	kidid = Id::localId( "/library/dup" );
	ASSERT( kidid.good(), "copy libkids" );
	// cout << " on " << myNode << ": kidid = " << kidid << ", node = " << kidid.node() << endl << flush;
	ASSERT( kidid.isGlobal(), "copy libkids" );
	ret = set( kidid.eref(), "destroy" );
	ASSERT( ret, "destroy libkids" );
	sprintf( name, "/target%d/dup", myNode );
	sname = name;
	kidid = Id::localId( sname );
	ASSERT( kidid.good(), "copy libkids to node" );
	ASSERT( !kidid.isGlobal(), "copy libkids to node" );
	sprintf( name, "/target%d", myNode );
	sname = name;
	kidid = Id::localId( sname );
	ret = set( kidid.eref(), "destroy" );
	ASSERT( ret, "destroy libkids" );
	// Should have a global delete for library objects too.
}