/***************************************************************************
**
**  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: 2007-11-13
**  Copyright: 2007-2019
**    Marc Wathelet (LGIT, Grenoble, France)
**
***************************************************************************/

#ifndef FKARRAYMAP_H
#define FKARRAYMAP_H

#include <QGpCoreMath.h>

#include "SourceSignal.h"

class SourceParameters;
class MediumParameters;

class FKArrayMap : public AbstractFunction
{
  TRANSLATIONS("FKArrayMap")
public:
  FKArrayMap();
  ~FKArrayMap();

  enum Polarization {FK_Vertical, FK_Radial, FK_Transverse,
                     FK_Rayleigh, FK_RayleighPositive, FK_RayleighNegative, FK_EllipticitySign,
                     HRFK_Vertical, HRFK_Radial, HRFK_Transverse,
                     HRFK_Rayleigh, HRFK_Ellipticity, HRFK_RayleighNoise, HRFK_PoggiEllipticity,
                     HRFK2_Rayleigh, HRFK2_Ellipticity, HRFK2_AbsEllipticity,
                     HRFK_DirectRayleigh, HRFK_DirectLove, HRFK_DirectEllipticity, HRFK_DirectAbsEllipticity,
                     HRFK2_DirectRayleigh,HRFK2_DirectEllipticity, HRFK2_DirectAbsEllipticity};

  void setStations(const QVector<Point2D>& p);
  void addSource();
  void setSourceCount(int nSrc);
  void removeSource(int index);
  void setSourceSignals(int iSrc, const SourceParameters& src,
                        const MediumParameters& medium, int blockCount);
  void setStationSignals(double noiseRatio, bool normalize, int blockCount);

  int sourceCount() const {return _sourceSig.count();}
  double theoreticalKmax() const;

  Polarization polarization() const {return _polarization;}
  void setPolarization(Polarization p) {_polarization=p;}

  void setSensorRotation(double a) {_sensorRotation=a;}
  double sensorRotation() const {return _sensorRotation;}

  void setWaveModel(SourceParameters::WaveModel wm) {_waveModel=wm;}
  SourceParameters::WaveModel waveModel() const {return _waveModel;}

  virtual double value(const Point& k) const;

  void setKmax(double k) {_kmax=k;}
  double FKVertical(const Point& k) const;
  double FKRadial(const Point& k) const;
  double FKTransverse(const Point& k) const;
  double FKRayleigh(const Point& k) const;
  double FKRayleighPositive(const Point& k) const;
  double FKRayleighNegative(const Point& k) const;
  double FKEllipticitySign(const Point& k) const;
  double HRFKVertical(const Point& k) const;
  double HRFKRadial(const Point& k) const;
  double HRFKTransverse(const Point& k) const;
  double HRFKRayleigh(const Point& k) const;
  double HRFKEllipticity(const Point& kell) const;
  double HRFKRayleighNoise(const Point& kell) const;
  double HRFKPoggiEllipticity(const Point& k) const;
  double HRFK2Rayleigh(const Point& kell) const;
  double HRFK2Ellipticity(const Point& kell) const;
  double HRFKDirectLove(const Point& k) const;
  double HRFKDirectRayleigh(const Point& kell) const;
  double HRFKDirectEllipticity(const Point& kell) const;
  double HRFK2DirectRayleigh(const Point& kell) const;
  double HRFK2DirectEllipticity(const Point& kell) const;

  virtual double thirdMinimum() const;
  virtual double thirdMaximum() const;
  virtual double thirdStep() const;
private:
  void clearSignals();
  void uniquePoints();
  void crossPowerVertical(int blockCount, bool normalize, double noiseRatio);
  void crossPowerRadial(int blockCount, bool normalize, double noiseRatio);
  void crossPowerTransverse(int blockCount, bool normalize, double noiseRatio);
  void crossPowerRayleigh(int blockCount, bool normalize, double noiseRatio);
  void crossPowerDirectLove(int blockCount, bool normalize, double noiseRatio);
  void crossPowerDirectRayleigh(int blockCount, bool normalize, double noiseRatio);
  static bool inverseCrossPower(ComplexMatrix& covmat);
  bool inverseCrossPower(ComplexMatrix * covmats);
  int rotationIndex(const Point& k) const;
  void steering(const Point& k, ComplexMatrix& e, ComplexMatrix& eh) const;
  void FKRayleighSteering(const Point& k, ComplexMatrix& e, ComplexMatrix& eh, double ell) const;
  void HRFKRayleighRadialSteering(const Point& k, ComplexMatrix& e, ComplexMatrix& eh, double ell) const;
  void HRFKRayleighVerticalSteering(const Point& k, ComplexMatrix& e, ComplexMatrix& eh, double ell) const;
  void HRFK2RayleighSteering(const Point& k, ComplexMatrix& e, ComplexMatrix& eh, double ell) const;
  void HRFKDirectLoveSteering(const Point& k, ComplexMatrix& e, ComplexMatrix& eh) const;
  void HRFKDirectRayleighSteering(const Point& k, ComplexMatrix& e, ComplexMatrix& eh, double ell) const;
  inline double fkPower(const Point& k, const ComplexMatrix& covmat) const;
  inline double fkPower(const ComplexMatrix& covmat, const ComplexMatrix& e, const ComplexMatrix& eh) const;
  inline double hrfkPower(const Point& k, const ComplexMatrix& covmat) const;
  inline double hrfkPower(const ComplexMatrix& covmat, const ComplexMatrix& e, const ComplexMatrix& eh) const;
  QVector<Angle> horizontalOrientations();

  SourceParameters::WaveModel _waveModel;
  Polarization _polarization;
  double _sensorRotation;
  QVector<Point2D> _stations;
  Complex *** _stationSig;
  QVector<SourceSignal *> _sourceSig;
  double _kmax;

  int _rotateStepCount;
  double _rotateStep;
  ComplexMatrix _verticalCrossSpectrum;
  ComplexMatrix * _rayleighCrossSpectra;
  ComplexMatrix * _radialCrossSpectra;
  ComplexMatrix * _transverseCrossSpectra;
  ComplexMatrix _loveCrossSpectrum;
  ComplexMatrix _rayleighCrossSpectrum;
};

#endif // FKARRAYMAP_H
