/***************************************************************************
**
**  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: 2016-08-23
**  Copyright: 2016-2019
**    Marc Wathelet (ISTerre, Grenoble, France)
**
***************************************************************************/

#include "MagnetoTelluricProxy.h"
#include "MagnetoTelluricPoint.h"

namespace QGpCoreWave {

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

    Full description of class still missing
  */

  CURVEPROXY_BASICIMPLEMENTATIONS(MagnetoTelluricProxy)

  int MagnetoTelluricProxy::yAxisColumn() const
  {
    TRACE;
    switch(_yMode) {
    case MagnetoTelluricPointOptions::ApparentResistivity:
      break;
    case MagnetoTelluricPointOptions::AbsoluteValue:
      return 5;
    case MagnetoTelluricPointOptions::PhaseDegrees:
      return 3;
    case MagnetoTelluricPointOptions::PhaseRadians:
      return 4;
    case MagnetoTelluricPointOptions::Real:
      return 6;
    case MagnetoTelluricPointOptions::Imaginary:
      return 7;
    }
    return 2;
  }

  QString MagnetoTelluricProxy::columnName(int col) const
  {
    TRACE;
    switch(col) {
    case 0: return tr("Frequency");
    case 1: return tr("Period");
    case 2: return tr("App. res.");
    case 3: return tr("Phase");
    case 4: return tr("Phase");
    case 5: return tr("Abs");
    case 6: return tr("Real");
    case 7: return tr("Imaginary");
    case 8: return tr("Skin depth");
    case 9: return tr("Stddev");
    case 10: return tr("Weight");
    default: return QString();
    }
  }

  QString MagnetoTelluricProxy::columnUnit(int col) const
  {
    TRACE;
    switch(col) {
    case 0: return tr("Hz");
    case 1: return tr("s");
    case 2: return tr("ohm m");
    case 3: return tr("degrees");
    case 4: return tr("radians");
    case 5:
    case 6:
    case 7:
    case 9:
      return tr("V/m/T");
    case 8:
      return tr("m");
    default: return QString();
    }
  }

  QString MagnetoTelluricProxy::columnTitle(int col) const
  {
    TRACE;
    switch(col) {
    case 2: return tr("Apparent Resisitivy (ohm m)");
    case 5: return tr("Impedance abs. value (1e3 V/m/T)");
    case 6: return tr("Impedance real part (1e3 V/m/T)");
    case 7: return tr("Impedance imaginary part (1e3 V/m/T)");
    default:
      break;
    }
    return CurveProxy::columnTitle(col);
  }

  QVector<int> MagnetoTelluricProxy::savedColumns() const
  {
    TRACE;
    QVector<int> l;
    l << 0 << 6 << 7 << 8 << 9;
    return l;
  }

  QVariant MagnetoTelluricProxy::columnValue(int sample, int col) const
  {
    TRACE;
    const MagnetoTelluricPoint& p=curve()[ sample ];
    switch(col) {
    case 0: return p.x();
    case 1: return 1.0/p.x();
    case 2:
      return MagnetoTelluricPointOptions::toApparentResistivity(p.x(), p.mean().abs());
    case 3:
      return p.mean().phase()*180.0/M_PI;
    case 4:
      return p.mean().phase();
    case 5:
      return p.mean().abs();
    case 6:
      return p.mean().re();
    case 7:
      return p.mean().im();
    case 8:
      return 500.0*sqrt(MagnetoTelluricPointOptions::toApparentResistivity(p.x(), p.mean().abs())/p.x());
    case 9: return p.stddev();
    case 10: return p.weight();
    default: return QVariant();
    }
  }

  void MagnetoTelluricProxy::setColumnValue(int sample, int col, const QVariant & value)
  {
    TRACE;
    MagnetoTelluricPoint& p=curve()[sample];
    Complex c=p.mean();
    switch(col) {
    case 0: p.setX(value.toDouble()); break;
    case 1: p.setX(1.0/value.toDouble()); break;
    case 2:
      c.setAbs(MagnetoTelluricPointOptions::toAbsoluteValue(p.x(), value.toDouble()));
      break;
    case 3:
      c.setPhase(value.toDouble()/180.0*M_PI);
      break;
    case 4:
      c.setPhase(value.toDouble());
      break;
    case 5:
      c.setAbs(value.toDouble());
      break;
    case 6:
      c.setRe(value.toDouble());
      break;
    case 7:
      c.setIm(value.toDouble());
      break;
    case 9: p.setStddev(value.toDouble()); break;
    case 10: p.setWeight(value.toDouble()); break;
    default: break;
    }
    p.setMean(c);
  }

  QStringList MagnetoTelluricProxy::columnFileTypes() const
  {
    TRACE;
    static QStringList types;
    if(types.isEmpty()) {
      types << tr("Frequency")                        // 1
            << tr("Period")                           // 2
            << tr("Apparent resistivity (ohm m)")     // 3
            << tr("Phase (degrees)")                  // 4
            << tr("Phase (radians)")                  // 5
            << tr("Impedance abs. value (V/m/T)")     // 6
            << tr("Impedance real part (V/m/T)")      // 7
            << tr("Impedance imaginary part (V/m/T)") // 8
            << tr("Stddev")                           // 9
            << tr("Weight");                          // 10
    }
    return types;
  }

  QVector<int> MagnetoTelluricProxy::defaultColumnFileTypes() const
  {
    TRACE;
    QVector<int> l;
    l << 1 << 7 << 8 << 9 << 10;
    return l;
  }

  bool MagnetoTelluricProxy::parse(ColumnTextIterator& it)
  {
    TRACE;
    const ColumnTextParser * parser=it.parser();
    int nColumns=parser->columnCount();
    MagnetoTelluricCurve& c=curve();
    c.clear();
    bool ok=true;
    while(!it.atEnd() && c.isEmpty()) {
      while(!it.atSectionEnd()) {
        MagnetoTelluricPoint p;
        Complex average;
        bool apparentResistivity=false;
        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:
            average.setAbs(parser->text(it.currentRow(), iCol).toDouble(&ok));
            apparentResistivity=true;
            break;
          case 4:
            average.setPhase(parser->text(it.currentRow(), iCol).toDouble(&ok)/180.0*M_PI);
            break;
          case 5:
            average.setPhase(parser->text(it.currentRow(), iCol).toDouble(&ok));
            break;
          case 6:
            average.setAbs(parser->text(it.currentRow(), iCol).toDouble(&ok));
            apparentResistivity=false;
            break;
          case 7:
            average.setRe(parser->text(it.currentRow(), iCol).toDouble(&ok));
            apparentResistivity=false;
            break;
          case 8:
            average.setIm(parser->text(it.currentRow(), iCol).toDouble(&ok));
            apparentResistivity=false;
            break;
          case 9:
            p.setStddev(parser->text(it.currentRow(), iCol).toDouble(&ok));
            break;
          case 10:
            p.setWeight(parser->text(it.currentRow(), iCol).toDouble(&ok));
            break;
         default:
            break;
          }
          if(!ok) {
            parser->errorParsingColumn(iCol, it.currentRow());
            return false;
          }
        }
        if(apparentResistivity) {
          average.setAbs(MagnetoTelluricPointOptions::toAbsoluteValue(p.x(), average.abs()));
        }
        p.setMean(average);
        c.append(p);
        it.nextRow();
      }
    }
    return true;
  }

} // namespace QGpCoreWave

