/*!
 *  \brief Send the individuals that were modified during the current generation.
 *  \param ioDeme Current deme to execute the operator.
 *  \param ioContext Current context to execute the operator.
 *  \todo Check if this operator can be used with migration operator.
 *  This operator can only be used in a context where the size of the
 *  population remains constant for all generations.
 */
void HPC::SendProcessedToSupervisorOp::operate(Deme& ioDeme, Context& ioContext)
{
	Beagle_StackTraceBeginM();

	ProcessingBuffer::Handle lBuffer = castHandleT<ProcessingBuffer>(ioDeme.getMember("ProcessingBuffer"));
	Beagle_NonNullPointerAssertM(lBuffer);

	std::ostringstream lOutStream;

	PACC::XML::Streamer lStreamer(lOutStream);
	lStreamer.openTag("Population");
	for(unsigned int i = 0; i < lBuffer->size(); ++i)
		(*lBuffer)[i]->write(lStreamer,false);
	lStreamer.closeTag();

	mComm->send(uint2str(ioContext.getProcessedDeme()), "NbrProcessed", "Parent");
	mComm->send(lBuffer->getIndex().serialize(), "ProcessedIndex", "Parent");
	mComm->send(lOutStream.str(), "Processed", "Parent");

	Beagle_LogDetailedM(
		ioContext.getSystem().getLogger(),
		"send", "Beagle::HPC::SendProcessedToSupervisorOp",
		std::string("Evolver send deme to his supervisor")
	);

	Beagle_StackTraceEndM("void HPC::SendProcessedToSupervisorOp::operate(Deme& ioDeme, Context& ioContext)");
}
/*!
 *  \brief Receive the fitness of an individuals group from evaluator node.
 *  \param ioDeme Deme to update by the receive fitness.
 *  \param ioContext Current context of the evolution.
 */
void HPC::RecvFitnessFromEvaluatorOp::operate(Deme& ioDeme, Context& ioContext)
{
	Beagle_StackTraceBeginM();

	ProcessingBuffer::Handle lBuffer = castHandleT<ProcessingBuffer>(ioDeme.getMember("ProcessingBuffer"));
	Beagle_NonNullPointerAssertM(lBuffer);

	Individual::Handle lOldIndividualHandle = ioContext.getIndividualHandle();
	unsigned int lOldIndividualIndex = ioContext.getIndividualIndex();

	prepareStats(ioDeme,ioContext);

	unsigned int lNbEvaluators = mComm->getNbrOfRelation("Child");

	unsigned int lNbIndividualInt = lBuffer->size() / lNbEvaluators;
	unsigned int lNbIndividualFrac = lBuffer->size() % lNbEvaluators;

	unsigned int lNbIndividualTotal = 0;

	for(int i = 0; i < lNbEvaluators; ++i ){
		int lNbIndividual = lNbIndividualInt;
		if(i < lNbIndividualFrac)
			++lNbIndividual;
		std::string lFitnessString;

		mComm->receive(lFitnessString, "Fitness", "Child", i);

		Beagle_LogDetailedM(
			ioContext.getSystem().getLogger(),
			"receive", "Beagle::HPC::RecvFitnessFromEvaluatorOp",
			std::string("Evolver receive fitness from his ")+uint2ordinal(i+1)+
			std::string(" evaluator") + std::string(" of ") + uint2str(lNbEvaluators)
		);

		std::istringstream lInStream(lFitnessString);
		PACC::XML::Document lDocument(lInStream);

		const Factory& lFactory = ioContext.getSystem().getFactory();
		Fitness::Alloc::Handle lFitnessAlloc =
				castHandleT<Fitness::Alloc>(lFactory.getConceptAllocator("Fitness"));
		for(PACC::XML::ConstIterator lIter = lDocument.getFirstRoot()->getFirstChild(); lIter; ++lIter){
			ioContext.setIndividualIndex(lNbIndividualTotal);
			ioContext.setIndividualHandle(ioDeme[lNbIndividualTotal]);
			if((*lBuffer)[lNbIndividualTotal]->getFitness() == 0)
				(*lBuffer)[lNbIndividualTotal]->setFitness( castHandleT<Fitness>(lFitnessAlloc->allocate()) );
			(*lBuffer)[lNbIndividualTotal]->getFitness()->read(lIter);
			++lNbIndividualTotal;
			updateStats(1,ioContext);
		}
	}
	Beagle_LogDetailedM(
		ioContext.getSystem().getLogger(),
		"receive", "Beagle::HPC::RecvFitnessFromEvaluatorOp",
		std::string("Evolver receive all its fitness.")
	);

	ioContext.setIndividualIndex(lOldIndividualIndex);
	ioContext.setIndividualHandle(lOldIndividualHandle);
	Beagle_StackTraceEndM("void RecvFitnessFromEvaluatorOp::operate(Deme& ioDeme, Context& ioContext)");
}
/*!
 *  \brief Distribute groups of individuals to evaluators nodes childs.
 *  \param ioDeme Current deme to execute the operator.
 *  \param ioContext Current context to execute the operator.
 *  This function distributed individuals to the evolver's evaluators.
 *
 *  It first checks if the deme has a \ref ProcessingBuffer. The buffer
 *  is used to memorize which individuals had invalid fitness, since the
 *  function only distributes individuals that were modified during the
 *  current generation. Once the buffer is filled, the individuals are
 *  distributed to evaluator.
 *  The number of individuals an evaluato will received is based on this
 *  formula :
 *  \f[ NbIndividuals =
        \left\{
	\begin{array}{lr}
	\frac{BufferSize}{NbEvaluators} + 1, &  EvaluatorRank > BufferSize \pmod{NbEvaluators} \\
	\frac{BufferSize}{NbEvaluators},  & else
	\end{array}
	\right.
    \f]
 *
 *  The function write the individuals in a streamer. The streamer opening
 *  tag is <Population> so the evaluator can directly read the string at
 *  its reception as a deme.
 *
 *  The string are sent using a non-blocking send function, so the function
 *  doesn't have to wait for the transaction to be completed before starting
 *  to build another packet of individuals. The function ends when all
 *  packets have been sent.
 */
void HPC::DistributeDemeToEvaluatorsOp::operate(Deme& ioDeme, Context& ioContext)
{
	Beagle_StackTraceBeginM();

	unsigned int lNbEvaluators = mComm->getNbrOfRelation("Child");

	ProcessingBuffer::Handle lBuffer = castHandleT<ProcessingBuffer>(ioDeme.getMember("ProcessingBuffer"));
	if(lBuffer==0){
		lBuffer = new ProcessingBuffer;
		ioDeme.addMember(lBuffer);
	}
	lBuffer->clear();
	for(unsigned int i = 0; i < ioDeme.size(); ++i){
		if((ioDeme[i]->getFitness() == 0) ||
		   (ioDeme[i]->getFitness()->isValid() == false)){
			lBuffer->push_back(ioDeme[i], i);
		}
	}

	unsigned int lNbIndividualInt = lBuffer->size() / lNbEvaluators;
	unsigned int lNbIndividualFrac = lBuffer->size() % lNbEvaluators;

	unsigned int lNbIndividualTotal = 0;
	unsigned int lNbIndividual = 0;

	std::vector<std::string> lStreams(lNbEvaluators);
	MPICommunication::Request::Bag lRequests(lNbEvaluators);
	for(unsigned int i = 0; i < lNbEvaluators; ++i){

		lNbIndividual = lNbIndividualInt;
		if(i < lNbIndividualFrac)
			lNbIndividual++;

		std::ostringstream lOutStream;
		PACC::XML::Streamer lStreamer(lOutStream);

		lStreamer.openTag("Population");
		for(int j = 0; j < lNbIndividual; ++j){
			(*lBuffer)[j+lNbIndividualTotal]->write(lStreamer, false);
		}
		lStreamer.closeTag();
		lStreams[i] = lOutStream.str();
		lRequests[i] = new MPICommunication::Request;
		mComm->sendNonBlocking(lStreams[i], lRequests[i], "Individuals", "Child", i);

		lNbIndividualTotal += lNbIndividual;

		Beagle_LogDetailedM(
			ioContext.getSystem().getLogger(),
			"distribute", "Beagle::HPC::DistributeDemeToEvaluatorsOp",
			std::string("Evolver send fractionnal Deme to his ")+uint2ordinal(i+1)+ " evaluator"
		);
	}
	mComm->waitAll(lRequests);
	Beagle_StackTraceEndM("DistributeDemeToEvaluatorsOp::operate(Deme& ioDeme, Context& ioContext)");
}