/***************************************************************************
**
**  This file is part of QGpCoreWave.
**
**  This library is free software; you can redistribute it and/or
**  modify it under the terms of the GNU Lesser General Public
**  License as published by the Free Software Foundation; either
**  version 2.1 of the License, or (at your option) any later version.
**
**  This file 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 Lesser General Public
**  License for more details.
**
**  You should have received a copy of the GNU Lesser General Public
**  License along with this library; if not, write to the Free Software
**  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
**
**  See http://www.geopsy.org for more information.
**
**  Created: 2006-09-25
**  Copyright: 2006-2019
**    Marc Wathelet
**    Marc Wathelet (LGIT, Grenoble, France)
**
***************************************************************************/

#include "ModalStorage.h"

namespace QGpCoreWave {

/*!
  \class ModalStorage ModalStorage.h
  \brief Storage for modal computation
 
  Storage for modal computation such as dispersion curve, ellipticity or spac
*/

/*!
  Init a empty storage. Use set() before using this object.
*/
ModalStorage::ModalStorage()
{
  TRACE;
  _nModes=0;
  _nX=0;
  _values=nullptr;
  _x=nullptr;
}

/*!
  \fn ModalStorage::ModalStorage(int nModes, const QVector<double> * x)
  Init storage with \a nModes and with the list of x \a o (not owned by this object)
*/

/*!
  Init storage with \a nModes and with the list of x \a o (not owned by this object)
*/
void ModalStorage::set(int nModes, const QVector<double> * x)
{
  TRACE;
  _nModes=nModes;
  _nX=x->count();
  _values=new RealValue [ _nModes * _nX ];
  _x=x;
}
/*!
  \fn ModalStorage::~ModalStorage()
  Delete stored values but not the list of x provided in constructor's arguments
*/

/*!
  Copy operator, only list of x remains shared.
*/
ModalStorage& ModalStorage::operator=(const ModalStorage& o)
{
  TRACE;
  _nModes=o._nModes;
  _nX=o._nX;
  _x=o._x;
  int nValues=_nModes*_nX;
  delete [] _values;
  _values=new RealValue[nValues];
  memcpy (_values, o._values, nValues*sizeof(RealValue));
  return *this;
}

/*!
  Transforms all values into their log10.
*/
void ModalStorage::log10()
{
  int nValues=_nModes * _nX;
  for(int i=0; i<nValues; i++) {
    _values[i].log10();
  }
  for(RefineList::iterator it=_refines.begin(); it!=_refines.end(); it++) {
    for(int i=0; i<_nModes; i++) {
      it->setValue(i, ::log10(it->value(i).value()));
    }
  }
}

/*!
  Transforms all values into their exp10
*/
void ModalStorage::exp10()
{
  int nValues=_nModes * _nX;
  for(int i=0; i<nValues;i++) {
    _values[i].exp10();
  }
  for(RefineList::iterator it=_refines.begin(); it!=_refines.end(); it++) {
    for(int i=0; i<_nModes; i++) {
      it->setValue(i, ::pow(10.0, it->value(i).value()));
    }
  }
}

/*!
  Transforms all values into their absolute value
*/
void ModalStorage::abs()
{
  int nValues=_nModes * _nX;
  for(int i=0; i<nValues;i++) {
    _values[i].abs();
  }
  for(RefineList::iterator it=_refines.begin(); it!=_refines.end(); it++) {
    for(int i=0; i<_nModes; i++) {
      it->setValue(i, ::fabs(it->value(i).value()));
    }
  }
}

/*!
  Transforms all values into their atan value (rad).
*/
void ModalStorage::atanRad()
{
  int nValues=_nModes * _nX;
  for(int i=0; i<nValues;i++) {
    _values[i].atanRad();
  }
  for(RefineList::iterator it=_refines.begin(); it!=_refines.end(); it++) {
    for(int i=0; i<_nModes; i++) {
      it->setValue(i, ::atan(it->value(i).value()));
    }
  }
}
/*!
  Transforms all values into their atan value (deg).
*/
void ModalStorage::atanDeg()
{
  int nValues=_nModes * _nX;
  for(int i=0; i<nValues;i++) {
    _values[i].atanDeg();
  }
  for(RefineList::iterator it=_refines.begin(); it!=_refines.end(); it++) {
    for(int i=0; i<_nModes; i++) {
      it->setValue(i, Angle::radiansToDegrees(::atan(it->value(i).value())));
    }
  }
}

/*!
  \fn ModalStorage::iterator::iterator(const ModalStorage * s, int iMode)
  Initialize an iterator for fixed and refined values
*/

/*!
  \fn iterator& ModalStorage::iterator::operator++()
  increment iterator for fixed and refined vaues
*/

/*!
  \fn bool ModalStorage::iterator::operator!=(const ModalStorage::iterator& o) const
  Compare two iterators
*/

/*!
  \fn ModalStorage::iterator::x() const
  Return current x
*/

/*!
  \fn Value& ModalStorage::iterator::value()
  Return current value
*/

/*!
  Output to stream \a s, mixing refines and original samples, removing invalid values.
  If \a modeIndex is negative, all modes are ouput.
*/
void ModalStorage::toStream( QTextStream& s, int modeIndex, const QString& comments) const
{
  TRACE;
  static const QString fmt("%1 %2\n");
  double xFactor=0.5/M_PI;
  for (int im=0; im<_nModes; im++) {
    if(modeIndex<0 || im==modeIndex) {
      s << comments;
      s << "# Mode " << im << "\n";
      for (Iterator it(this, im); !it.atEnd(); ++it) {
        const RealValue& val=it.value();
        if (val.isValid())
          s << fmt.arg(it.x()*xFactor, 0, 'g', 15).arg(val.value(), 0, 'g', 15);
      }
    }
  }
}

/*!
  Return a curve for mode \a iMode, mixing refines and original samples, removing invalid values
*/
Curve<Point2D> ModalStorage::curve(int iMode) const
{
  double xFactor=0.5/M_PI;
  Curve<Point2D> points;
  for(Iterator it(this, iMode); !it.atEnd(); ++it) {
    const RealValue & val=it.value();
    if(val.isValid())
      points.append(Point2D( it.x() * xFactor, val.value()) );
  }
  return points;
}


/*!
  Save all to report (including frequency), mixing refines and original samples, removing invalid values

  Begin with a table of the number of samples per mode

  4                 nm Modes
  For each mode:
  4                 number of samples for this mode mode, nx[im]
  nx[im]*2*8        values x,y
*/
void ModalStorage::writeReport(QDataStream& s) const
{
  TRACE;
  double xFactor=0.5/M_PI;
  s << _nModes;
  for(int im=0; im < _nModes;im++ ) {
    // room for sample per mode table
    int xCountReal=0;
    qint64 nSamplesPos=s.device() ->pos();
    s << xCountReal;
    for(Iterator it(this, im); !it.atEnd(); ++it) {
      const RealValue & val=it.value();
      if(val.isValid()) {
        s << it.x() * xFactor << val.value();
        xCountReal++;
      }
    }
    // Write the real number of x at the beginning
    qint64 curPos=s.device() ->pos();
    s.device() ->seek(nSamplesPos);
    s << xCountReal;
    s.device() ->seek(curPos);
  }
}

} // namespace QGpCoreWave
