#ifndef SEARCHRADIUS_H
#define SEARCHRADIUS_H

#include "correlation.h"

//TMP
//#include <fstream>

namespace seemicro
{

/**
  * Dieses Modul steuert ein CorrelationModule. Es wird aktiv,
  * wenn \c correlation.micro.radiusValid == \c false.
  * Dann wird eine Korrelation über die Radien von 30 bis 120
  * durchgeführt und der Radius, bei dem sich eine maximale
  * Korrelationsstärke ergibt, als gefundener Radius
  * gesetzt.
  */
struct SearchRadiusModule : public RecognitionModule
{
    /**
      * Das CorrelationModule-Objekt, das kontrolliert wird.
      */
    CorrelationModule& correlation;

    /**
      * Zwischenvariable. Radius, bei dem maximale Korrelationsstärke
      * auftrat.
      */
    float best;

    float step;
    int MINR;
    int MAXR;
    /**
      * Korrelationsstärken der Radien, für die eine
      * Korrelation durchgeführt wurde. Sie bilden
      * einen interessanten Graphen.
      */
    float *maximaz, *maximazGemittelt;

    /**
      * Anzahl der Arrayelemente von *maximaz
      */
    int maximazMAXI;

    SearchRadiusModule(CorrelationModule& Ac, int AMINR=30, int AMAXR=120, float Astep=1.0) :
      correlation(Ac), step(Astep), MINR(AMINR), MAXR(AMAXR)
    {
      maximazMAXI = int((MAXR-MINR)/step);
      maximaz = new float[maximazMAXI];
      maximazGemittelt = new float[maximazMAXI];
      correlation.micro.radiusValid = false;
    }

    ~SearchRadiusModule()
    {
      delete [] maximaz;
      delete [] maximazGemittelt;
    }

    void processKeyFrame(void)
    {
      if(correlation.micro.radiusValid) return;

#ifdef DEBUG
      if(DEBUGLEVEL >= 2) cerr << "radiusValid = false\n";
#endif

      // auflösungsabhängig suchen -> maximaz[] entsprechend groß!
      best = searchRadius(maximaz, float(MINR), float(MAXR), step);
      correlation.micro.radius = best;
      correlation.micro.radiusValid = true;
      correlation.kparams->radius = best;
      correlation.paramChanged = true;
      correlation.outputChanged = true;// damit correlationOutput sich aktualisiert
      outputChanged = true;
    }

    /**
      * Führt Korrelation für Radien minRadius bis maxRadius durch und füllt @c values[]
      * mit der jeweiligen Korrelationsstärke.
      * @returns radius of highest response.
      * 	 better: should return params of highest response!
      */
    float searchRadius(float *values, float minRadius, float maxRadius,
	float step)
    {
      int index = 0;
      int mostmaxindex = 0;
      float best = minRadius;

      //TMP
      //std::ofstream o("radius-korrelationsstärke.data");

      for(float r=minRadius; r<maxRadius; r+=step)
      {
	if(DEBUGLEVEL >= 3) cerr << "r=" << r;

	correlation.kparams->radius=r;
	correlation.paramChanged = true;
	correlation.processKeyFrame();
	values[index] = correlation.correlationStrength;

	//TMP
	//o << r << "\t" << correlation.correlationStrength << std::endl;

	if(DEBUGLEVEL >= 3)
	  cerr << " strength=" << correlation.correlationStrength << endl;
	if(values[mostmaxindex] < correlation.correlationStrength)
	{
	  mostmaxindex = index;
	  best = r;
	}
	index++;
      }

      for(int i=1;i<maximazMAXI-1;i++)
      {
	maximazGemittelt[i] = 0.25*maximaz[i-1] + 0.5*maximaz[i] + 0.25*maximaz[i+1];
      }

      //TMP
      //o.close();

      return best;
    }

  }; // SearchRadiusModule

} // seemicro

#endif // RECOGNITIONMODULE_H

