/***************************************************************************
**
**  This file is part of geopsyptmotion.
**
**  geopsyptmotion 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.
**
**  geopsyptmotion 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: 2004-05-24
**  Copyright: 2004-2019
**    Marc Wathelet
**    Marc Wathelet (ULg, Liège, Belgium)
**    Marc Wathelet (LGIT, Grenoble, France)
**
***************************************************************************/

#include <GeopsyCore.h>
#include <GeopsyGui.h>
#include <QGpCoreTools.h>
#include <QGpGuiTools.h>
#include <SciFigs.h>
#include "PtMotionResults.h"

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

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

void PtMotionResults::createObjects(SubSignalPool * subPool)
{
  TRACE;
  ASSERT(subPool->count()%3==0);
  sheet()->setStatusBar(GeopsyGuiEngine::instance()->statusBar());
  int n=subPool->count()/3;
  _curveLayers.resize(n);
  SubSignalPool::iterator it=subPool->begin();
  double x=0.5, y=0.5;
  for(int ig=0; ig<n; ig++, ++it) {
    AxisWindow * w=sheet()->addGraph();
    w->setGeometry(x, y, 7.0, 7.0, Axis::AxisSize);
    x+=9.0;
    if(x==18.5) {
      x=0.5;
      y+=9;
    }
    _curveLayers[ig]=new XUniqueYColorLines(w);
    _curveLayers[ig]->setLineWeight(0.01);
  }
}

void PtMotionResults::updateSignals(const SubSignalPool * subPool, TimeRangeParameters& tlParam,
                                    bool doFilter, const FilterParameters& fparam,
                                    bool verticalPlane, double direction)
{
  TRACE;
  ASSERT(subPool->count()>=_curveLayers.count());
  SubSignalPool::const_iterator it=subPool->begin();
  Angle proj;
  proj.setDegreeAzimuth(direction);
  QString xSuffix, ySuffix;
  if(verticalPlane) {
    proj.normalize();
    xSuffix=tr(" - dir %1" ).arg(Angle::mathToGeographic(proj.radians()), 0, 'f', 1);
    ySuffix=tr(" - Vertical");
    setWindowTitle(tr("Vertical particle motion%1").arg(xSuffix));
  } else {
    xSuffix=tr(" - East");
    ySuffix=tr(" - North");
    setWindowTitle(tr("Horizontal particle motion"));
  }
  const Signal *sigZ, *sigN, *sigE;
  const DoubleSignal *sigZp, *sigNp, *sigEp;
  Rect r;
  int n=_curveLayers.count();
  for(int ig=0; ig<n; ig++, ++it) {
    sigZ=*it;
    sigN=*(++it);
    sigE=*(++it);
    if(doFilter) {
      sigZp=filtered(sigZ, fparam);
      sigNp=filtered(sigN, fparam);
      sigEp=filtered(sigE, fparam);
    } else {
      sigZp=sigZ->saveType(DoubleSignal::Waveform);
      sigNp=sigN->saveType(DoubleSignal::Waveform);
      sigEp=sigE->saveType(DoubleSignal::Waveform);
    }
    TimeRange tw=tlParam.absoluteRange(sigZ);
    XUniqueYColorLines * plot=_curveLayers[ig];
    AxisWindow * w=plot->graph();
    w->xAxis()->setTitle(sigZ->name()+xSuffix);
    w->xAxis()->setTitleInversedScale(w->xAxis()->title());
    w->yAxis()->setTitle(sigZ->name()+ySuffix);
    w->yAxis()->setTitleInversedScale(w->yAxis()->title());
    double invdt=1.0/sigZ->samplingPeriod();
    int startIndex=qRound(sigZ->startTime().secondsTo(tw.start())*invdt);
    if(startIndex<0) startIndex=0;
    if(startIndex>sigZ->nSamples()) startIndex=sigZ->nSamples();
    int endIndex=qRound(sigZ->startTime().secondsTo(tw.end())*invdt);
    if(endIndex<0) endIndex=0;
    if(endIndex>sigZ->nSamples()) endIndex=sigZ->nSamples();
    plot->clear();
    plot->setPointCount(1, endIndex-startIndex);
    CONST_LOCK_SAMPLES(double, sampZ, sigZp)
      CONST_LOCK_SAMPLES(double, sampN, sigNp)
        CONST_LOCK_SAMPLES(double, sampE, sigEp)
          double * x=plot->x();
          double * y=plot->y();
          LayerLocker ll(plot);
          if(verticalPlane) {
            for(int i=startIndex; i<endIndex; i++) {
              int ip=i-startIndex;
              x[ip]=sampE[i]*proj.cos()+sampN[i]*proj.sin();
              y[ip]=sampZ[i];
            }
          } else {
            for(int i=startIndex; i<endIndex; i++) {
              int ip=i-startIndex;
              x[ip]=sampE[i];
              y[ip]=sampN[i];
            }
          }
        UNLOCK_SAMPLES(sigEp)
      UNLOCK_SAMPLES(sigNp)
    UNLOCK_SAMPLES(sigZp)
    if(doFilter) {
      delete sigZp;
      delete sigNp;
      delete sigEp;
    } else {
      sigZ->restoreType(sigZp);
      sigN->restoreType(sigNp);
      sigE->restoreType(sigEp);
    }
    w->deepUpdate();
  }
}

void PtMotionResults::setPlotOtions(bool plotLines)
{
  TRACE;
  int n=_curveLayers.count();
  for(int ig=0; ig<n; ig++) {
    XUniqueYColorLines * plot=_curveLayers[ig];
    plot->setSymbol(plotLines ? Symbol::NoSymbol : Symbol::Circle);
  }
}

DoubleSignal * PtMotionResults::filtered(const DoubleSignal * sig, const FilterParameters& fparam)
{
  TRACE;
  DoubleSignal * fSig=new DoubleSignal(sig->nSamples());
  fSig->setSamplingPeriod(sig->samplingPeriod());
  fSig->copySamplesFrom(sig);
  fSig->filter(fparam);
  fSig->fastFourierTransform(DoubleSignal::Waveform);
  return fSig;
}

void PtMotionResults::setLimits()
{
  TRACE;
  Rect r;
  int n=_curveLayers.count();
  for(int ig=0;ig < n;ig++ ) {
    AxisWindow * w=_curveLayers[ ig ]->graph();
   // Adjust axis limits
    r=_curveLayers[ig]->boundingRect();
    r.enlarge(0.05, LinearScale, LinearScale);
    r.square();
    w->xAxis()->setRange(r.x1(), r.x2());
    w->yAxis()->setRange(r.y1(), r.y2());
    w->deepUpdate();
  }
}
