/***************************************************************************
**
**  This file is part of gpviewmax.
**
**  gpviewmax 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.
**
**  gpviewmax 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: 2018-07-16
**  Copyright: 2018-2019
**    Marc Wathelet (ISTerre, Grenoble, France)
**
***************************************************************************/

#include <QGpGuiWave.h>

#include "ModeWidgets.h"

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

  Full description of class still missing
*/

/*!
  Description of constructor still missing
*/
ModeWidgets::ModeWidgets(QObject * parent)
  : QObject(parent)
{
  TRACE;
  _dispersion=nullptr;
  _ellipticity=nullptr;
  _noise=nullptr;
  _azimuth=nullptr;
  _power=nullptr;
}

/*!
  Description of destructor still missing
*/
ModeWidgets::~ModeWidgets()
{
  TRACE;
}

void ModeWidgets::setHistogram(IrregularGrid2DPlot * layer, Histogram2D * hist, bool normalized)
{
  TRACE;
  if(hist) {
    if(normalized) {
      hist->normalizeArea(YAxis);
    }
    layer->setGrid(*hist);
    if(!hist->xTitle().isNull()) {
      layer->graph()->xAxis()->setTitle(hist->xTitle());
    }
    if(!hist->yTitle().isNull()) {
      layer->graph()->yAxis()->setTitle(hist->yTitle());
    }
    if(!hist->yTitleInversedScale().isNull()) {
      layer->graph()->yAxis()->setTitleInversedScale(hist->yTitleInversedScale());
    }
    layer->graph()->xAxis()->setScaleType(hist->xScaleType());
    layer->graph()->yAxis()->setScaleType(hist->yScaleType());
    delete hist;
  }
}

void ModeWidgets::setComments(const QString &cmt)
{
  TRACE;
  if(_dispersion) _dispersion->setComments(cmt);
  if(_ellipticity) _ellipticity->setComments(cmt);
  if(_noise) _noise->setComments(cmt);
  if(_azimuth) _azimuth->setComments(cmt);
  if(_power) _power->setComments(cmt);
}

void ModeWidgets::setSamples(const Samples& s, const Reader& param)
{
  TRACE;
  if(_dispersion) setHistogram(_dispersion, dispersionHistogram(s, param), param.isNormalized());
  if(_ellipticity) setHistogram(_ellipticity, ellipticityHistogram(s, param), param.isNormalized());
  if(_noise) setHistogram(_noise, noiseHistogram(s, param), param.isNormalized());
  if(_azimuth) setHistogram(_azimuth, azimuthHistogram(s, param), param.isNormalized());
  if(_power) setHistogram(_power, powerHistogram(s, param), param.isNormalized());
}

void ModeWidgets::addWidgets(GraphicSheet * sheet, const Reader& param)
{
  TRACE;
  AxisWindow * w;
  ColorMap map;
  double width=8.0;
  double rightPos=0.5+9.5*(sheet->objects().count()/5+1);
  double topPos=0.5;
  map.generateColorScale(20, ColorPalette::McNamesClip, true);
  map.setWhiteTransparent(true);

  if(param.showPlots() & Reader::Dispersion) {
    w=new AxisWindow(sheet);
    w->setObjectName(_name+"Dispersion");
    sheet->addObject(w);
    w->setAnchor(AxisWindow::TopRight);
    w->xAxis()->setSizeType(Axis::AxisSize);
    w->xAxis()->setSizeInfo(width);
    w->yAxis()->setSizeInfo(7.0);
    w->setPrintRight(rightPos);
    w->setPrintTop(topPos);
    _dispersion=new IrregularGrid2DPlot(w);
    _dispersion->setSmooth(false);
    _dispersion->setColorMap(map);
    if(!param.referenceDispersionLayer().isEmpty()) {
      w->graphContent()->appendLayers(param.referenceDispersionLayer());
    }
    w->updateExternalGeometry();
    sheet->showObject(w);
    topPos+=7.0;
  }

  if(param.showPlots() & Reader::Ellipticity) {
    w=new AxisWindow(sheet);
    w->setObjectName(_name+"Ellipticity");
    sheet->addObject(w);
    w->setAnchor(AxisWindow::TopRight);
    w->xAxis()->setSizeType(Axis::AxisSize);
    w->xAxis()->setSizeInfo(width);
    w->yAxis()->setSizeInfo(7.0);
    w->setPrintRight(rightPos);
    w->setPrintTop(topPos);
    _ellipticity=new IrregularGrid2DPlot(w);
    _ellipticity->setSmooth(false);
    _ellipticity->setColorMap(map);
    if(!param.referenceEllipticityLayer().isEmpty()) {
      w->graphContent()->appendLayers(param.referenceEllipticityLayer());
    }
    w->updateExternalGeometry();
    sheet->showObject(w);
    topPos+=7.0;
  }

  if(param.showPlots() & Reader::Noise) {
    w=new AxisWindow(sheet);
    w->setObjectName(_name+"Noise");
    sheet->addObject(w);
    w->setAnchor(AxisWindow::TopRight);
    w->xAxis()->setSizeType(Axis::AxisSize);
    w->xAxis()->setSizeInfo(width);
    w->yAxis()->setNumberType('e');
    w->yAxis()->setSizeInfo(4.0);
    w->setPrintRight(rightPos);
    w->setPrintTop(topPos);
    _noise=new IrregularGrid2DPlot(w);
    _noise->setSmooth(false);
    _noise->setColorMap(map);
    w->updateExternalGeometry();
    sheet->showObject(w);
    topPos+=4.0;
  }

  if(param.showPlots() & Reader::Azimuth) {
    w=new AxisWindow(sheet);
    w->setObjectName(_name+"Azimuth");
    sheet->addObject(w);
    w->setAnchor(AxisWindow::TopRight);
    w->xAxis()->setSizeType(Axis::AxisSize);
    w->xAxis()->setSizeInfo(width);
    w->yAxis()->setSizeInfo(7.0);
    w->setPrintRight(rightPos);
    w->setPrintTop(topPos);
    _azimuth=new IrregularGrid2DPlot(w);
    _azimuth->setSmooth(false);
    _azimuth->setColorMap(map);
    w->updateExternalGeometry();
    sheet->showObject(w);
    topPos+=7.0;
  }

  if(param.showPlots() & Reader::Power) {
    w=new AxisWindow(sheet);
    w->setObjectName(_name+"Power");
    sheet->addObject(w);
    w->setAnchor(AxisWindow::TopRight);
    w->xAxis()->setSizeType(Axis::AxisSize);
    w->xAxis()->setSizeInfo(width);
    w->yAxis()->setNumberType('e');
    w->yAxis()->setSizeInfo(7.0);
    w->setPrintRight(rightPos);
    w->setPrintTop(topPos);
    _power=new IrregularGrid2DPlot(w);
    _power->setSmooth(false);
    _power->setColorMap(map);
    w->updateExternalGeometry();
    sheet->showObject(w);
  }
}

Histogram2D * ModeWidgets::histogram(const Reader& param, const SamplingParameters& y)
{
  TRACE;
  Histogram2D * h;
  static const QString msg=tr("X axis from %1 to %2 with %3 bins\n");
  if(param.xSampling()) {
     h=new Histogram2D(param.xSampling()->count(), y.count());
     App::log(msg.arg(param.xSampling()->minimum())
                 .arg(param.xSampling()->maximum())
                 .arg(param.xSampling()->count()));
     if(!h->setXSampling(*param.xSampling())) {
       delete h;
       return nullptr;
     }
  } else {
    h=new Histogram2D(param.xValues().count(), y.count());
    App::log(msg.arg(param.xValues().first())
                .arg(param.xValues().last())
                .arg(param.xValues().count()));
    if(!h->setXSampling(param.xValues())) {
      delete h;
      return nullptr;
    }
  }
  if(param.xLogSampling()) {
    h->setXScaleType(Scale::Log);
  } else {
    h->setXScaleType(Scale::Linear);
  }
  h->setXTitle(tr("Frequency (Hz)"));
  App::log(tr("Y axis from %1 to %2 with %3 bins\n")
           .arg(y.minimum())
           .arg(y.maximum())
           .arg(y.count()));
  if(!y.isValid() || !h->setYSampling(y)) {
    delete h;
    return nullptr;
  }
  return h;
}

Histogram2D * ModeWidgets::dispersionHistogram(const Samples& s, const Reader& param)
{
  TRACE;
  App::log(tr("Dispersion histogram\n"));
  Histogram2D * h=histogram(param, param.dispersionSampling());
  if(!h) {
    return nullptr;
  }
  // TODO support alternative ways of plotting dipsersion (same for ellipticity)
  h->setYTitle(param.dispersionTitle());
  h->setYTitleInversedScale(tr("Velocity (m/s)"));
  h->setYScaleType(Scale::InversedLog);
  h->setSamples(s.dispersionSamples());
  return h;
}

Histogram2D * ModeWidgets::ellipticityHistogram(const Samples& s, const Reader& param)
{
  TRACE;
  App::log(tr("Ellipticity histogram\n"));
  Histogram2D * h=histogram(param, param.ellipticitySampling());
  if(!h) {
    return nullptr;
  }
  h->setYTitle(param.ellipticityTitle());
  h->setYScaleType(Scale::Linear);
  h->setSamples(s.ellipticitySamples());
  return h;
}

Histogram2D * ModeWidgets::noiseHistogram(const Samples& s, const Reader& param)
{
  TRACE;
  App::log(tr("Noise histogram\n"));
  Histogram2D * h=histogram(param, param.noiseSampling());
  if(!h) {
    return nullptr;
  }
  h->setYTitle(param.noiseTitle());
  h->setYScaleType(Scale::Log);
  h->setSamples(s.noiseSamples());
  return h;
}

Histogram2D * ModeWidgets::azimuthHistogram(const Samples& s, const Reader& param)
{
  TRACE;
  App::log(tr("Azimuth histogram\n"));
  Histogram2D * h=histogram(param, param.azimuthSampling());
  if(!h) {
    return nullptr;
  }
  h->setYTitle(param.azimuthTitle());
  h->setYScaleType(Scale::Linear);
  h->setSamples(s.azimuthSamples());
  return h;
}

Histogram2D * ModeWidgets::powerHistogram(const Samples& s, const Reader& param)
{
  TRACE;
  App::log(tr("Power histogram\n"));
  Histogram2D * h=histogram(param, param.powerSampling());
  if(!h) {
    return nullptr;
  }
  h->setYTitle(param.powerTitle());
  h->setYScaleType(Scale::Log);
  h->setSamples(s.powerSamples());
  return h;
}

void ModeWidgets::setLimits(bool normalize)
{
  TRACE;
  if(_dispersion) setLimits(_dispersion, normalize);
  if(_ellipticity) setLimits(_ellipticity, normalize);
  if(_noise) setLimits(_noise, normalize);
  if(_azimuth) setLimits(_azimuth, normalize);
  if(_power) setLimits(_power, normalize);
}

void ModeWidgets::setLimits(IrregularGrid2DPlot * layer, bool normalize)
{
  TRACE;
  GraphContent * gc=layer->graphContent();
  AxisWindow * w=gc->graph();
  Rect r=layer->boundingRect();
  r.enlarge(0.01, gc->scaleX().sampling(), gc->scaleY().sampling());
  w->xAxis()->setRange(r.x1(), r.x2());
  w->yAxis()->setRange(r.y1(), r.y2());

  ColorMap pal=layer->colorMap();
  double m=layer->grid().maximumValue();
  if(normalize) {
    pal.setVLog(0.0001*m, m);
  } else {
    pal.generateColorScale(qRound(m+1.0), ColorPalette::McNamesClip, true);
    pal.setVLinear(0.5, m-0.5);
  }
  layer->setColorMap(pal);
  w->updateGeometry(); // TopRight anchor imply that position can change when changing axis limits
}

void ModeWidgets::setColorMap(const ColorMap& map)
{
  if(_dispersion) _dispersion->setColorMap(map);
  if(_ellipticity) _ellipticity->setColorMap(map);
  if(_noise) _noise->setColorMap(map);
  if(_azimuth) _azimuth->setColorMap(map);
  if(_power) _power->setColorMap(map);
}
