/***************************************************************************
**
**  This file is part of geopsyarray.
**
**  geopsyarray 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.
**
**  geopsyarray 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: 2007-03-27
**  Copyright: 2007-2019
**    Marc Wathelet
**    Marc Wathelet (LGIT, Grenoble, France)
**
***************************************************************************/

#include <GeopsyGui.h>
#include <QGpGuiWave.h>
#include <SciFigs.h>

#include "ActiveFKResults.h"

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

  Full description of class still missing
*/

/*!
  Description of constructor still missing
*/
ActiveFKResults::ActiveFKResults(QWidget * parent)
    : GraphicSheetMenu(parent)
{
  TRACE;
  Settings::getSize(this, "ActiveFKResults");

  // Tools menu
  QMenu * m;
  QAction * a;

  m=addMenu(tr("&Tools"));

  a=new QAction(tr("Stack selected plots"), this);
  a->setStatusTip(tr("Grids of selected plot are stacked and a new plot is added"));
  connect(a, SIGNAL(triggered()), this, SLOT(stackGrids()));
  m->addAction(a);

  m->addSeparator();

  a=new QAction(tr("Pick curves"), this);
  a->setStatusTip(tr("Switch all selected graphs to pick mode (pick ordered)"));
  a->setCheckable(true);
  connect(a, SIGNAL(toggled(bool)), this, SLOT(setPick(bool)));
  m->addAction(a);

  a=new QAction(tr("Auto pick curves"), this);
  a->setStatusTip(tr("Scan grids to find the absolute maximum and start picking from there"));
  connect(a, SIGNAL(triggered()), this, SLOT(autoPick()));
  m->addAction(a);

  a=new QAction(tr("Export all curves"), this);
  a->setStatusTip(tr("Export al curves from all selected plots"));
  connect(a, SIGNAL(triggered()), this, SLOT(exportCurves()));
  m->addAction(a);
}

/*!
  Description of destructor still missing
*/
ActiveFKResults::~ActiveFKResults()
{
  TRACE;
  Settings::setSize(this, "ActiveFKResults");
}

ModalLine * ActiveFKResults::createReferenceLine()
{
  TRACE;
  ModalLine * line=new ModalLine;
  line->setPen(Pen(Qt::black, 0.6));
  line->setSymbol(Symbol(Symbol::Circle, 1.2, Pen(Qt::black, 0.0),
                         Brush(Qt::black, Qt::SolidPattern)));
  return line;
}

void ActiveFKResults::createObjects(ActiveFKToolSet * arrays)
{
  TRACE;
  sheet()->setStatusBar(GeopsyGuiEngine::instance()->statusBar());
  int n=arrays->sources().count();
  double x=0.5, y=0.5;
  _gridLayers.resize(n);
  _curveLayers.resize(n);
  _limitLayers.resize(n);
  for(int ig=0; ig<n; ig++) {
    AxisWindow * w=sheet()->addGraph();
    w->setGeometry(x, y+0.5, 9, 9);
    TextEdit * c=sheet()->addText();
    c->setGeometry(x, y, 9, 1);
    c->setText(arrays->sources().at(ig)->source()->name());
    x+=9;
    if(x==18.5) {x=0.5;y += 10;}
    _gridLayers[ig]=new IrregularGrid2DPlot(w);
    _curveLayers[ig]=new LineLayer(w);
    _limitLayers[ig]=new DispersionLimitLayer(w);
    _curveLayers[ig]->setReferenceLine(createReferenceLine());
    _limitLayers[ig]->addLine();
  }
}

void ActiveFKResults::setXAxis(const SamplingParameters& s)
{
  TRACE;
  int n=_gridLayers.count();
  for(int ig=0;ig < n;ig++) {
    AxisWindow * w=_gridLayers[ig]->graph();
    if(s.type()==SamplingParameters::Linear) {
      w->xAxis()->setScaleType(Scale::Linear);
    } else {
      w->xAxis()->setScaleType(Scale::Log);
    }
    w->xAxis()->setRange(s.minimum(), s.maximum());
    _limitLayers[ig]->setFrequencySampling(s);
    w->updateInternalGeometry();
    w->deepUpdate();
  }
}

void ActiveFKResults::setYAxis(Scale::Type t, double min, double max)
{
  TRACE;
  int n=_gridLayers.count();
  for(int ig=0;ig < n;ig++) {
    AxisWindow * w=_gridLayers[ig]->graph();
    w->yAxis()->setScaleType(t);
    w->yAxis()->setRange(min, max);
    w->updateInternalGeometry();
    w->deepUpdate();
  }
}

void ActiveFKResults::setWaveLengthLimit(int ig, double wl)
{
  TRACE;
  _limitLayers[ig]->setConstantWaveNumber(0, 2.0*M_PI/wl);
  _limitLayers[ig]->graph()->deepUpdate();
}

bool ActiveFKResults::selectAll(QString title)
{
  int n=_gridLayers.count();
  for(int ig=0;ig < n;ig++) {
    if(_curveLayers[ ig ]->graph()->isSelected()) {
      return true;
    }
  }
  return _sheet.selectAll(title);
}

void ActiveFKResults::setPick(bool on)
{
  TRACE;
  int n=_gridLayers.count();
  for(int ig=0;ig < n;ig++) {
    if(_curveLayers[ ig ]->graph()->isSelected()) {
      _curveLayers[ig]->setTrackingAction(LineLayer::PickOrdered, on);
    }
  }
}

void ActiveFKResults::autoPick()
{
  TRACE;
  if(!selectAll(tr("Automatic picking"))) return;
  int n=_gridLayers.count();
  for(int ig=0; ig<n; ig++) {
    if(_curveLayers[ig]->graph()->isSelected()) {
      ModalLine * line=static_cast<ModalLine *>(_curveLayers[ig]->addLine());
      emit newCurve(ig, line);
      ModalCurve& curve=line->curve();
      curve=_gridLayers[ig]->grid().followMaximumX<ModalCurve, FactoryPoint>();
      _curveLayers[ig]->deepUpdate();
    }
  }
}

void ActiveFKResults::adjust(int ig, ModalCurve& curve, double min, double max, SamplingOptions options)
{
  TRACE;
  // Transforms X scale according to options (log and inv)
  if(options & InversedScale) {
    curve.xInverse();
  }
  curve.sort();
  _gridLayers[ig]->grid().followMaximumX<ModalCurve, FactoryPoint>(curve, min, max);
  // Re-Transforms axis according options (log and inv)
  if(options & InversedScale)
    curve.xInverse();
}

void ActiveFKResults::exportCurves()
{
  TRACE;
  if(!selectAll(tr("Export all curves"))) return;
  QString fileName=Message::getSaveFileName(tr("Export all curves"), tr("4 columns file(*)"));
  if(!fileName.isEmpty()) {
    QFile f(fileName);
    if(!f.open(QIODevice::WriteOnly)) {
      Message::warning(MSG_ID, tr("Export all curves"),
                       tr("Cannot to write to file %1").arg(fileName), Message::cancel());
      return ;
    }
    QTextStream s(&f);
    int n=_gridLayers.count();
    DispersionProxy proxy;
    for(int ig=0;ig < n;ig++) {
      LineLayer * curveLayer=_curveLayers[ig];
      if(curveLayer->graph()->isSelected()) {
        int n=curveLayer->count();
        s << "# Shot " << ig << endl;
        for(int i=0;i<n;i++) {
          proxy.setCurve(&static_cast<ModalLine *>(curveLayer->line(i))->curve());
          proxy.save(s);
        }
      }
    }
  }
}

void ActiveFKResults::stackGrids()
{
  TRACE;
  if(!selectAll(tr("Stack grids"))) return;
  IrregularGrid2D stackedGrid;
  int nStacks=0;
  int n=_gridLayers.count();
  for(int ig=0;ig < n;ig++) {
    IrregularGrid2DPlot * gridLayer=_gridLayers[ig];
    if(gridLayer->graph()->isSelected()) {
      if(nStacks==0) {
        stackedGrid=gridLayer->grid();
        nStacks++;
      } else {
        stackedGrid += gridLayer->grid();
        nStacks++;
      }
    }
  }
  // Add plot
  if(nStacks>0) {
    double x=0.5 + 9 * (n % 2), y=0.5 + (n/2) * 10;
    AxisWindow * w=sheet()->addGraph();
    w->setGeometry(x, y+1, 9, 9);
    IrregularGrid2DPlot * gridLayer=new IrregularGrid2DPlot(w);
    _gridLayers.append(gridLayer);
    LineLayer * curveLayer=new LineLayer(w);
    curveLayer->setReferenceLine(createReferenceLine());
    _curveLayers.append(curveLayer);
    gridLayer->setGrid(stackedGrid);
    gridLayer->setLinearColorMap(0);
    DispersionLimitLayer * dispLimitLayer=new DispersionLimitLayer(w);
    dispLimitLayer->addLine();
    _limitLayers.append(dispLimitLayer);
    // Add text label
    TextEdit * c=sheet()->addText();
    c->setGeometry(x, y, 9, 1);
    c->setText(tr("Stack of %1 grids").arg(nStacks));
    c->deepUpdate();
    // Copy axis range and scale from last plot
    AxisWindow * w1=_gridLayers[n-1]->graph();
    emit newPlot(curveLayer, c->text());
    w->xAxis()->setScaleType(w1->xAxis()->scaleType());
    w->yAxis()->setScaleType(w1->yAxis()->scaleType());
    w->xAxis()->setRange(w1->xAxis()->minimum(), w1->xAxis()->maximum());
    w->yAxis()->setRange(w1->yAxis()->minimum(), w1->yAxis()->maximum());
    w->updateInternalGeometry();
  }
}
