/* -*- C++ -*- */
#ifndef __fft_Histogram_Header_File__
#define __fft_Histogram_Header_File__

#include "types.h"
#include "Array2D.h"
#include <cstring>
#include <cassert>
#include <iostream>
#include <fstream>

namespace fft
{
   template <typename T>
   class Histogram
   {

      public:

	 struct ExtremeValue
	 {
	       ExtremeValue(T pos, u32 val)
		  : position(pos), value(val)
	       {}
	       
	       T position;
	       u32 value;
	 };

	 typedef std::vector<ExtremeValue> ExtremeValueList;

	 Histogram(const Array2D<T>& src, u32 nStep)
	    : nStep(nStep),
	      histMin(src.min()), histMax(src.max()),
	      stepSize((histMax - histMin) / nStep), 
	      data(0)
	 {
	    data = new u32[nStep];
	    memset(data, sizeof(u32) * nStep, 0);
	    for (u32 i = 0; i < src.size(); i++)
	    {
	       data[cellIdx(src[i])]++;
	    }
	 }

	 u32 cellIdx(T val)
	 {
	    return static_cast<u32>((val - histMin)/stepSize);
	 }

	 T cellCenter(u32 idx)
	 {
	    return histMin + static_cast<T>(idx + 0.5) * stepSize;
	 }

	 ~Histogram()
	 {
	    delete [] data;
	    data = 0;
	 }

	 //
	 // accessors
	 //

	 u32 operator[](u32 idx) const
	 {
	    assert(idx <= nStep);
	    return data[idx];
	 }


	 
	 ExtremeValueList localMax(u32 lookAhead = 1)
	 {
	    ExtremeValueList ret;

	    for (u32 i = lookAhead; i < nStep - lookAhead; i+= lookAhead)
	    {
	       s32 difR = data[i + lookAhead] - data[i];
	       s32 difL = data[i] - data[i - lookAhead];
	       if (difL < 0 && difR > 0)
	       {
		  ret.push_back(ExtremeValue(cellCenter(i), data[i]));
	       }
	    }

	    return ret;
	 }

	 
	 void convolution(const T* kernel, u32 kernelSize)
	 {
	    u32* locData = new u32[nStep];
	    u32 ks2 = kernelSize / 2;
	    for (u32 i = 0; i < nStep; i++)
	    {
	       u32& val = locData[i];
	       val = 0;

	       for (u32 j = 0; j < kernelSize; j++)
	       {
		  s32 idx = static_cast<s32>(i + j) - ks2;
		  u32 idxx = (idx < 0) ? (idx + nStep) : ((idx >= nStep) ? (idx - nStep) : idx);
		  val += data[idxx] * kernel[j];
	       }
	    }
	    
	    delete [] data;
	    data = locData;
	 }

	 void print()
	 {
	    for (u32 i = 0; i < nStep; i++)
	    {
	       std::cerr << data[i] << " ";
	    }
	    std::cerr << std::endl;
	 }

	 void storeGnuPlot(const String& fname)
	 {
	    std::ofstream ofs(fname.c_str(), std::ios::out);
	    
	    for (u32 i = 0; i < nStep; i++)
	    {
	       ofs << cellCenter(i) << " " << data[i] << std::endl;
	    }
	    ofs << std::endl;
	    
	    ofs.close();

	 }




      private:
	 u32 nStep;
	 T histMin, histMax;
	 T stepSize;
	 u32* data;
   };
}



#endif //__fft_Histogram_Header_File__

