/***************************************************************************
**
**  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: 2008-03-04
**  Copyright: 2008-2019
**    Marc Wathelet
**    Marc Wathelet (LGIT, Grenoble, France)
**
***************************************************************************/

#include "SPACCrossSpectrum.h"
#include "StationPair.h"
#include "SPACRing.h"

namespace ArrayCore {

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

    Full description of class still missing
  */

  /*!
    Description of constructor still missing
  */
  SPACCrossSpectrum::SPACCrossSpectrum(const ArraySelection * array,
                                       const SPACParameters * param)
      : ArrayCrossSpectrum(array, param), _stationPairs(array)
  {
    setStations(array);
    _rings=_stationPairs.rings(parameters());
    resize();
  }

  SPACCrossSpectrum::~SPACCrossSpectrum()
  {
    TRACE;
  }

  void SPACCrossSpectrum::resize()
  {
    switch (_mode) {
    case ArrayStations::ThreeComponents:
      _love.resize(2*_stations.count());
      break;
    case ArrayStations::Horizontal:
      ASSERT(false);
    case ArrayStations::Vertical:
      break;
    }
    _rayleigh.resize(_stations.count());
  }

  bool SPACCrossSpectrum::calculate(const QVector<int>& blocks)
  {
    TRACE;
    if(_mode==ArrayStations::ThreeComponents) {
      resetLove();
    }
    resetRayleigh();

    for(QVector<int>::const_iterator it=blocks.begin(); it!=blocks.end(); it++) {
      if(lockTimeWindow(_timeWindows->list().at(*it), _timeWindows->plan())) {
        if(_mode==ArrayStations::ThreeComponents) {
          addHorizontalLove();
        }
        addVertical();
        unlockTimeWindow();
      }
    }

    if(_mode==ArrayStations::ThreeComponents) {
      meanLove(blocks.count());
      // Normalization is more complex than for vertical
      // TODO??
    }
    meanRayleigh(blocks.count());
    normalize(_rayleigh);

    return true;
  }

  void SPACCrossSpectrum::normalize(ComplexMatrix& covmat)
  {
    TRACE;
    int n=covmat.rowCount();
    double * diag=new double[n];
    for(int i=0; i<n; i++) {
      const Complex& c=covmat.at(i, i);
      ASSERT(c.im()<c.re()*1e-10);
      diag[i]=1.0/::sqrt(c.re());
    }
    for(int i=0; i<n; i++) {
      int j;
      for(j=0; j<i; j++) {
        covmat.at(i, j)*=diag[i]*diag[j];
      }
      covmat.at(i, i)=1.0;
      for(j++; j<n; j++) {
        covmat.at(i, j)*=diag[i]*diag[j];
      }
    }
    delete [] diag;
  }



} // namespace ArrayCore
