/***************************************************************************
**
**  This file is part of gpfksimulator.
**
**  gpfksimulator 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.
**
**  gpfksimulator 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: 2016-12-09
**  Copyright: 2016-2019
**    Marc Wathelet (ISTerre, Grenoble, France)
**
***************************************************************************/

#include "SourceSignal.h"
#include "MediumParameters.h"

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

  Full description of class still missing
*/

GlobalRandom * SourceSignal::_timePhaseGenerator=nullptr;

/*!
  Description of constructor still missing
*/
SourceSignal::SourceSignal()
{
  TRACE;
  _sigs=nullptr;
  if(!_timePhaseGenerator) {
    _timePhaseGenerator=new GlobalRandom;
    CoreApplication::instance()->addGlobalObject(_timePhaseGenerator);
  }
}

/*!
  Description of destructor still missing
*/
SourceSignal::~SourceSignal()
{
  TRACE;
  delete [] _sigs;
}

void SourceSignal::setParameters(SourceParameters::WaveModel wm,
                                 const SourceParameters& param,
                                 const MediumParameters& medium,
                                 int blockCount,
                                 const QVector<Point2D>& stations)
{
  TRACE;
  // FK uses only the first block with 0 time phase
  // Random phases stabilize HRFK based on several blocks
  _param=param;
  // Resize containers
  int ns=stations.count();
  delete [] _sigs;
  _sigs=new QVector<Complex>[blockCount];
  for(int ib=0; ib<blockCount; ib++) {
    _sigs[ib].resize(ns);
  }
  double k=2.0*M_PI*medium.frequency()/_param.velocity();
  double timePhase=0.0;
  if(wm==SourceParameters::PlaneWaves) {
    for(int ib=0; ib<blockCount; ib++) {
      QVector<Complex>& bSigs=_sigs[ib];
      if(ib>0) {
        timePhase=_timePhaseGenerator->uniform(0.0, 2.0*M_PI);
      }
      for(int is=0; is<ns; is++) {
        double az=Point().azimuthTo(stations[is]);
        double r=Point().distanceTo(stations[is])*cos(az-_param.azimuthMath(wm));
        bSigs[is].setExp(_param.amplitude(), timePhase+_param.phase()-k*r);
      }
    }
  } else {
    if(medium.attenuation()==0.0) {
      for(int ib=0; ib<blockCount; ib++) {
        QVector<Complex>& bSigs=_sigs[ib];
        if(ib>0) {
          timePhase=_timePhaseGenerator->uniform(0.0, 2.0*M_PI);
        }
        for(int is=0; is<ns; is++) {
          double r=_param.sourcePoint().distanceTo(stations[is]);
          bSigs[is].setExp(_param.amplitude(), timePhase+_param.phase()-k*r);
        }
      }
    } else {
      double inv2Qk=k/(2.0*medium.attenuation());
      for(int ib=0; ib<blockCount; ib++) {
        QVector<Complex>& bSigs=_sigs[ib];
        if(ib>0) {
          timePhase=_timePhaseGenerator->uniform(0.0, 2.0*M_PI);
        }
        for(int is=0; is<ns; is++ ) {
          double r=_param.sourcePoint().distanceTo(stations[is]);
          bSigs[is].setExp(_param.amplitude()/(2.0*M_PI*r)*exp(-r*inv2Qk), timePhase+_param.phase()-k*r);
        }
      }
    }
  }
}
