/***************************************************************************
**
**  This file is part of SciFigs.
**
**  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)
**
***************************************************************************/

#include "IrregularGrid2DPlot.h"
#include "AxisWindow.h"
#include "XMLSciFigs.h"
#include "GraphContent.h"
#include "GraphContentLayerFactory.h"
#include "LayerPainterRequest.h"
#include "IrregularGrid2DDraw.h"
#include "LayerLocker.h"

namespace SciFigs {

/*!
  \class IrregularGrid2DPlot IrregularGrid2DPlot.h
  \brief A IrregularGrid2DPlot is a layer to plot a 2D grid whose cells have variable widths and heigths

*/

const QString IrregularGrid2DPlot::xmlIrregularGrid2DPlotTag="IrregularGrid2DPlot";

REGISTER_GRAPHCONTENTLAYER(IrregularGrid2DPlot, "IrregularGrid2DPlot")

IrregularGrid2DPlot::IrregularGrid2DPlot(AxisWindow * parent) :
    GridPlot(parent)
{
  TRACE;
  addActions();
}

IrregularGrid2DPlot::~IrregularGrid2DPlot()
{
  TRACE;
}

/*!
  Set current grid.
*/
void IrregularGrid2DPlot::setGrid(const IrregularGrid2D& grid)
{
  TRACE;
  LayerLocker ll(this);
  _grid=grid;
}

/*!
  Adjust palette to grid minimum and maximum
*/
void IrregularGrid2DPlot::setLinearColorMap()
{
  TRACE;
  setLinearColorMap(_grid.minimumValue(), _grid.maximumValue());
}

/*!
  Adjust palette to maximum only
*/
void IrregularGrid2DPlot::setLinearColorMap(double minimum)
{
  TRACE;
  setLinearColorMap(minimum, _grid.maximumValue());
}

void IrregularGrid2DPlot::addActions()
{
  TRACE;
  if(graphContent()) {
    QAction * a=graphContent()->addAction( "ExportGridValues" );
    a->setText(tr("Export values"));
    a->setToolTip(tr("Export grid values into a text file"));
    connect(a, SIGNAL(triggered( bool) ) , this, SLOT(exportValues()) );
  }
}

void IrregularGrid2DPlot::paintData(const LayerPainterRequest& lp, QPainter& p, double) const
{
  TRACE;
  if(_grid.nx()<2 || _grid.ny()<2) return;
  const GraphContentOptions& gc=lp.options();
  IrregularGrid2DDraw d;
  // Get the limit of visible area in terms of grid indexes
  d.setVisibleArea(_grid, gc);
  // Create two int vectors containing the x and y of nodes (centers of blocks)
  d.setCellNodes(_grid, gc);

  if(smooth()) {
    if(showGrid()) d.setCellLimits();
    drawGrid2DSmooth(_grid, colorMap(), lp, p, d);
  } else {
    d.setCellLimits();
    drawGrid2DBlock(_grid, colorMap(), lp, p, d);
  }
  if(showGrid()) {
    drawGridLines(p, d);
  }
}

bool IrregularGrid2DPlot::mouseReleaseEvent (QMouseEvent * e, int)
{
  TRACE;
  if(e->buttons() & Qt::LeftButton) {
    Point2D p=graphContent()->options().s2r2D(e->pos());
    emit clicked(_grid.indexOfX(p.x()), _grid.indexOfY(p.y()) );
  }
  return true;
}

bool IrregularGrid2DPlot::trackRectangle(int, double rx1, double ry1, double rx2, double ry2,
                                             Qt::KeyboardModifiers)
{
  TRACE;
  Rect r(rx1, ry1, rx2, ry2);
  int nx=_grid.nx(), ny=_grid.ny();
  for(int iy=0;iy < ny;iy++ ) {
    for(int ix=0;ix < nx;ix++ ) {
      Point2D p=_grid.coordinates(ix, iy);
      if(r.includes(p, _fillType) )
        * _grid.valuePointer(ix, iy)=_fillValue;
    }
  }
  graphContent()->deepUpdate();
  return true;
}

Rect IrregularGrid2DPlot::boundingRect() const
{
  TRACE;
  Rect r;
  if(_grid.nx()>0 && _grid.ny()>0) {
    r.setLimits(_grid.left(0), _grid.bottom(0),
                _grid.right(_grid.nx() - 1), _grid.top(_grid.ny() - 1) );
  }
  return r;
}

void IrregularGrid2DPlot::exportValues(QString fileName)
{
  TRACE;
  if(fileName.isEmpty()) {
    fileName=Message::getSaveFileName(tr( "Export grid values" ), tr( "All files (*)" ));
  }
  if( !fileName.isEmpty()) {
    QFile f(fileName);
    if(f.open(QIODevice::WriteOnly)) {
      QTextStream s(&f);
      s << _grid;
    } else {
      Message::warning(MSG_ID, tr( "Export grid values" ), tr("Cannot write to file %1").arg(fileName));
    }
  }
}

void IrregularGrid2DPlot::xml_writeChildren(XML_WRITECHILDREN_ARGS) const
{
  TRACE;
  XMLSciFigs * scifigsContext=static_cast<XMLSciFigs *>(context);
  if(scifigsContext->data()) {
    _grid.xml_save(s, context);
  }
  GridPlot::xml_writeChildren(s, context);
}

XMLMember IrregularGrid2DPlot::xml_member(XML_MEMBER_ARGS)
{
  TRACE;
  XMLSciFigs * scifigsContext=static_cast<XMLSciFigs *>(context);
  if(scifigsContext->data()) {
    if(tag=="IrregularGrid2D") return XMLMember(&_grid);
  }
  return GridPlot::xml_member(tag, attributes, context);
}

QString IrregularGrid2DPlot::coordinateTipInfo(const Point2D&, const Point2D& pReal) const
{
  TRACE;
  if(_grid.nx()==0 || _grid.ny()==0) return QString();
  int ix=_grid.indexOfX(pReal.x());
  int iy=_grid.indexOfY(pReal.y());
  static const QString str("(%2 ; %3 ; %1)");
  if(ix>-1 && ix<_grid.nx() && iy>-1 && iy<_grid.ny()) {
    return str.arg(_grid.value(ix, iy), 0, 'g');
  } else {
    return str.arg("NaN");
  }
}

} // namespace SciFigs
