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

#include <DinverDCCore.h>

#include "SPACLoop.h"
#if 0
namespace ArrayCore {

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

    Full description of class still missing
  */

  /*!
    Description of constructor still missing
  */
  SPACLoop::SPACLoop(const ArraySelection * array)
    : ArrayLoop(array)
  {
    TRACE;
  }

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

  bool SPACLoop::setParameters(const ArrayParameters * p)
  {
    TRACE;
    const SPACParameters * sParam=dynamic_cast<const SPACParameters *>(p);
    if(!sParam) {
      qDebug() << "Parameters are not SPACParameters in SPACLoop::setParameters.";
      return false;
    }
    ArrayLoop::setParameters(p);
    results()->setParameters(*sParam);

    // Write ring log
    int nRings=sParam->ringCount();
    for(int iRing=0; iRing<nRings; iRing++) {
      App::log(sParam->ring(iRing).toUserString()+"\n");
    }
    return true;
  }

  LoopWorker * SPACLoop::newWorker()
  {
    SPACLoopWorker * t=new SPACLoopWorker;
    t->setLoop(this);
    t->setArray(array());
    t->setParameters(parameters());
    return t;
  }

  SPACLoopWorker::SPACLoopWorker()
  {
    TRACE;
    _crossSpectrum=nullptr;
  }

  SPACLoopWorker::~SPACLoopWorker()
  {
    TRACE;
    // Parameters are not owned by process
    _crossSpectrum->takeParameters();
    delete _crossSpectrum;
  }

  void SPACLoopWorker::setArray(const ArraySelection * array)
  {
    TRACE;
    _crossSpectrum=new SPACCrossSpectrum(array);
    _crossSpectrum->setTimeRangeList(new TimeWindowList);
  }

  void SPACLoopWorker::setParameters(const SPACParameters * param)
  {
    TRACE;
    _crossSpectrum->setParameters(param);
    _stats.setParameters(param, _loop->array()->array()->nComponents());
  }

  void SPACLoopWorker::run(int index)
  {
    TRACE;
    // Revert the order: start with expensive high frequencies
    // When the number of cores increases and tends to the number
    // of frequencies, it is more efficient to start with with the
    // most expensive frequencies.
    QString freqStatus;
    int frequencyIndex=endIndex()-index-1;
    if(!_crossSpectrum->setFrequencyIndex(frequencyIndex, &freqStatus)) {
      return;
    }
    setStatus(freqStatus);

    // Loop over all time windows
    const TimeRangeList& winList=*_crossSpectrum->timeRangeList();
    int nWin=winList.count();
    setProgressMaximum(nWin);

    _stats.reset();
    SPACResults * results=_loop->results();
    double maxImaginary=_crossSpectrum->parameters()->maximumImaginary();

    int iWin=0;
    int blockSetCount=0;
    int nRejected[3];
    nRejected[0]=0;
    nRejected[1]=0;
    nRejected[2]=0;
    FourierPlan plan(qRound(winList.at(0).lengthSamples(_crossSpectrum->array().array()->first()->samplingFrequency())
                     *_crossSpectrum->parameters()->oversamplingFactor()),
                     _crossSpectrum->array().array()->first()->samplingPeriod(),
                     _crossSpectrum->frequency().center());
    while(iWin<nWin) {
      if(terminated()) {
        break;
      }
      APP_LOG(3, tr("  Time window %1/%2...\n")
                        .arg(iWin)
                        .arg(nWin));
      setProgressValue(iWin);
      if(_crossSpectrum->calculate(iWin, plan)) {
        Complex val;
        for(int iRing=_crossSpectrum->ringCount()-1; iRing>=0; iRing--) {
          const RingPairs& ring=_crossSpectrum->ring(iRing);
          switch (_loop->array()->array()->components()) {
          case StationSignals::AllComponent:
            val=ring.radialAutocorr(_crossSpectrum);
            if(fabs(val.im())<maxImaginary) {
              _stats.addValue(iRing, 1, val.re());
            } else {
              nRejected[1]++;
            }
            val=ring.transverseAutocorr(_crossSpectrum);
            if(fabs(val.im())<maxImaginary) {
              _stats.addValue(iRing, 2, val.re());
            } else {
              nRejected[2]++;
            }
            break;
          case StationSignals::VerticalComponent:
            break;
          }
          val=ring.verticalAutocorr(_crossSpectrum);
          if(fabs(val.im())<maxImaginary) {
            _stats.addValue(iRing, 0, val.re());
          } else {
            nRejected[0]++;
          }
        }
      } else {
        break;
      }
      blockSetCount++;
    }
    if(AbstractStream::applicationVerbosity()>=1) {
      int n;
      switch (_loop->array()->array()->components()) {
      case StationSignals::AllComponent:
        n=_stats.count(1);
        App::log(tr("%1 values, %2 rejected (%3 %) at %4 Hz for radial component.\n")
                 .arg(n)
                 .arg(nRejected[1])
                 .arg((100.0*nRejected[1])/(nRejected[1]+n))
                 .arg(_crossSpectrum->frequency().center()));
        n=_stats.count(2);
        App::log(tr("%1 values, %2 rejected (%3 %) at %4 Hz for transverse component.\n")
                 .arg(n)
                 .arg(nRejected[2])
                 .arg((100.0*nRejected[2])/(nRejected[2]+n))
                 .arg(_crossSpectrum->frequency().center()));
        break;
      case StationSignals::VerticalComponent:
        break;
      }
      n=_stats.count(0);
      App::log(tr("%1 values, %2 rejected (%3 %) at %4 Hz for vertical component.\n")
               .arg(n)
               .arg(nRejected[0])
               .arg((100.0*nRejected[0])/(nRejected[0]+n))
               .arg(_crossSpectrum->frequency().center()));
    }
    results->add(frequencyIndex, _crossSpectrum->frequency().center(), _stats);
    App::log(tr("Computed %1 block sets at %2 Hz\n")
             .arg(blockSetCount)
             .arg(_crossSpectrum->frequency().center(), 0, 'f', 2));
  }

} // namespace ArrayCore
#endif
