#include "mpi.h"
#include <stdio.h>
#include <math.h>
#include "oo/Function.h"
#include "oo/ParallelIntegrator.h"

namespace integrators
{
  namespace oo
  {
    // ParallelIntegrator implementation
    ParallelIntegrator::ParallelIntegrator ()
    {
      function_m = 0;
    }

    void ParallelIntegrator::setFunction (functions::Function *
                                          function_to_integrate)
    {
      function_m = function_to_integrate;
    }

    double ParallelIntegrator::integrate (double lowBound, double upBound,
                                          int count)
    {
      int  n, myid, numprocs, i;
      double result, myresult, h, sum, x;
      double startwtime = 0.0, endwtime;
      int namelen;
      char processor_name[MPI_MAX_PROCESSOR_NAME];

      MPI_Comm_size (MPI_COMM_WORLD, &numprocs);
      MPI_Comm_rank (MPI_COMM_WORLD, &myid);
      MPI_Get_processor_name (processor_name, &namelen);

      fprintf (stderr, "Process %d on %s: number of intervals = %d\n", myid, processor_name,
               count);

      n = count;
      MPI_Bcast (&count, 1, MPI_INT, 0, MPI_COMM_WORLD);
      if (count == 0)
        {
          return -1;
        }
      else
        {
          h = (upBound - lowBound) / (double) count;
          sum = 0.0;
          for (i = myid + 1; i <= count; i += numprocs)
            {
              x = h * ((double) i - 0.5);
              sum += function_m->evaluate (x);
            }
          myresult = h * sum;

          MPI_Reduce (&myresult, &result, 1, MPI_DOUBLE, MPI_SUM, 0,
                      MPI_COMM_WORLD);

        }

      return result;
    }

  }
}