/***************************************************************************
**
**  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: 2018-04-25
**  Copyright: 2018-2019
**    Marc Wathelet (ISTerre, Grenoble, France)
**
***************************************************************************/

#include "MuttiArrayFKLoop.h"
#include "WaveNumberConverter.h"

namespace ArrayCore {
#if 0

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

    Full description of class still missing
  */

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

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

  LoopWorker * MuttiArrayFKLoop::newWorker()
  {
    TRACE;
  }

  void MuttiArrayFKLoopWorker::run(int index)
  {
    TRACE;
    // Within a higly parallel process, we cannot use a separate endl when
    // writing to standard stream, the sentence can be cut before \n
    // We use flush instead.

    // 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 the
    // most expensive frequencies.
    // This is no longer the case with the limitation on number of statistical point STATISTIC_COUNT
    QString freqStatus;
    for(QVector<FKCrossSpectrum *>::iterator it=_process.begin(); it!=_process.end(); it++) {
      (*it)->setFrequencyIndex(endIndex()-index-1, &freqStatus);
    }
    setStatus(freqStatus);

    WaveNumberConverter conv(_process.first()->frequency().center());
    bool runRayleigh, runLove;
    SAFE_UNINITIALIZED(runRayleigh, true)
    SAFE_UNINITIALIZED(runLove, true)
    switch(_loop->results()->mode()) {
    case ArrayStations::Vertical:
      runRayleigh=setSlownessRange(0);
      runLove=false;
      static_cast<FK *>(_grid[0]->function())->setTotalLimits(_crossSpectrum->frequency().squaredOmega());
      break;
    case ArrayStations::Horizontal:
    case ArrayStations::ThreeComponents:
      runRayleigh=setSlownessRange(0);
      runLove=setSlownessRange(1);
      static_cast<FK *>(_grid[0]->function())->setTotalLimits(_crossSpectrum->frequency().squaredOmega());
      static_cast<FK *>(_grid[1]->function())->setTotalLimits(_crossSpectrum->frequency().squaredOmega());
      break;
    }
    if(!runRayleigh && !runLove) {
      return;
    }

    // Loop over all processes to build a common cross-spectral matrix
    for(QVector<FKCrossSpectrum *>::iterator it=_process.begin(); it!=_process.end(); it++) {

    }

    // Loop over all time windows
    const TimeRangeList& winList=*_crossSpectrum->timeRangeList();
    int nWin=winList.count();
    setProgressMaximum(nWin);
#ifdef FKLOOP_TIMING
    QTime chrono;
    int t;
#endif
    int iWin=0;
    while(iWin<nWin) {
      if(terminated()) {
        break;
      }
#ifdef FKLOOP_TIMING
      chrono.start();
#endif

      APP_LOG(3, tr("  Time window %1/%2...%3 %4\n")
                        .arg(iWin)
                        .arg(nWin)
                        .arg(runRayleigh ? "R" : " ")
                        .arg(runLove ? "L" : " "));
      setProgressValue(iWin);
#ifdef FKLOOP_INSPECT_TIME
      const TimeRange& win=winList.at(iWin);
      if(fabs(win->start()-FKLOOP_INSPECT_TIME)<0.1) {
        App::log(tr("Inspect time window starting at %1\n").arg(win->start()) << flush;
      } else {
        continue;
      }
#endif
      conv.setTime(winList.at(iWin).start());
      if(_crossSpectrum->run(iWin, runRayleigh, runLove)) {
        switch(_loop->results()->mode()) {
        case ArrayStations::Vertical:
          conv.setPolarization(Mode::Vertical);
          localizeMax(0);
          addPeak(0, conv);
          break;
        case ArrayStations::Horizontal:
          if(runRayleigh) {
            conv.setPolarization(Mode::Radial);
            localizeMax(0);
            addPeak(0, conv);
          }
          if(runLove) {
            conv.setPolarization(Mode::Transverse);
            localizeMax(1);
            addPeak(1, conv);
          }
          break;
        case ArrayStations::ThreeComponents:
          if(runRayleigh) {
            conv.setPolarization(Mode::Rayleigh);
            localizeMax(0);
            addPeak(0, conv);
          }
          if(runLove) {
            conv.setPolarization(Mode::Love);
            localizeMax(1);
            addPeak(1, conv);
          }
          break;
        }
        _crossSpectrum->unlockTimeWindow();
#ifdef FKLOOP_TIMING
        t=chrono.elapsed();
        App::log(9, tr("Time window computation took %1 ms").arg(t));
#endif
      } else {  // HRFK regularly return false for the last windows
        APP_LOG(3, tr("    cannot lock time window\n"));
      }
    }
    App::log(tr("Computed %1 windows at %2 Hz\n").arg(nWin).arg(conv.frequency(), 0, 'f', 2) << flush;
  }
#endif

} // namespace ArrayCore

