/***************************************************************************
**
**  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: 2003-01-14
**  Copyright: 2003-2019
**    Marc Wathelet
**    Marc Wathelet (ULg, Liège, Belgium)
**    Marc Wathelet (LGIT, Grenoble, France)
**
***************************************************************************/

#ifndef IrregularGrid2D_H
#define IrregularGrid2D_H

#include "IrregularGrid2DData.h"
#include "GridSearch.h"

namespace QGpCoreMath {

class QGPCOREMATH_EXPORT IrregularGrid2D : public XMLClass
{
  TRANSLATIONS("IrregularGrid2D")
public:
  IrregularGrid2D() {_d=new IrregularGrid2DData;}
  IrregularGrid2D(int nx, int ny) {_d=new IrregularGrid2DData(nx, ny);}

  virtual const QString& xml_tagName() const {return xmlIrregularGrid2DTag;}
  static const QString xmlIrregularGrid2DTag;

  void operator+=(const IrregularGrid2D& o) {_d->operator+=( *o._d);}
  void copy(const GridSearch& o, AxisType normalTo=ZAxis, double at=0.0) {_d->copy(o, normalTo, at);}

  int nx() const {return _d->nx();}
  int ny() const {return _d->ny();}
  void clear() {_d->clear();}
  void init(int nx, int ny) {_d->init(nx, ny);}
  void init(int nx, int ny, double value) {_d->init(nx, ny, value);}
  void init(double value=0.0)  {_d->init(value);}
  bool isLike(IrregularGrid2D& o) const {return _d->isLike( *o._d);}
  // Function to set _x and _y values
  void setLinear(AxisType axis, double min, double max) {_d->setLinear(axis, min, max);}
  void setLog(AxisType axis, double min, double max) {_d->setLog(axis, min, max);}
  // Resample the grid at x defined by xModel (e.g. from another curve)
  void resample(AxisType axis, const QVector<double>& xModel) {_d->resample(axis, xModel);}
  void resample(AxisType axis, int n, double min, double max, SamplingOptions options) {_d->resample(axis, n, min, max, options);}
  // Cut function between two x values
  void cut(AxisType axis, double min, double max, SamplingOptions options) {_d->cut(axis, min, max, options);}
  void inverse(AxisType axis) {_d->inverse(axis);}
  void log10(AxisType axis) {_d->log10(axis);}
  void log10() {_d->log10();}
  void pow10(AxisType axis) {_d->pow10(axis);}
  void pow10() {_d->pow10();}
  void multiplyCoordinates(AxisType axis, double fac) {_d->multiplyCoordinates(axis, fac);}
  void multiplyValues(AxisType along, int index, double fac) {_d->multiplyValues(along, index, fac);}
  void multiplyValues(double fac) {_d->multiplyValues(fac);}
  const double * axisData(AxisType axis) const {return _d->axisData(axis);}
  // Function to acces the grid
  double value(int ix, int iy) const {return _d->value(ix, iy);}
  void setValue(int ix, int iy, double val) {return _d->setValue(ix, iy, val);}
  double * valuePointer(int ix, int iy) {return _d->valuePointer(ix, iy);}
  const double * valuePointer(int ix, int iy) const {return _d->valuePointer(ix, iy);}
  QVector<double> x() const {return _d->x();}
  QVector<double> y() const {return _d->y();}
  double x(int ix) const {return _d->x(ix);}
  double y(int iy) const {return _d->y(iy);}
  void setX(int ix, double val) {_d->setX(ix,val);}
  void setY(int iy, double val) {_d->setY(iy,val);}
  inline Point2D coordinates(int ix, int iy) const {return _d->coordinates(ix, iy);}
  double minimumValue() const {return _d->minimumValue();}
  double maximumValue() const {return _d->maximumValue();}
  double minimumValue(int& ix, int& iy) const {return _d->minimumValue(ix, iy);}
  double maximumValue(int& ix, int& iy) const {return _d->maximumValue(ix, iy);}
  double minimumAxis(AxisType axis) const {return _d->minimumAxis(axis);}
  double maximumAxis(AxisType axis) const {return _d->maximumAxis(axis);}
  double maximumValue(AxisType along, int index) const {return _d->maximumValue(along, index);}
  double minimumValue(AxisType along, int index) const {return _d->minimumValue(along, index);}
  double sum(AxisType along, int index) const {return _d->sum(along, index);}
  double mean(AxisType along, int index) const {return _d->mean(along, index);}
  double median(AxisType along, int index) const {return _d->median(along, index);}
  double mode(AxisType along, int index) const {return _d->mode(along, index);}
  double variance(AxisType along, int index) const {return _d->variance(along, index);}
  double variance(AxisType along, int index, double average) const {return _d->variance(along, index, average);}
  double varianceFit(AxisType along, int index, double average) const {return _d->varianceFit(along, index, average);}
  double misfit(AxisType along, int index, const GaussDistribution& gd) const {return _d->misfit(along, index, gd);}
  double normalizeArea(AxisType along, int index) {return _d->normalizeArea(along, index);}
  void normalizeArea(AxisType along) {_d->normalizeArea(along);}
  double normalizeAmplitude(AxisType along, int index) {return _d->normalizeAmplitude(along, index);}
  void normalizeAmplitude(AxisType along) {_d->normalizeAmplitude(along);}
  void smooth(AxisType along) {_d->smooth(along);}
  void smooth(AxisType along, int index) {_d->smooth(along, index);}
  double smoothInvalidCells(AxisType along, int index,
                            double invalidValue, double sigma2,
                            double RVal, bool modify) {return _d->smoothInvalidCells(along, index, invalidValue, sigma2, RVal, modify);}
  void printValues(AxisType along, int index) {_d->printValues(along, index);}

  int indexOfX(double val) const {return _d->indexOfX(val);}
  int indexOfY(double val) const {return _d->indexOfY(val);}
  bool belongs(const Point2D& p, int ix, int iy) const {return _d->belongs(p, ix, iy);}
  /* Get values of a row or a column of the grid as a Curve object
      Return a row if along X_Axis, a column if along Y_Axis **/
  Curve<Point2D> crossSection(AxisType axis, int ixy) const {return _d->crossSection(axis, ixy);}
  Curve<Point2D> crossSection(Segment2D seg, double deltaX=0) const {return _d->crossSection(seg, deltaX);}
  Curve<Point2D> crossSection(const Curve<Point2D>& path, double deltaX=0) const {return _d->crossSection(path, deltaX);}
  Curve<Point2D> integralCrossSection(AxisType axis,int index) const {
     return _d->integralCrossSection(axis, index);
  }
  template <class CurveClass, class PointClass> CurveClass followMaximumX() const {
    return _d->followMaximumX<CurveClass, PointClass>();
  }
  template <class CurveClass, class PointClass> CurveClass followMaximumX(int ixMin, int ixMax, int iyMax) const {
    return _d->followMaximumX<CurveClass, PointClass>(ixMin, ixMax, iyMax);
  }
  template <class CurveClass, class PointClass> void followMaximumX(CurveClass& curve, double min, double max) const {
    return _d->followMaximumX<CurveClass, PointClass>(curve, min, max);
  }
  template <class CurveClass, class PointClass> CurveClass followMaximumY() const {
    return _d->followMaximumY<CurveClass, PointClass>();
  }
  template <class CurveClass, class PointClass> CurveClass followMaximumY(int iyMin, int iyMax, int ixMax) const {
    return _d->followMaximumY<CurveClass, PointClass>(iyMin, iyMax, ixMax);
  }
  template <class CurveClass, class PointClass> void followMaximumY(CurveClass& curve, double min, double max) const {
    return _d->followMaximumY<CurveClass, PointClass>(curve, min, max);
  }
  // Geometries of cells
  double width(int ix) const {return _d->width(ix);}
  double height(int iy) const {return _d->height(iy);}
  double left(int ix) const {return _d->left(ix);}
  double right(int ix) const {return _d->right(ix);}
  double bottom(int iy) const {return _d->bottom(iy);}
  double top(int iy) const {return _d->top(iy);}
protected:
  virtual void xml_writeProperties(XML_WRITEPROPERTIES_ARGS) const;
  virtual bool xml_setProperty(XML_SETPROPERTY_ARGS);
  virtual XMLMember xml_member(XML_MEMBER_ARGS);
  virtual void xml_writeBinaryData(XML_WRITEBINARYDATA_ARGS) const;
  virtual bool xml_setBinaryData(XML_SETBINARYDATA_ARGS);
  virtual bool xml_setBinaryData200411(XML_SETBINARYDATA_ARGS);
private:
  QSharedDataPointer<IrregularGrid2DData> _d;
};

QGPCOREMATH_EXPORT QTextStream& operator>>(QTextStream& s, IrregularGrid2D& grd);
QGPCOREMATH_EXPORT QTextStream& operator<<(QTextStream& s, const IrregularGrid2D& grd);

} // namespace QGpCoreMath

#endif // IRREGULARGRID2D.H
