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

#ifndef ACTIVEFKSTEERING_H
#define ACTIVEFKSTEERING_H

#include <QGpCoreMath.h>

#include "FKSteering.h"
#include "ArraySelection.h"
#include "ArrayCoreDLLExport.h"

namespace ArrayCore {

  class ARRAYCORE_EXPORT ActiveFKSteering : public FKSteering
  {
  public:
    ActiveFKSteering();
    ~ActiveFKSteering();

    void clear();

    void setSource(const Point& src, const ArraySelection& array);

    void setDistances();
    void setAmplitudeFactors();
    void setRadialRotations();
    void setTransverseRotations();

    int count() const {return _count;}
    double distance(int index) const {return _distances[index];}
    double amplitudeFactor(int index) const {return _amplitudeFactors[index];}
    const Angle& radialRotation(int index) const {return _radialRotations[index];}
    const Angle& transverseRotation(int index) const {return _transverseRotations[index];}

    /*inline void twoComponentConvRayleighRadial(double k, double ell, ComplexMatrix& e, ComplexMatrix& eh) const;
    inline void twoComponentConvRayleighVertical(double k, double ell, ComplexMatrix& e, ComplexMatrix& eh) const;
    inline void twoComponentRayleighRadial(double k, double ell, ComplexMatrix& e, ComplexMatrix& eh) const;
    inline void twoComponentRayleighVertical(double k, double ell, ComplexMatrix& e, ComplexMatrix& eh) const;
    inline void threeComponentRayleighRadial(double k, double ell, ComplexMatrix& e, ComplexMatrix& eh) const;
    inline void twoComponentTransverse(double k, ComplexMatrix& e, ComplexMatrix& eh) const;*/
  protected:
    int _count;
    Point2D * _vectors;
    double * _distances;
    double * _amplitudeFactors;
    Angle * _radialRotations;
    Angle * _transverseRotations;
  };

  // TODO move to specific classes like ActiveFKSteeringOneComponent
  /*
  inline void ActiveFKSteering::twoComponentConvRayleighRadial(double k, double ell, ComplexMatrix& e, ComplexMatrix& eh) const
  {
    int stationCount=_count;
    int stationCount2=2*stationCount;
    e.resize(stationCount2, 1);
    eh.resize(1, stationCount2);
    Complex q;
    Complex cell(0.0, -1.0/ell); // See Wathelet et al. (2018) equation (17)
    for(int i=stationCount-1; i>=0; i--) {
      q.setUnitExp(-k*_distances[i]);
      e.at(i+stationCount, 0)=q;
      eh.at(0, i+stationCount)=conjugate(q);
      q*=cell;
      e.at(i, 0)=q;
      eh.at(0, i)=conjugate(q);
    }
  }

  inline void ActiveFKSteering::twoComponentConvRayleighVertical(double k, double ell, ComplexMatrix& e, ComplexMatrix& eh) const
  {
    int stationCount=_count;
    int stationCount2=2*stationCount;
    e.resize(stationCount2, 1);
    eh.resize(1, stationCount2);
    Complex q;
    Complex cell(0.0, ell); // See Wathelet et al. (2018) equation (17)
    for(int i=stationCount-1; i>=0; i--) {
      q.setUnitExp(-k*_distances[i]);
      e.at(i, 0)=q;
      eh.at(0, i)=conjugate(q);
      q*=cell;
      e.at(i+stationCount, 0)=q;
      eh.at(0, i+stationCount)=conjugate(q);
    }
  }

  inline void ActiveFKSteering::twoComponentRayleighRadial(double k, double ell, ComplexMatrix& e, ComplexMatrix& eh) const
  {
    int stationCount=_count;
    int stationCount2=2*stationCount;
    e.resize(stationCount2, 1);
    eh.resize(1, stationCount2);
    Complex q;
    Complex cell(0.0, -ell); // See Wathelet et al. (2018) equation (30)
    for(int i=stationCount-1; i>=0; i--) {
      q.setUnitExp(-k*_distances[i]);
      e.at(i+stationCount, 0)=q;
      eh.at(0, i+stationCount)=conjugate(q);
      q*=cell;
      e.at(i, 0)=q;
      eh.at(0, i)=conjugate(q);
    }
  }

  inline void ActiveFKSteering::twoComponentRayleighVertical(double k, double ell, ComplexMatrix& e, ComplexMatrix& eh) const
  {
    int stationCount=_count;
    int stationCount2=2*stationCount;
    e.resize(stationCount2, 1);
    eh.resize(1, stationCount2);
    Complex q;
    Complex cell(0.0, 1.0/ell); // See Wathelet et al. (2018) equation (30)
    for(int i=stationCount-1; i>=0; i--) {
      q.setUnitExp(-k*_distances[i]);
      e.at(i, 0)=q;
      eh.at(0, i)=conjugate(q);
      q*=cell;
      e.at(i+stationCount, 0)=q;
      eh.at(0, i+stationCount)=conjugate(q);
    }
  }

  inline void ActiveFKSteering::threeComponentRayleighRadial(double k, double ell,
                                                             ComplexMatrix& e, ComplexMatrix& eh) const
  {
    int stationCount=_count;
    int stationCount2=2*stationCount;
    int stationCount3=3*stationCount;
    e.resize(stationCount3, 1);
    eh.resize(1, stationCount3);
    Complex q, qc;
    Complex cell(0.0, -ell);
    for(int i=stationCount-1; i>=0; i--) {
      q.setUnitExp(-k*_distances[i]);
      e.at(i+stationCount2, 0)=q;
      eh.at(0, i+stationCount2)=conjugate(q);
      q*=cell;
      qc=conjugate(q);
      e.at(i, 0)=q*_radialRotations[i].cos();
      eh.at(0, i)=qc*_radialRotations[i].cos();
      e.at(i+stationCount, 0)=q*_radialRotations[i].sin();
      eh.at(0, i+stationCount)=qc*_radialRotations[i].sin();
    }
  }

  inline void ActiveFKSteering::twoComponentTransverse(double k, ComplexMatrix& e, ComplexMatrix& eh) const
  {
    int stationCount=_count;
    int stationCount2=2*stationCount;
    e.resize(stationCount2, 1);
    eh.resize(1, stationCount2);
    Complex q,qc;
    for(int i=stationCount-1; i>=0; i--) {
      q.setUnitExp(-k*_distances[i]);
      qc=conjugate(q);
      e.at(i, 0)=q*_transverseRotations[i].cos();
      eh.at(0, i)=qc*_transverseRotations[i].cos();
      e.at(i+stationCount, 0)=q*_transverseRotations[i].sin();
      eh.at(0, i+stationCount)=qc*_transverseRotations[i].sin();
    }
  }*/

} // namespace ArrayCore

#endif // ACTIVEFKSTEERING_H

