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

#include <GeopsyCore.h>
#include <GeopsyGui.h>
#include <QGpGuiTools.h>
#include <SciFigs.h>
#include "TFAResults.h"
#include "TFAParameters.h"

TFAResults::TFAResults(QWidget *parent) :
    GraphicSheetMenu(parent)
{
  TRACE;
  Settings::getSize(this, "TFAResults" );
}

TFAResults::~TFAResults()
{
  TRACE;
  Settings::setSize(this, "TFAResults");
}

void TFAResults::createObjects(const SubSignalPool * subPool)
{
  TRACE;
  sheet()->setStatusBar(GeopsyGuiEngine::instance()->statusBar());
  int n=subPool->count();
  double y=1.0;
  _gridLayers.resize(n);
  for(int ig=0;ig < n;ig++ ) {
    AxisWindow * w=sheet()->addGraph();
    Signal * sig=subPool->at(ig);
    w->xAxis()->setTitle( "Time (s)" );
    w->xAxis()->setTitleInversedScale( "1/Time (1/s)" );
    w->yAxis()->setTitle( "Frequency (Hz)" );
    w->yAxis()->setTitleInversedScale( "Period (s)" );
    w->yAxis()->setScaleType(Scale::Log);
    _gridLayers[ig]=new IrregularGrid2DPlot(w);
    w->setGeometry(1.0, y, 15.0, 8.0);
    TextEdit * t=sheet()->addText();
    t->setGeometry(16.0, y, 4.0, 5.0);
    t->setAnchor(GraphicObject::BottomRight);
    t->setPrintXAnchor(16.0);
    t->setPrintYAnchor(y);
    t->setText(sig->nameComponent());
    t->updateGeometry();
    ColorMapWidget * p=new ColorMapWidget;
    p->setAnchor(GraphicObject::TopLeft);
    p->setPrintXAnchor(16.25);
    p->setPrintYAnchor(y+0.5);
    p->setOrientation(Axis::West);
    p->setPrintWidth(1.8);
    p->setPrintHeight(6.0);
    p->setTitle(tr("Amplitude"));
    connect(_gridLayers[ig], SIGNAL(colorMapChanged(ColorMap)), p, SLOT(setColorMap(const ColorMap&)));
    connect(p, SIGNAL(changed(ColorMap)), _gridLayers[ig], SLOT(setColorMap(const ColorMap&)));
    _sheet.addObject(p);
    _sheet.showObject(p);
    y += 8.0;
  }
}

void TFAResults::compute(int ig, Signal *sig, TFAParameters &param)
{
  TRACE;
  IrregularGrid2DPlot * plot =_gridLayers[ig];
  int nFreq=param.frequencySampling().count();
  TimeRange tw=param.range().absoluteRange(sig);
  int nTime=tw.lengthSamples(sig->samplingFrequency());
  if(nTime<=0) {
    Message::warning(MSG_ID, tr("Time Frequency Analysis"),
                     tr("Specified time range does not contain any signal (%1).").arg(sig->nameComponent()),
                     Message::ignore(), true);
    return;
  }
  TRACE_BUG;
  TRACE_BUG_INT(_gridLayers.count());
  TRACE_BUG_INT(nFreq);
  TRACE_BUG_INT(nTime);
  if(nTime*nFreq*_gridLayers.count()>64*1024*1024) { // More than 512 Mb required
    Message::warning(MSG_ID, tr("Time Frequency Analysis"),
                     tr("Time range is probably too large for signal %4 (%5=%6 samples). Given the number of signals (%1), "
                        "the number of frequency samples (%2), the maximum number of time samples is %3. "
                        "That corresponds to a total memory consumption of 512 Mb. Contact the developpers "
                        "if you think that this limit is obsolete according to current computer memories.")
                        .arg(_gridLayers.count())
                        .arg(nFreq)
                        .arg(round(64.0*1024*1024/_gridLayers.count()/nFreq))
                        .arg(sig->nameComponent())
                        .arg(Number::secondsToDuration(tw.lengthSeconds(), 0))
                        .arg(nTime), Message::ignore(), true);
    return;
  }
  DoubleSignal * sigProc=new DoubleSignal(nTime);
  sigProc->setSamplingPeriod(sig->samplingPeriod());
  sigProc->copySamplesFrom(sig, sig->startTime().secondsTo(tw.start()), 0.0, tw.lengthSeconds());
  IrregularGrid2D grid(nTime, nFreq);
  // TODO: set absolute timing in xAxis
  for(int iTime=0; iTime<nTime; iTime++) {
    grid.setX(iTime, iTime*sig->samplingPeriod());
  }
  SignalDatabase * db=GeopsyGuiEngine::instance()->database(this);
  for(int iFreq=0; iFreq<nFreq; iFreq++) {
    double f=param.frequencySampling().value(iFreq);
    grid.setY(iFreq, f);
    GeopsyCoreEngine::instance()->showMessage(db, tr("Signal %1 : Morlet wavelet convolution at %2 Hz")
                                              .arg(sig->nameComponent()).arg(f));
    param.wavelet().setFi(f);
    ComplexSignal * w=sigProc->morletWavelet(param.wavelet());
    CONST_LOCK_SAMPLES(Complex, wSamples, w)
      for(int iTime=0; iTime<nTime; iTime++ ) {
        grid.setValue(iTime, iFreq, wSamples[iTime].abs());
      }
    UNLOCK_SAMPLES(w)
    delete w;
  }
  plot->setSmooth(true);
  plot->setGrid(grid);
  plot->setLinearColorMap(0.0);
  Rect r=plot->boundingRect();
  AxisWindow * w=plot->graph();
  w->xAxis()->setRange(r.x1(), r.x2());
  w->yAxis()->setRange(r.y1(), r.y2());
  w->deepUpdate();
  delete sigProc;
}
