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

#include <QGpCoreTools.h>

#include "DispersionProxy.h"

namespace QGpCoreWave {

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

  Full description of class still missing
*/

QString DispersionProxy::columnName(int col) const
{
  TRACE;
  switch(col) {
    case 0: return tr("Frequency");
    case 1: return tr("Period");
    case 2: return tr("Slowness");
    case 3: return tr("Velocity");
    case 4: return tr("Wave length");
    case 5: return tr("Stddev");
    case 6: return tr("Weight");
    default: return QString();
  }
}

QString DispersionProxy::columnUnit(int col) const
{
  TRACE;
  switch(col) {
    case 0: return tr("Hz");
    case 1: return tr("s");
    case 2: return tr("s/m");
    case 3: return tr("m/s");
    case 4: return tr("m");
    default: return QString();
  }
}

QVector<int> DispersionProxy::savedColumns() const
{
  TRACE;
  QVector<int> l;
  l << 0 << 2 << 5 << 6;
  return l;
}

QVariant DispersionProxy::columnValue(int sample, int col) const
{
  TRACE;
  const FactoryPoint& p=curve()[sample];
  switch(col) {
  case 0: return p.x();
  case 1: return 1.0/p.x();
  case 2: return p.mean();
  case 3: return 1.0/p.mean();
  case 4: return 1.0/(p.x()*p.mean());
  case 5: return p.stddev();
  case 6: return p.weight();
  default: return QVariant();
  }
}

void DispersionProxy::setColumnValue(int sample, int col, const QVariant & value)
{
  TRACE;
  FactoryPoint& p=curve()[sample];
  switch(col) {
  case 0: p.setX(value.toDouble()); break;
  case 1: p.setX(1.0/value.toDouble()); break;
  case 2: p.setMean(value.toDouble()); break;
  case 3: p.setMean(1.0/value.toDouble()); break;
  case 4: p.setMean(1.0/(value.toDouble()*p.x()) ); break;
  case 5: p.setStddev(value.toDouble()); break;
  case 6: p.setWeight(value.toDouble()); break;
  default: break;
  }
}

QStringList DispersionProxy::columnFileTypes() const
{
  TRACE;
  static QStringList types;
  if(types.isEmpty()) {
    types << tr("Frequency (Hz)")             // 1
          << tr("Period (s)")                 // 2
          << tr("Slowness (s/m)")             // 3
          << tr("Velocity (m/s)")             // 4
          << tr("log stddev")                 // 5
          << tr("Stddev (s/m, approx.)")      // 6
          << tr("Stddev (m/s, approx.)")      // 7
          << tr("Weight")                     // 8
          << tr("Valid");                     // 9
  }
  return types;
}

QVector<int> DispersionProxy::defaultColumnFileTypes() const
{
  TRACE;
  QVector<int> types;
  types << 1 << 3 << 5 << 8 << 9;
  return types;
}

bool DispersionProxy::parse(ColumnTextIterator& it)
{
  TRACE;
  const ColumnTextParser * parser=it.parser();
  int nColumns=parser->columnCount();
  ModalCurve& c=curve();
  c.clear();
  bool ok=true;
  while(!it.atEnd() && c.isEmpty()) {
    while(!it.atSectionEnd()) {
      FactoryPoint p;
      enum StddevType {Slowness, Velocity, Log};
      StddevType stddevType=Log;
      for(int iCol=0;iCol<nColumns;iCol++) {
        switch(parser->type(iCol)) {
        case 1:
          p.setX(parser->text(it.currentRow(), iCol).toDouble(&ok));
          break;
        case 2:
          p.setX(1.0/parser->text(it.currentRow(), iCol).toDouble(&ok));
          break;
        case 3:
          p.setMean(parser->text(it.currentRow(), iCol).toDouble(&ok));
          break;
        case 4:
          p.setMean(1.0/parser->text(it.currentRow(), iCol).toDouble(&ok));
          break;
        case 5:
          p.setStddev(parser->text(it.currentRow(), iCol).toDouble(&ok));
          break;
        case 6:
          p.setStddev(parser->text(it.currentRow(), iCol).toDouble(&ok));
          stddevType=Slowness;
          break;
        case 7:
          p.setStddev(parser->text(it.currentRow(), iCol).toDouble(&ok));
          stddevType=Velocity;
          break;
        case 8:
          p.setWeight(parser->text(it.currentRow(), iCol).toDouble(&ok));
          break;
        case 9:
          p.setValid(parser->text(it.currentRow(), iCol).toInt(&ok)==1);
          break;
       default:
          break;
        }
        if(!ok) {
          parser->errorParsingColumn(iCol, it.currentRow());
          return false;
        }
      }
      if(p.stddev()!=0.0 && p.stddev()<0.0) {
        App::log(tr("Standard deviation must be positive\n") );
      }
      switch(stddevType) {
      case Log:
        break;
      case Slowness:
        p.setStddev(0.5*((p.mean()+p.stddev())/p.mean()+p.mean()/(p.mean()-p.stddev())));
        break;
      case Velocity: {
          double v=1.0/p.mean();
          p.setStddev(0.5*((v+p.stddev())/v+v/(v-p.stddev())));
        }
        break;
      }
      c.append(p);
      it.nextRow();
    }
  }
  // For convenience add a default mode
  if(c.modes().isEmpty()) {
    c.addMode(Mode(Mode::Phase, Mode::Rayleigh, 0));
  }
  return true;
}

} // namespace QGpCoreWave
