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

#include "T0Correlation.h"
#include "ShotRecord.h"

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

  Full description of class still missing
*/

/*!
  Description of constructor still missing
*/
T0Correlation::T0Correlation(ShotRecord * refShot, ShotRecord * shot)
{
  TRACE;
  _refShot=refShot;
  _shot=shot;
  _minRecIndex=0;
  _maxRecIndex=_refShot->receivers()->count()-1;
}

void T0Correlation::setReceiverRange(int minRecIndex, int maxRecIndex)
{
  TRACE;
  int nReceivers=_refShot->receivers()->count();
  _minRecIndex=minRecIndex;
  if(_minRecIndex<0) _minRecIndex=0;
  else if(_minRecIndex>=nReceivers) _minRecIndex=nReceivers-1;
  _maxRecIndex=maxRecIndex;
  if(_maxRecIndex<0) _maxRecIndex=0;
  else if(_maxRecIndex>=nReceivers) _maxRecIndex=nReceivers-1;
  if(_minRecIndex > _maxRecIndex) {
    int tmp=_minRecIndex;
    _minRecIndex=_maxRecIndex;
    _maxRecIndex=tmp;
  }
}

/*!
  Fast but imprecise shift: shift only multiples of deltaT
*/
double T0Correlation::value(const Point& p, int) const
{
  TRACE;
  double globalCorr=0.0;
  for(int i=_minRecIndex; i<=_maxRecIndex; i++) {
    Signal * shotSig=_shot->receivers()->at(i);
    const Signal * refShotSig=_refShot->receivers()->at(i);
    DateTime saveTime=shotSig->startTime();
    // Do not use shit() because signals are altered and it is longer
    shotSig->setStartTime(refShotSig->startTime().shifted(p.x()));
    TimeRange tw=_timeLimits.absoluteRange(shotSig);
    double norm=1.0/refShotSig->maximumAmplitude();
    globalCorr+=shotSig->correlation(refShotSig, tw)*norm*norm;
    shotSig->setStartTime(saveTime);
  }
  return globalCorr;
}

/*!
  Slow but precise shift: shift by arbitrary time
*/
double T0Correlation::value(const Point& p) const
{
  TRACE;
  double globalCorr=0.0;
  for(int i=_minRecIndex; i<=_maxRecIndex; i++) {
    const Signal * refShotSig=_refShot->receivers()->at(i);
    const Signal * shotSig=_shot->receivers()->at(i);
    DoubleSignal * shiftShotSig=new DoubleSignal(*shotSig);
    shiftShotSig->copySamplesFrom(shotSig);
    shiftShotSig->shift(p.x());
    TimeRange tw=_timeLimits.absoluteRange(shotSig);
    double norm=1.0/refShotSig->maximumAmplitude();
    globalCorr+=shiftShotSig->correlation(refShotSig, refShotSig->startTime().secondsTo(tw.start()),
                                                      shotSig->startTime().secondsTo(tw.start()),
                                                      tw.lengthSeconds())*norm*norm;
    delete shiftShotSig;
  }
  return globalCorr;
}
