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

#include "StationProcessSignals.h"

namespace GeopsyCore {

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

  Full description of class still missing
*/

/*!
  Never take ownership of \a originalSignals
*/
StationProcessSignals::StationProcessSignals(const StationSignals * originalSignals)
{
  _nComponents=originalSignals->nComponents();
  _originals=originalSignals;
  _signals=new ComponentSignals[_nComponents];
}

/*!
  Never take ownership of \a originalSignals
*/
StationProcessSignals::StationProcessSignals(int nComponents)
{
  _nComponents=nComponents;
  _originals=nullptr;
  _signals=new ComponentSignals[_nComponents];
}

/*!
  Description of destructor still missing
*/
StationProcessSignals::~StationProcessSignals()
{
  for(int iComp=0; iComp<_nComponents; iComp++) {
    ComponentSignals& cs=_signals[iComp];
    if(cs.merged) {
      qDeleteAll(*cs.merged);
      delete cs.merged;
    }
    if(cs.filtered) {
      qDeleteAll(*cs.filtered);
      delete cs.filtered;
    }
    delete cs.processed;
  }
  delete [] _signals;
}

/*!
  If \a frequency is 0, no filter is performed
*/
void StationProcessSignals::setHighPassFilter(double frequency)
{
  TRACE;
  if(_nComponents<=0) return;
  if(frequency<=0.0) {
    for(int iComp=0; iComp<_nComponents; iComp++) {
      ComponentSignals& cs=_signals[iComp];
      if(cs.filtered) {
        qDeleteAll(*cs.filtered);
        delete cs.filtered;
        cs.filtered=nullptr;
      }
    }
  } else {
    double dt=_originals->samplingPeriod();
    if(!_signals[0].merged) {
      // TODO merge original signals
    }
    if(!_signals[0].filtered) { // Allocate filtered signals
      for(int iComp=0; iComp<_nComponents; iComp++) {
        const SubSignalPool& originals=_originals->originals(iComp);
        ComponentSignals& cs=_signals[iComp];
        cs.filtered=new QList<DoubleSignal *>;
        DoubleSignal * sig;
        for(SubSignalPool::const_iterator it=originals.begin(); it!=originals.end();it++) {
          Signal * origSig=*it;
          sig=new DoubleSignal (origSig->nSamples());
          sig->setSamplingPeriod(dt);
          cs.filtered->append(sig);
        }
      }
    }
    // Copy and filter, normally should be based on merged signals TODO
    for(int iComp=0; iComp<_nComponents; iComp++) {
      const SubSignalPool& originals=_originals->originals(iComp);
      ComponentSignals& cs=_signals[iComp];
      FilterParameters fparam;
      fparam.setFrequencyRange(frequency);
      fparam.setWidth(0.1);
      fparam.setBand(FilterParameters::HighPass);
      fparam.setMethod(FilterParameters::FrequencyWindow);
      int n=originals.count();
      for(int i=0; i<n; i++) {
        Signal * origSig=originals.at(i);
        (*cs.filtered)[i]->copySamplesFrom(origSig);
        (*cs.filtered)[i]->filter(fparam);
      }
    }
  }
}

/*!
  Extracts a copy of original signals for component \a comp and for time window \a tw
*/
bool StationProcessSignals::copyOriginalSignal(int iComp, const TimeRange& tw,
                                               const StationProcessSignals * from)
{
  TRACE;
  ComponentSignals& fromCS=from->_signals[iComp];
  ComponentSignals& toCS=_signals[iComp];
  const SubSignalPool& originals=from->_originals->originals(iComp);
  int n=originals.count();

  double dt=from->_originals->samplingPeriod();
  int nSamples=tw.lengthSamples(1.0/dt);
  if(toCS.processed) {
    toCS.processed->freeSamples();
    toCS.processed->setNSamples(nSamples);
    toCS.processed->setType(DoubleSignal::Waveform);
    toCS.processed->setSamplingPeriod(dt);
  } else {
    toCS.processed=new DoubleSignal(nSamples);
    toCS.processed->setSamplingPeriod(dt);
  }
  // Set NULL signal
  toCS.processed->setValue(0.0);
  if(fromCS.filtered) {
    for(int i=0; i<n; i++) {
      Signal * origSig=originals.at(i);
      DoubleSignal * sig=fromCS.filtered->at(i);
      if(!toCS.processed->copySamplesFrom(sig, origSig->startTime().secondsTo(tw.start()), 0.0, tw.lengthSeconds())) {
        return false;
      }
    }
  } else {
    for(int i=0; i<n; i++) {
      Signal * sig=originals.at(i);
      if(!toCS.processed->copySamplesFrom(sig, sig->startTime().secondsTo(tw.start()), 0.0, tw.lengthSeconds())) {
        return false;
      }
    }
  }
  return true;
}


/*!
  Lock all processed signals. If successful, the samples of processed signals can be used and UNLOCK_SAMPLES must be called
  when signal samples are no longer necessary.
*/
bool StationProcessSignals::lockSamples()
{
  TRACE;
  for(int iComp=0; iComp<_nComponents; iComp++) {
    ComponentSignals& cs=_signals[iComp];
    cs.processedSamples=cs.processed->constLockSamples();
    if(!cs.processedSamples) {
      for(iComp--; iComp>=0; iComp--) _signals[iComp].processed->unlockSamples();
      return false;
    }
  }
  return true;
}

/*!
  Unlock all processed signals. Can be called only after a successful LOCK_SAMPLES
*/
void StationProcessSignals::unlockSamples()
{
  TRACE;
  for(int iComp=0; iComp<_nComponents; iComp++) {
    DoubleSignal * sig=_signals[iComp].processed;
    if(sig) {
      sig->unlockSamples();
    }
  }
}

} // namespace GeopsyCore
