/***************************************************************************
**
**  This file is part of QGpCoreMath.
**
**  This library is free software; you can redistribute it and/or
**  modify it under the terms of the GNU Lesser General Public
**  License as published by the Free Software Foundation; either
**  version 2.1 of the License, or (at your option) any later version.
**
**  This file 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 Lesser General Public
**  License for more details.
**
**  You should have received a copy of the GNU Lesser General Public
**  License along with this library; if not, write to the Free Software
**  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
**
**  See http://www.geopsy.org for more information.
**
**  Created: 2007-11-12
**  Copyright: 2007-2019
**    Marc Wathelet
**    Marc Wathelet (LGIT, Grenoble, France)
**
***************************************************************************/

#include "FunctionSearch.h"
#include "AbstractFunction.h"

namespace QGpCoreMath {

double FunctionSearchMaximum::relativePrecision=1e-5;
double FunctionSearchMaximum::relativePrecision2=1e-10;

/*!
  \class FunctionSearch FunctionSearch.h
  \brief Brief description of class still missing

  Full description of class still missing
*/

/*!
  Description of constructor still missing
*/
FunctionSearch::FunctionSearch()
{
  TRACE;
  for(int i=0; i<3; i++) {
    _relative[i]=true;
    _precision[i]=0.001;
  }
  _function=nullptr;
}

/*!
  Delete current function. To prevent automatic deletion, call takeFunction() before.
*/
FunctionSearch::~FunctionSearch()
{
  TRACE;
  delete _function;
  qDeleteAll(_maxima);
}

/*!
  Set current function. Ownership is transfered to this object. To get it back you must
  call takeFunction().
*/
void FunctionSearch::setFunction(AbstractFunction * f)
{
  TRACE;
  delete _function;
  _function=f;
}

/*!
  Take ownership of the function object
*/
AbstractFunction * FunctionSearch::takeFunction()
{
  TRACE;
  AbstractFunction * f=_function;
  _function=nullptr;
  return f;
}

void FunctionSearch::globalMax(double absThres)
{
  TRACE;
  ASSERT(_maxima.count()==1);
  if(_maxima.first()->value()<absThres) {
    delete _maxima.takeLast();
  }
}

void FunctionSearch::localMax(int nMax, double absThres, double relThres)
{
  TRACE;
  std::sort(_maxima.begin(), _maxima.end(), FunctionSearchMaximum::greaterThanValue);
  // filter the ensemble of maxima
  // With an absolute value for the maximum
  if(absThres>0.0) {
    int i=_maxima.count()-1;
    while(i>=0 && _maxima.at(i)->value()<absThres) {
      delete _maxima.takeLast();
      i--;
    }
  }
  // With a value for the maximum defined as a ratio of the global max
  if(relThres>0.0 && _maxima.count()>0) {
    absThres=_maxima.at(0)->value()*relThres*0.01;
    int i=_maxima.count()-1;
    while(i>=0 && _maxima.at(i)->value()<absThres) {
      delete _maxima.takeLast();
      i--;
    }
  }
  // Remove all maxima exceeding nMax
  while(_maxima.count()>nMax) {
    delete _maxima.takeLast();
  }
}

/*!
  Remove all solutions that are too close.
*/
void FunctionSearch::unique()
{
  TRACE;
  std::sort(_maxima.begin(), _maxima.end(), FunctionSearchMaximum::lessThanPos);
  QGpCoreTools::unique(_maxima, FunctionSearchMaximum::equalPos);
}

void FunctionSearch::clearMaxima()
{
  TRACE;
  qDeleteAll(_maxima);
  _maxima.clear();
}

void FunctionSearch::debugScan(const Point& min, const Point& max, int n)
{
  Point d=max;
  d-=min;
  d/=n;
  Point p;
  for(int ix=0; ix<=n; ix++) {
    for(int iy=0; iy<=n; iy++) {
      p.setX(min.x()+d.x()*ix);
      p.setY(min.y()+d.y()*iy);
      if(d.z()==0.0) {
        printf("%10.5lf %10.5lf %lg\n", p.x(), p.y(), value(p));
      } else {
        for(int iz=0; iz<=n; iz++) {
          p.setZ(min.z()+d.z()*iz);
          printf("%10.5lf %10.5lf %10.5lf %lg\n", p.x(), p.y(), p.z(), value(p));
        }
      }
    }
  }
}

} // namespace QGpCoreMath
