/***************************************************************************
**
**  This file is part of QGpCompatibility.
**
**  QGpCompatibility 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 3 of the License, or
**  (at your option) any later version.
**
**  QGpCompatibility 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 Foobar.  If not, see <http://www.gnu.org/licenses/>
**
**  See http://www.geopsy.org for more information.
**
**  Created: 2002-10-15
**  Copyright: 2002-2019
**    Marc Wathelet
**    Marc Wathelet (ULg, Liège, Belgium)
**    Marc Wathelet (LGIT, Grenoble, France)
**
***************************************************************************/

#ifndef COMPATFunction_H
#define COMPATFunction_H

#include <QGpCoreMath.h>

#include "CompatDataPoint.h"

#include "QGpCompatibilityDLLExport.h"

namespace QGpCompatibility {

class QGPCOMPATIBILITY_EXPORT CompatFunctionPoint : public CompatDataPoint
{
public:
  CompatFunctionPoint(double x, double y, double yErr, double weight)
    : CompatDataPoint(y, yErr, weight), _x(x) {}

  bool operator<(const CompatFunctionPoint& o) const {return _x<o._x;}
  bool operator==(const CompatFunctionPoint& o) const {return _x==o._x;}

  double& x() {return _x;}
  const double& x() const {return _x;}
private:
  double _x;
};

class QGPCOMPATIBILITY_EXPORT CompatFunction
{
  TRANSLATIONS("CompatFunction");
public:
  CompatFunction();
  CompatFunction(QVector<double> * x, QVector<double> * y, QVector<double> * dy);
  CompatFunction(QVector<Point>& f);
  ~CompatFunction();

  void line(double x1, double y1, double x2, double y2);
  int size() {return _x ? _x->size() : 0;}
  void setX(QVector<double> * x);
  void setY(QVector<double> * y);
  void setYErr(QVector<double> * dy);
  void setWeight(QVector<double> * w);
  void set(QVector<Point>& f);
  void addPoint(int atIndex, double x, double y, double z);
QVector<double> * x() {return _x;}
  QVector<double> * y() {return _y;}
  QVector<double> * yErr() {return _yErr;}
  QVector<double> * weight() {return _weight;}
  double y(double x) {return interpole(x, find(x, _x), _x, _y);}
  void sort();
  void deleteVectors();
  void resample_ds(int n, double min, double max, bool isLog, bool isInv,
                    double valX, double valY);
  void resample(int n, double min, double max, bool isLog, bool isInv, double invalid_value=0);
  void resample(QVector<double> * xModel, double invalid_value, bool doInterpole);
  void resample(QVector<Point>& xModel, double invalid_value, bool doInterpole);
  void cut (double min, double max, bool isInv);
  void removeInvalidValues(double invalidValue);
  double minX();
  double maxX();
  int minYAt();
  int maxYAt();
  double minY();
  double maxY();
  void resize(int n, bool removeLast=true);

  void log10();
  void exp10();
  void inverseX();
  void inverseY(double invalidValue);
  void inverseYErr();
  void log10Y(double invalidValue);
  void log10YErr();
  double fitFactor(double x, double val);
  double fitFactor(int index, double val);
  void getModes(QVector<double>& mean, QVector<double>& stddev);
  int closestMax(int starti);
  void multiplyX(double value);
  void multiplyXbyY();
  // Apply to partition statistical functions
  double average();
  double stddev(double average);
protected:
  QVector<double> * _x;
  QVector<double> * _y;
  QVector<double> * _yErr;
  QVector<double> * _weight;
  /*
     This flag is set to false whenever one of the three vector is changed 
     by set(). All operation on CompatFunction are blocked while this flag is false
     Call sort() to enable them
  */
  bool _isSorted;
  // Minimum power of 2 greater than the size of _x, otpimisation of find()
  int _n2;
  int find(double val, QVector<double> * inVector);
  double interpole(double val, int indexInVector,
                    QVector<double> * inVector,
                    QVector<double> * outVector);
};

} // namespace QGpCompatibility

#endif // COMPATFUNCTION_H
