#include "globals.h"

#include "Communication.h"
#include "Parameters.h"
#include "Statistics.h"

bool global::isMultipleOf( unsigned int divisor, unsigned int dividend ) {
  return (( divisor % dividend ) == 0 );
}

void global::solve( SgEngine *engine, const StoppingConditions &stopCon ) {
  // Fetch singletons
  Parameters *parameters = Parameters::getInstance();
  Statistics *statistics = Statistics::getInstance();
  // Create communication object
  Communication communication( engine );
  communication.solveBegin();

  while ( !statistics->isExecutionFinished() ) {
    bool newEpoch = false;
    communication.checkMessages();
    engine->doMoreGenerations( parameters->getIntervalUpdateParameters() );
    unsigned int numGenerations = statistics->adjustNumGenerations( parameters->getIntervalUpdateParameters() );
    engine->updatePopulation();
    if ( parameters->getRank() == 0 && // only p0 should evaluate the global stopping conditions
         !statistics->isGlobalStopSent() &&
         isMultipleOf( numGenerations, parameters->getIntervalStoppingGlobal() ) &&
         stopCon.poll( StoppingConditions::GLOBAL ) ) {
      communication.sendMessage( Messages::GLOBAL_STOP );
    }
    if ( !statistics->isGlobalStopSent() &&
         isMultipleOf( numGenerations, parameters->getIntervalStoppingLocal() ) &&
         stopCon.poll( StoppingConditions::LOCAL ) ) {
      communication.sendMessage( Messages::LOCAL_STOP );
    }
    if ( !statistics->isGlobalStopSent() &&
         isMultipleOf( numGenerations, parameters->getIntervalCheckEpoch() ) &&
         stopCon.checkEpoch() ) {
      communication.sendMessage( Messages::ALLELES );
      newEpoch = true;
    }
    parameters->updateParameters( newEpoch );
    if ( newEpoch )
      statistics->startNewEpoch();
  } // while ( !statistics->isExecutionFinished() )
  communication.solveEnd();
}
