/*!
 *  \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)");
}
/*!
 *  \brief Calculate the statistics of the current deme/generation.
 *  \param ioDeme Actual deme of the evolution.
 *  \param ioContext Context of the evolution.
 */
void StatsCalculateOp::operate(Deme& ioDeme, Context& ioContext)
{
	Beagle_StackTraceBeginM();
	Beagle_LogTraceM(
	    ioContext.getSystem().getLogger(),
	    "stats", "Beagle::StatsCalculateOp",
	    string("Calculating stats for the ")+
	    uint2ordinal(ioContext.getDemeIndex()+1)+" deme"
	);

	if(ioContext.getGeneration() != mGenerationCalculated) {
		mGenerationCalculated = ioContext.getGeneration();
		mNbDemesCalculated = 0;
	}

	if(ioDeme.getStats() == NULL) {
		const Factory& lFactory = ioContext.getSystem().getFactory();
		Stats::Alloc::Handle lStatsAlloc =
			castHandleT<Stats::Alloc>(lFactory.getConceptAllocator("Stats"));
		Stats::Handle lStats = castHandleT<Stats>(lStatsAlloc->allocate());
		ioDeme.addMember(lStats);
	}

	if(ioDeme.getStats()->isValid() == false) {
		calculateStatsDeme(*ioDeme.getStats(), ioDeme, ioContext);
		ioDeme.getStats()->setValid();
	}
	
	Beagle_LogObjectM(
	    ioContext.getSystem().getLogger(),
	    Logger::eStats,
	    "stats",
	    "Beagle::StatsCalculateOp",
	    *ioDeme.getStats()
	);

	if(++mNbDemesCalculated == mPopSize->size()) {
		Beagle_LogTraceM(
		    ioContext.getSystem().getLogger(),
		    "stats", "Beagle::StatsCalculateOp",
		    "Calculating stats for the vivarium"
		);
		
		if(ioContext.getVivarium().getStats() == NULL) {
			const Factory& lFactory = ioContext.getSystem().getFactory();
			Stats::Alloc::Handle lStatsAlloc =
				castHandleT<Stats::Alloc>(lFactory.getConceptAllocator("Stats"));
			Stats::Handle lStats = castHandleT<Stats>(lStatsAlloc->allocate());
			ioContext.getVivarium().addMember(lStats);
		}
		
		calculateStatsVivarium(*ioContext.getVivarium().getStats(),
		                       ioContext.getVivarium(),
		                       ioContext);
		ioContext.getVivarium().getStats()->setValid();
		
		Beagle_LogObjectM(
		    ioContext.getSystem().getLogger(),
		    Logger::eStats,
		    "stats", "Beagle::StatsCalculateOp",
		    *ioContext.getVivarium().getStats()
		);
	}
	Beagle_StackTraceEndM("void StatsCalculateOp::operate(Deme& ioDeme, Context& ioContext)");
}