/***************************************************************************
 *   Copyright (C) 2005 by Armando Navarro Vazquez   *
 *   qoajnv@usc.es   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#include <algorithm>

#include <qpainter.h>

#include "peakpicker.h"
#include "spectrum.h"

const size_t capacity=80;
PeakPicker::PeakPicker() : m_spectrum(NULL)
{
  m_peaks.reserve(capacity);
}

PeakPicker::PeakPicker(Spectrum* sp) : m_spectrum(sp)
{
  m_peaks.reserve(capacity);
}



PeakPicker::~PeakPicker()
{}


void PeakPicker::Clear()
{
  m_peaks.clear();
  m_peaks.reserve(capacity);
}


void PeakPicker::Calculate(const QRect& region, const QRect& clientrect)
{
  const fidarray& data=m_spectrum->Data();
  size_t firstwpoint, lastwpoint;
  m_spectrum->ScreenLimits(firstwpoint,lastwpoint);
  float l=static_cast<float>(region.left()-clientrect.left())/clientrect.width();
  float r=static_cast<float>(region.right()-clientrect.left())/clientrect.width();
  size_t first=qRound((lastwpoint-firstwpoint)*l)+firstwpoint;
  size_t last=qRound((lastwpoint-firstwpoint)*r)+firstwpoint;
  size_t i;
  float max=1e-12;
  float min=-1e-12;
  for(i=firstwpoint;i<lastwpoint;i++)
  {
    if( data[i].real() > max ) max=data[i].real();
    if (data[i].real() < min ) min=data[i].real();
  }
  float nslevel=GetNoiseLevel();
 // if ( fabs(limit) < 5*nslevel ) limit=nslevel;
  for(size_t i=first;i<last;i++)
  {
    float val=data[i].real();
    if( fabs(val) > (max/25) )
    {
      if( ( val > data[i-1].real() ) &&  ( val > data[i+1].real() ) && (val > data[i-2].real() ) &&  ( val > data[i+2].real() )  )
        m_peaks.push_back(i);

     /* if( ( val < data[i-1].re ) &&  ( val < data[i+1].re ) && (val < data[i-2].re ) &&  ( val < data[i+2].re ) && (val < data[i-3].re ) &&  ( val < data[i+3].re ))
        m_peaks.push_back(i);*/

    }
  }
  //sort the container
   std::sort( m_peaks.begin(), m_peaks.end() );  
   std::vector<size_t>::iterator it=std::unique( m_peaks.begin(), m_peaks.end() );
   m_peaks.erase(it,m_peaks.end());

}

float PeakPicker::GetNoiseLevel()
{
  const fidarray& data=m_spectrum->Data();
  const size_t nregions=16;
  size_t size=data.size()/nregions;
  float sd=1e12;
  for(size_t i=0;i<nregions;i++)
  {
    float rsd=GetSD(i*size,(i+1)*size-1);
    if( rsd < sd) sd=rsd;
  }

  return sd;

}

float PeakPicker::GetSD(size_t first,size_t last)
{
  size_t interval=last-first;
  float sum=0;
  const fidarray& data=m_spectrum->Data();
  for(size_t i=first;i<last;i++)
  {
    sum+=data[i].real();
  }
  float av=sum/interval;
  sum=0;
  for(size_t i=first;i<last;i++)
  {
    float diff=data[i].real()-av;
    sum+=(diff*diff);
  }
  return sqrt(sum/interval);

}


void PeakPicker::Draw(QPainter* p, const QRect& rect)
{
  int npeaks=m_peaks.size();	//Count the peaks to draw
  int counter=0;
  size_t from,to;
  m_spectrum->ScreenLimits(from,to);
  int i;
  for(i=0;i<npeaks;i++)
  {
    if( m_peaks[i] > from && m_peaks[i] < to)
      counter++;
  }
  if( counter == 0 ) return;
  p->save();
  int x;

  QPen pen(QColor(255,255,255));
  QFont font("Arial");
  p->setPen(pen);
  p->setFont(font);

  float Hz,ppm,real,im;
  int* textx= new int[counter];




  //int* textx=new int [counter];

  QString str1("text");
  QFontMetrics metricfont=p->fontMetrics();
  QRect boundrect=metricfont.boundingRect(str1);
  //CSize size=pDC->GetTextExtent(str1);
  m_width=boundrect.height();
  m_width++;



  counter=0;
  for(i=0;i<npeaks;i++)
  {
    if(m_peaks[i]>=from && m_peaks[i]<to)
    {
      int peak=m_peaks[i];
      //fid.GetInfoSpectrum(peak,&ppm,&Hz,&real,&im);
      x=qRound( (peak-from)*rect.width()/static_cast<float>(to-from) ) + rect.left();
      textx[counter]=x;
      counter++;


    }
  }

  OrganizeText(textx,rect,counter);
  OrganizeText(textx,rect,counter);
  counter=0;

  QPen linepen(QColor(255,25,25));

  int height=rect.height();
  for(i=0;i<npeaks;i++)
  {
    if( m_peaks[i] > from && m_peaks[i] < to)
    {
      p->setPen(linepen);
      int peak=m_peaks[i];
      int x=qRound( (peak-from)*rect.width()/static_cast<float>(to-from))+rect.left();
      int x1=textx[counter];
      counter++;
      QString str;
      //str.sprintf("%.2f",m_spectrum->PointToPPM(m_peaks[i]));
      QPoint points[4];
      points[0].setX(x);
      points[0].setY(rect.top()+0.28*height);
     points[1].setX(x);
      points[1].setY(rect.top()+0.24*height);
     points[02].setX(x1);
      points[2].setY(rect.top()+0.12*height);
     points[3].setX(x1);
      points[3].setY(rect.top()+0.09*height);
     
     p->drawPoints(points,4);



      p->setPen(pen);
      p->save();
      p->translate(x1+m_width/2 ,rect.top()+0.08*height);
      p->rotate(-90);
      p->drawText(0,0,str);
      p->restore();

    }
  }

  delete [] textx;
  p->restore();
}

void PeakPicker::MoveRight(int* text, int pos, int ntexts)
{

  text[pos]+=m_width;

  while(((text[pos]/*+m_width*/)>text[pos+1]) &&(pos < (ntexts-1)))
  {

    text[pos+1]+=m_width;
    pos++;

  }


}

void PeakPicker::MoveLeft(int *text, int pos)
{
  text[pos]-=m_width;

  while(((text[pos-1]/*+m_width*/)>text[pos]) && (pos >0 ))
  {	//if(pos==0)
    text[pos-1]-=m_width;
    pos--;

  }
}

void PeakPicker::OrganizeText(int *text, const QRect &clientrect,int ntexts)
{
  int n=ntexts/2;
  register int i;
  for(i=ntexts-2;i>=n;i--)
  {
    if(text[i]+m_width>text[i+1])
    {
      MoveLeft(text,i);
      MoveRight(text,i+1,ntexts);
    }
  }

  for(i=0;i<ntexts-1;i++)
  {
    if(text[i]+m_width>text[i+1])
    {
      MoveRight(text,i+1,ntexts);
      MoveLeft(text,i);

    }
  }

}

bool PeakPicker::HasPeakAt(const QPoint& point, const QRect& rect)
{}



