#include <iostream>

#include "cca.h"
#include "ports/Function_CCA.h"
#include "ports/RandomGenerator_CCA.h"

#include "MonteCarloIntegrator_CCA.h"
#include "macros_CCA.h"

namespace integrators
{
  namespace ccaimpl
  {
    // Integrator interface methods

    MonteCarloIntegrator::MonteCarloIntegrator ()
    {
      function_m = 0;
      random_m = 0;
      frameworkServices = 0;
    }

    MonteCarloIntegrator::~MonteCarloIntegrator ()
    {
    }

    double MonteCarloIntegrator::integrate (double lowBound, double upBound,
                                            int count)
    {
      gov::cca::Port * port;
      double sum = 0.0;

      // Get RandomGenerator port
      port = frameworkServices->getPort ("RandomGeneratorPort");
      if (port)
        random_m =
          dynamic_cast < randomgen::ccaports::RandomGenerator * >(port);
      if (random_m == 0)
        {
          cerr << "Connected to something other than a RandomGenerator port"
            << endl;
          return -1;
        }

      // Get Function port
      port = frameworkServices->getPort ("FunctionPort");
      if (port)
        function_m = dynamic_cast < functions::ccaports::Function * >(port);
      if (function_m == 0)
        {
          cerr << "Connected to something other than a Function port" << endl;
          return -1;
        }

      for (int i = 0; i < count; i++)
        {
          double x = random_m->getRandomNumber ();
          sum = sum + function_m->evaluate (x);
        }

      // Release ports
      frameworkServices->releasePort ("RandomGeneratorPort");
      frameworkServices->releasePort ("FunctionPort");

      return (upBound - lowBound) * sum / count;
    }

    /**
     * The framework passes a pointer to the Services object
     * via this method, which is called by the framework as soon
     * as the component is instantiated.
     */
    void MonteCarloIntegrator::setServices (gov::cca::Services * services)
    {
      if (services != 0)
        {
          frameworkServices = services;

          // Provide an Integrator port
          gov::cca::PortInfo * portInfo =
            frameworkServices->createPortInfo ("IntegratorPort",
                                               "integrators.ccaports.Integrator",
                                               0);
          if (portInfo != 0)
            frameworkServices->addProvidesPort (this, portInfo);

          // Use a Function port
          portInfo =
            frameworkServices->createPortInfo ("FunctionPort",
                                               "functions.ccaports.Function",
                                               0);
          frameworkServices->registerUsesPort (portInfo);

          // Use a a RandomGenerator port
          portInfo =
            frameworkServices->createPortInfo ("RandomGeneratorPort",
                                               "randomgen.ccaports.RandomGenerator",
                                               0);
          frameworkServices->registerUsesPort (portInfo);
        }
      else
        {
          // Close down if not closed already
          if (frameworkServices != 0)
            frameworkServices->removeProvidesPort ("IntegratorPort");
          frameworkServices = 0;
        }
    }

  }
}