/***************************************************************************
**
**  This file is part of gpell.
**
**  gpell 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.
**
**  gpell 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-12-15
**  Copyright: 2008-2019
**    Marc Wathelet
**    Marc Wathelet (LGIT, Grenoble, France)
**
***************************************************************************/

#include <QGpCoreTools.h>
#include <QGpCoreWave.h>
#include "EllipticityReader.h"

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

  Full description of class still missing
*/

/*!
  Description of constructor still missing
*/
EllipticityReader::EllipticityReader()
    : ArgumentStdinReader()
{
  TRACE;
  _nRayleigh=1;
  _sampling.setType(SamplingParameters::Log);
  _sampling.setRange(0.2, 20.0);
  _sampling.setStep(1.025);
  _outputCurves=true;
  _calculatePeaks=false;
  _abs=false;
  _angleDeg=false;
  _angleRad=false;
  _oneMode=false;
  _love=0.0;
  _halfSpaceIndex=-1;
  _plot=false;
}

bool EllipticityReader::setOptions(int& argc, char ** argv)
{
  TRACE;
  // Check arguments
  int i, j=1;
  for(i=1; i<argc; i++) {
    QByteArray arg=argv[i];
    if(arg[0]=='-') {
      if(arg=="-R") {
        CoreApplication::checkOptionArg(i, argc, argv);
        _nRayleigh=atoi(argv[i]);
      } else if (arg=="-one-mode") {
        _oneMode=true;
      } else if(arg=="-abs") {
        _abs=true;
      } else if(arg=="-angle" || arg=="-angle-deg") {
        _angleDeg=true;
        _angleRad=false;
      } else if(arg=="-angle-rad") {
        _angleRad=true;
        _angleDeg=false;
      } else if(arg=="-plot") {
        _plot=true;
      } else if(arg=="-love") {
        CoreApplication::checkOptionArg(i, argc, argv);
        _love=atof(argv[i]);
        if(_love<0.0 || _love>=1.0) {
          App::log(tr("gpell: Love contribution must be between 0 and 1\n") );
          return false;
        }
      } else if(arg=="-s") {
        CoreApplication::checkOptionArg(i, argc, argv);
        _sampling.setType(argv[i]);
      } else if(arg=="-min") {
        CoreApplication::checkOptionArg(i, argc, argv);
        _sampling.setMinimum(atof(argv[i]));
      } else if(arg=="-max") {
        CoreApplication::checkOptionArg(i, argc, argv);
        _sampling.setMaximum(atof(argv[i]));
      } else if(arg=="-step") {
        CoreApplication::checkOptionArg(i, argc, argv);
        _sampling.setStep(atof(argv[i]));
      } else if(arg=="-n") {
        CoreApplication::checkOptionArg(i, argc, argv);
        _sampling.setCount(atoi(argv[i]));
      } else if(arg=="-p") {
        _calculatePeaks=true;
        _outputCurves=false;
      } else if(arg=="-c") {
        _calculatePeaks=false;
        _outputCurves=true;
      } else if(arg=="-pc") {
        _calculatePeaks=true;
        _outputCurves=true;
      } else if(arg=="-half-space") {
        CoreApplication::checkOptionArg(i, argc, argv);
        _halfSpaceIndex=atoi(argv[i]);
        _nRayleigh=0;
      } else {
        App::log(tr("gpell: bad option %1, see -help\n").arg(argv[i]) );
        return false;
      }
    } else {
      argv[j++]=argv[i];
    }
  }
  if(j < argc) {
    argv[j]=nullptr;
    argc=j;
  }
  // Common sampling scale
  _x=_sampling.values();
  // convert to angular frequency
  for(int i=_x.count()-1; i>=0; i--) {
    _x[i]*=2.0*M_PI;
  }
  return true;
}

bool EllipticityReader::parse(QTextStream& s)
{
  TRACE;
  QTextStream sOut(stdout);
  Seismic1DModel m;
  QString comments;
  if(!m.fromStream(s, &comments)) {
    return false;
  }
  if(m.layerCount()>0) {
    if(_nRayleigh>0) {
      Rayleigh rayleigh(&m);
      Dispersion dispersion (_nRayleigh, &_x);
      // 2017-06-23 : Noticed that with 1e-12, we reach the maximum Neville iterations
      //              The current slowness get corrupted with NaN and the process never stops.
      //              With 1e-12 the solver precision is set to 1e-15, probably entering into
      //              trouble with double number representation.
      dispersion.setPrecision(1e-10);
      Ellipticity ell(_nRayleigh, &_x);
      // TODO: take errors into consideration
      if(!dispersion.calculate(&rayleigh, &ell)) {
        App::log(tr("Error computing ellipticity curve (eventually increase verbosity to debug)\n") );
        return false;
      }
      QList<double> * peaks=new QList<double>[_nRayleigh];
      if(_calculatePeaks) {
        for(int im=0; im<_nRayleigh; im++) {
          peaks[im]=ell.peaks(im, dispersion, &rayleigh);
        }
      }
      if(_abs) {
        ell.abs();
        if(_love>0.0) {
          ell.addLove(_love/(1.0-_love));
        }
      }
      if(_angleRad) {
        ell.atanRad();
      } else if(_angleDeg) {
        ell.atanDeg();
      }
      if(_outputCurves) {
        sOut << QString("# %1 Rayleigh ellipticity mode(s)\n").arg(_nRayleigh);
        if(_plot) {
          double signThreshold=2.0;
          if(_angleRad) {
            signThreshold=::atan(signThreshold);
          } else if(_angleDeg) {
            signThreshold=Angle::radiansToDegrees(::atan(signThreshold));
          }
          ell.toStream(sOut, _oneMode ? _nRayleigh-1 : -1, comments, signThreshold);
        } else {
          ell.toStream(sOut, _oneMode ? _nRayleigh-1 : -1, comments);
        }
      } else {
        sOut << comments;
        for(int im=0; im < _nRayleigh; im++ ) {
          sOut << "# Mode " << im << "\n";
          for(int ip=0; ip < peaks[im].count(); ip++ ) {
            sOut << peaks[im][ip] << "\n";
          }
        }
      }
      delete [] peaks;
    } else if(_halfSpaceIndex>=0) {
      if(_halfSpaceIndex<m.layerCount()) {
        Complex e=m.halfSpaceEllipticity(_halfSpaceIndex);
        sOut << QString("(%1)+i*(%2) abs=%3 (%5 deg.) phi=%4")
                .arg(e.re())
                .arg(e.im())
                .arg(e.abs())
                .arg(Angle::radiansToDegrees(e.phase()))
                .arg(Angle::radiansToDegrees(atan(e.abs()))) << "\n";
      } else {
        App::log(tr("gpell: half-space index out of range\n") );
        return false;
      }
    }
  }
  return true;
}
