/***************************************************************************
**
**  This file is part of gpgridsearch.
**
**  gpgridsearch 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.
**
**  gpgridsearch 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: 2016-04-25
**  Copyright: 2016-2019
**    Marc Wathelet (ISTerre, Grenoble, France)
**
***************************************************************************/

#include <DinverDCCore.h>

#include "Reader.h"
#include "WorkerLoop.h"

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

  Full description of class still missing
*/

/*!
  Description of constructor still missing
*/
Reader::Reader()
{
  TRACE;
  _paramIndex=0;
  _values=0;
}

Reader::~Reader()
{
  TRACE;
  delete [] _values;
  delete _outputReport;
}

bool Reader::setOptions(int& argc, char ** argv)
{
  TRACE;
  QString paramFile;
  QString targetFile;
  QString reportFile;

  int i, j = 1;
  for (i=1; i<argc; i++) {
    QByteArray arg = argv[i];
    if (arg[0]=='-') {
      if(arg=="-param") {
        CoreApplication::checkOptionArg(i, argc, argv);
        paramFile=argv[i];
      } else if(arg=="-target") {
        CoreApplication::checkOptionArg(i, argc, argv);
        targetFile=argv[i];
      } else if(arg=="-o") {
        CoreApplication::checkOptionArg(i, argc, argv);
        reportFile=argv[i];
      } else {
        App::log(tr("bad option %1, see -help\n").arg(argv[i]) );
        return false;
      }
    } else {
      argv[j++]=argv[i];
    }
  }
  if(j<argc) {
    argv[j]=nullptr;
    argc=j;
  }

  if(paramFile.isEmpty()) {
    App::log(tr("missing parameter file\n") );
    return false;
  }
  if(targetFile.isEmpty()) {
    App::log(tr("missing target file\n") );
    return false;
  }
  if(reportFile.isEmpty()) {
    App::log(tr("missing report file\n") );
    return false;
  }

  XMLVirtualPlugin pluginParam(&_groundModel, "DispersionCurve");
  XMLDinverHeader hdrParam(&pluginParam);
  if(hdrParam.xml_restoreFile(paramFile)!=XMLClass::NoError) {
    App::log(tr("error loading parameterization file %1\n").arg(paramFile) );
    return false;
  }
  if(_groundModel.isEmpty()) {
    App::log(tr("parametrized model is empty or at least one of its profiles is missing.\n") );
    return false;
  }

  // Initialization of profiles used only for counting the number of variable parameters
  _groundModel.initFinalProfiles();
  _groundModel.toParameters(_paramSpace);
  _paramSpace.setVariableParameters();
  _values=new Curve<Point1D>[_paramSpace.variableParameterCount()];
  _paramIndex=0;

  XMLVirtualPlugin pluginTarget(&_targets, "DispersionCurve");
  XMLDinverHeader hdrTarget(&pluginTarget);
  if(hdrTarget.xml_restoreFile(targetFile)!=XMLClass::NoError) {
    App::log(tr("gpdcmisfit: error parsing target file\n") );
    return false;
  }
  _targets.validateTargets();

  if(!ReportWriter::initReport(reportFile, tr("Open report for writing"), ReportWriter::Append)) {
    return false;
  }
  _outputReport=new ReportWriter(reportFile);
  if(!_outputReport->open()) {
    App::log(tr("cannot open report file for writing\n") );
    return false;
  }

  return true;
}

/*!
  Read input for variable range and number of values: min max n
*/
bool Reader::parse(QTextStream& s)
{
  TRACE;
  QString buf;
  while(!s.atEnd()) {
    buf=s.readLine();
    if(!buf.isEmpty() && buf[0]!='\n' && buf[0]!='#') {
      LineParser lp(buf);
      if(_paramIndex>=_paramSpace.variableParameterCount()) {
        App::log(tr("More parameter specifications than variable parameters in .param file\n") );
        return false;
      }
      bool ok=true;
      double min=lp.toDouble(0, ok);
      double max=lp.toDouble(1, ok);
      int n=lp.toInt(2, ok);
      if(ok) {
        Curve<Point1D>& c=_values[_paramIndex];
        c.line(min, max);
        c.resample(n, min, max, LogScale);
        App::log(tr("Values for parameter '%1'\n").arg(_paramSpace.variableParameter(_paramIndex)->name()));
        App::log(c.toString()+"\n");
      } else {
        App::log(tr("bad range specification for parameter %1 (expected 'min max n')\n")
                            .arg(_paramSpace.variableParameter(_paramIndex)->name()));
        return false;
      }
      _paramIndex++;
    }
  }
  return true;
}

void Reader::run()
{
  TRACE;
  WorkerLoop loop(this);
  loop.start();
  loop.waitFinished();
}

ReportWriter * Reader::beginWriteReport() const
{
  TRACE;
  _reportMutex.lock();
  return _outputReport;
}

void Reader::endWriteReport() const
{
  TRACE;
  _reportMutex.unlock();
}
