/***************************************************************************
**
**  This file is part of geopsy-fk.
**
**  geopsy-fk 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.
**
**  geopsy-fk 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: 2017-09-07
**  Copyright: 2017-2019
**    Marc Wathelet (ISTerre, Grenoble, France)
**
***************************************************************************/

#include <ArrayCore.h>

#include "geopsy-fkVersion.h"
#include "geopsy-fkInstallPath.h"

PACKAGE_INFO("geopsy-fk", GEOPSY_FK)

ApplicationHelp * help();

bool preOptions(int argc, char ** argv, FKParameters * param)
{
  double refineRange=0.1;
  int i, j = 1;
  for (i=1; i<argc; i++) {
    QByteArray arg = argv[i];
    if (arg[0]=='-') {
      if(arg=="-refine") {
        CoreApplication::checkOptionArg(i, argc, argv);
        QFile f(argv[i]);
        if(f.open(QIODevice::ReadOnly)) {
          QTextStream s(&f);
          Curve<Point2D> dc;
          dc.fromStream(s);
          param->setRefineGridIndex(0); // Rayleigh only, under testing
          for(Curve<Point2D>::iterator it=dc.begin(); it!=dc.end(); it++) {
            param->addCurveRefine(it->x(), it->y()*(1.0-refineRange), it->y()*(1.0+refineRange));
          }
        } else {
          App::log(tr("Cannot open file '%1'\n") );
          return false;
        }
      } else if(arg=="-refine-range") {
        CoreApplication::checkOptionArg(i, argc, argv);
        refineRange=atof(argv[i]);
      } else {
        argv[j++]=argv[i];
      }
    } else {
      argv[j++]=argv[i];
    }
  }
  return true;
}

bool postOptions(int& argc, char ** argv, FKParameters * param, CoreToolInterface& gti)
{
  int i, j=1;
  for (i=1; i<argc; i++) {
    QByteArray arg=argv[i];
    if (arg[0]=='-') {
      if(arg=="-param-example") {
        if(CoreApplication::checkOptionArg(i, argc, argv, false)) {
          if(!param->setProcessType(argv[i])) {
            App::log(tr("Unrecognized process type '%1'\n").arg(argv[i]));
            return false;
          }
          if(gti.groups().isEmpty()) {
            param->setDefaultValues(param->processType(), param->inversionMethod(), ArrayStations::Vertical);
          } else {
            SubSignalPool array=gti.subPool(gti.groups().first());
            FKTool tool;
            if(!tool.setSubPool(&array)) {
              App::log(tr("Error initializing group '%1'\n").arg(array.name()));
              return false;
            }
            param->setDefaultValues(param->processType(), param->inversionMethod(), tool.array()->mode());
          }
        }
        QTextStream(stdout) << param->AbstractParameters::toString()
                            << param->toString();
        ::exit(0);
      } else {
        argv[j++]=argv[i];
      }
    } else {
      argv[j++]=argv[i];
    }
  }
  argc=j;
  return true;
}

int main(int argc, char ** argv)
{
  CoreApplication a(argc, argv, help);
  // No plugins are loaded, TODO: pre-parse options to activate plugins
  GeopsyCoreEngine gp(false);
  skipOpenBlasMultiThreading();

  FKParameters * param=new FKParameters;
  CoreToolInterface gti;
  gti.setParameters(param);
  if(!preOptions(argc, argv, param)) {
    return 2;
  }
  if(!gti.setOptions(argc, argv)) {
    return 2;
  }
  if(!postOptions(argc, argv, param, gti)) {
    return 2;
  }
  if(!CoreApplication::checkRemainingArgs(argc, argv)) {
    return 2;
  }
  if(!gti.outputBaseName().isEmpty()) {
    param->setOutputBaseName(gti.outputBaseName());
  }
  if(param->outputBaseName().isEmpty()) {
    param->setOutputBaseName("a-");
  }
  QList<const AbstractSignalGroup *>::const_iterator it;
  for(it=gti.groups().begin(); it!=gti.groups().end(); it++) {
    FKTool tool;
    const AbstractSignalGroup * group=*it;
    SubSignalPool array=gti.subPool(group);
    if(!tool.setSubPool(&array)) {
      App::log(tr("Error initializing group '%1'\n").arg(array.name()));
      return 2;
    }
    // Set default values according to the available components and processing type
    param->setDefaultValues(param->processType(), param->inversionMethod(),tool.array()->mode());
    // Force values set by the user
    param->setValues(*param);
    if(!tool.setParameters(*param)) {
      tool.waitFinished();
      // K max solver not properly deleted without a event loop...
      return 2;
    }
    tool.start();
    tool.waitFinished();
    if(param->outputBaseName().endsWith(".max")) {
      tool.results()->save(param->outputBaseName());
    } else {
      tool.results()->save(param->outputBaseName()+group->name());
    }
    gp.cache()->free(); // Avoid to keep all signals from all groups in memory
  }
  return 0;
}

ApplicationHelp * help()
{
  TRACE;
  ApplicationHelp * h=new ApplicationHelp;
  h->setOptionSummary( "[OPTIONS]");
  h->setComments("Calculate FK for ambient vibrations and active sources.");
  h->addGroup("geopsy-fk", "geopsy-fk");
  h->addOption("-refine <DC>","Accept only samples around DC curve (frequency-slowness).");
  h->addOption("-refine-range <RANGE>","Adjust relative range for the refine DC (default=0.1).");
  h->addOption("-param-example <PROCESS>","Output default parameters, template to build a new parameter file.\n"
                                          "If PROCESS is provided, default values are optimized for PROCESS type.\n"
                                          "Accepted values for PROCESS are those for PROCESS_TYPE parameter.");
  CoreToolInterface::setHelp(h);
  return h;
}
