/***************************************************************************
**
**  This file is part of dinverdc.
**
**  dinverdc 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.
**
**  dinverdc 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: 2005-10-27
**  Copyright: 2005-2019
**    Marc Wathelet
**    Marc Wathelet (LGIT, Grenoble, France)
**
***************************************************************************/

#include <QGpCompatibility.h>
#include <QGpCoreTools.h>
#include <QGpGuiTools.h>
#include <QGpGuiWave.h>
#include <SciFigs.h>

#include "EllipticityCurveTargetWidget.h"

/*!
  Constructs a EllipticityCurveTargetWidget as a child of \a parent and widget flags set to \a fl.
  DispersionTargetWidget basically include a CurveBrowser to let the user select the
  target dispersion curves and input its current knowledge of the modal identification.
*/
EllipticityCurveTargetWidget::EllipticityCurveTargetWidget(QWidget* parent)
    : ModalCurveBrowser(parent)
{
  TRACE;
  AxisWindow * w=new AxisWindow(this);
  dock(w);
  setProxy(new EllipticityProxy);
  setWindowTitle(tr("Ellipticity target"));
  setModeType(Mode::Ellipticity);
  setPlotProxy(new EllipticityPlotProxy);
  LineLayer * l=new LineLayer(w);
  initLayer(l);
  setCurrentLayer(l);
}

EllipticityCurveTargetWidget::~EllipticityCurveTargetWidget()
{
  TRACE;
  WidgetRect::saveRect(this);
}

void EllipticityCurveTargetWidget::resizeEvent(QResizeEvent * e)
{
  TRACE;
  WidgetRect::record(this);
  ModalCurveBrowser::resizeEvent(e);
}

void EllipticityCurveTargetWidget::load()
{
  TRACE;
  MessageContext();
  QStringList fileNames=Message::getOpenFileNames(tr("Load curve to fit"),
                                                  tr("All files (*);;"
                                                     "Geopsy HV output(*.hv);;"
                                                     "na_viewer report (*.report);;"
                                                     "JSesame HV output 7 columns(*.out)" ));
  if( !fileNames.isEmpty()) {
    int curvesCount=count();
    ColumnTextParser * parser=nullptr;
    int n=fileNames.count();
    for(int i=0;i<n;i++) {
      QString fileName=fileNames.at(i);
      if(CompatInversionReport::isRightFormat(fileName) )
        loadReport(fileName);
      else {
        QFile f(fileName);
        if(f.open(QIODevice::ReadOnly) ) {
          QTextStream s(&f);
          QString str=s.readLine().trimmed();
          f.close();
          if(str=="### data used in the H/V ratio processing:" )
            loadHVJSesame(fileName);
          else if(str.startsWith( "# GEOPSY output version" ))
            loadHVGeopsy(fileName);
          else
            loadMultiColumns(fileName, i==n-1, parser);
        } else {
          Message::warning(MSG_ID, tr("Loading a H/V curve"), tr("Cannot open file %1").arg(fileName), Message::ok(), true);
        }
      }
    }
    delete parser;
    if(curvesCount==0) setLimits();
  }
}

void EllipticityCurveTargetWidget::loadReport(QString fileName)
{
  TRACE;
  CompatInversionReport report(false, fileName);
  if(report.currentEllipticity()==nullptr) {
    Message::warning(MSG_ID, tr("Loading report"),
                     tr("Report %1 contains no ellipticity curve\n").arg(fileName), Message::ok(), true);
    return ;
  }
  CompatEllipticityData * ell=report.loadEllipticityGoal();
  int nModes=report.modesCount();
  for(int i=0;i < nModes;i++ ) {
    addCurve(ell->curve(i));
  }
  delete ell;
}

void EllipticityCurveTargetWidget::loadHVJSesame(QString fileName)
{
  TRACE;
  // open values as 2 or 3 columns
  QFile f(fileName);
  if(!f.open(QIODevice::ReadOnly)) {
    Message::warning(MSG_ID, tr("Loading JSesame HV output ..."),
                     tr("Impossible to access to file %1").arg(fileName), Message::cancel(), true);
    return;
  }
  QTextStream s(&f);
  ModalCurve av,ns,ew;
  bool ok;
  FactoryPoint p;
  // TODO: code not tested with a true JSesame output file
  while(!s.atEnd()) {
    QString str=s.readLine().trimmed().simplified();
    if(str.left(1)!="#") {
      p.setX(str.section(QRegExp("[ \t]"), 0, 0).toDouble(&ok));
      if(ok) {
        av.append(p);
        ns.append(p);
        ew.append(p);
        double m, s;
        m=Angle::radiansToDegrees(std::atan(str.section(QRegExp("[ \t]"), 1, 1).toDouble(&ok)));
        if(!ok) goto error;
        s=str.section(QRegExp("[ \t]"), 4, 4).toDouble(&ok);
        if(!ok) s=1.0;
        av.last().setMean(m);
        av.last().setStddev(0.5*(m*s-m+m-m/s));
        m=Angle::radiansToDegrees(std::atan(str.section(QRegExp("[ \t]"), 2, 2).toDouble(&ok)));
        if(!ok) goto error;
        s=str.section(QRegExp("[ \t]"), 5, 5).toDouble(&ok);
        if(!ok) s=1.0;
        ns.last().setMean(m);
        ns.last().setStddev(0.5*(m*s-m+m-m/s));
        m=Angle::radiansToDegrees(std::atan(str.section(QRegExp("[ \t]"), 3, 3).toDouble(&ok)));
        if(!ok) goto error;
        s=str.section(QRegExp("[ \t]"), 6, 6).toDouble(&ok);
        if(!ok) s=1.0;
        ew.last().setMean(m);
        ew.last().setStddev(0.5*(m*s-m+m-m/s));
      }
    }
  }
  if(av.isEmpty()) {
    Message::warning(MSG_ID, tr("Loading JSesame HV output ..."),
                     tr("Empty file %1").arg(fileName), Message::cancel(), true);
    return ;
  }
  av.sort();
  ns.sort();
  ew.sort();
  av.addLog(tr("Values loaded from  JSesame HV output file %1.\n").arg(fileName));
  av.addMode(Mode(Mode::Absolute, 0));
  ns.addMode(Mode(Mode::Absolute, 0));
  ew.addMode(Mode(Mode::Absolute, 0));
  addCurve(av);
  addCurve(ns);
  addCurve(ew);
  return;
error:
  Message::wrongTextFormat(s, tr("Loading JSesame H/V output file %1").arg(fileName));
}

void EllipticityCurveTargetWidget::loadHVGeopsy(QString fileName)
{
  TRACE;
  // open values as 2 or 3 columns
  QFile f(fileName);
  if( !f.open(QIODevice::ReadOnly) ) {
    Message::warning(MSG_ID, tr("Loading Geopsy HV output ..."),
                     tr("Impossible to access to file %1").arg(fileName), Message::cancel(), true);
    return ;
  }
  QTextStream s(&f);
  ModalCurve av;
  bool ok, upDownEqual=true;
  double mean, err1, err2;
  int winCount=1;
  FactoryPoint p;
  while(!s.atEnd()) {
    QString str=s.readLine().trimmed().simplified();
    if(str.left(1)=="#") {
      if(str.section("=", 0, 0).trimmed()=="# Number of windows")
        winCount=str.section( "=", 1, 1).toInt();
    } else {
      p.setX(str.section(QRegExp( "[ \t]"), 0, 0).toDouble(&ok));
      if(ok) {
        av.append(p);
        mean=str.section(QRegExp("[ \t]"), 1, 1).toDouble(&ok);
        if(ok) {
          av.last().setMean(Angle::radiansToDegrees(std::atan(mean)));
          err1=mean/str.section(QRegExp( "[ \t]"), 2, 2).toDouble(&ok);
          if(!ok) err1=0.0;
          err2=str.section(QRegExp("[ \t]"), 3, 3).toDouble(&ok)/mean;
          if(!ok) err2=0.0;
          if(fabs(err1-err2)>1e-4) upDownEqual=false;
          av.last().setStddev(0.5*(err1+err2));
          av.last().setWeight(winCount);
          continue;
        }
        Message::wrongTextFormat(s, tr("Loading Geopsy HV output file %1").arg(fileName));
        return;
      }
   }
  }
  if(av.isEmpty()) {
    Message::warning(MSG_ID, tr("Loading Geopsy HV output ..."),
                     tr("Empty file %1").arg(fileName), Message::cancel(), true);
    return ;
  }
  if(!upDownEqual) {
    Message::warning(MSG_ID, tr("Loading Geopsy HV output ..."),
                     tr("Factor for min and max curve is not the same (prec=1e-4).\n"
                        "An arithmetic average between the two values is kept.\n"
                        "(file %1)").arg(fileName), Message::ok(), true);
  }
  av.sort();
  av.addLog(tr("Values loaded from Geopsy HV output file %1.\n").arg(fileName));
  av.addMode(Mode(Mode::Absolute, 0));
  addCurve(av);
}
