/***************************************************************************
**
**  This file is part of gpcurve.
**
**  gpcurve 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.
**
**  gpcurve 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: 2008-06-26
**  Copyright: 2008-2019
**    Marc Wathelet
**    Marc Wathelet (LGIT, Grenoble, France)
**
***************************************************************************/

#include <QGpCoreTools.h>
#include "CurveReader.h"
#include "gpcurveVersion.h"
#include "gpcurveInstallPath.h"

PACKAGE_INFO("gpcurve", GPCURVE)

ApplicationHelp * help();

int main(int argc, char ** argv)
{
  CoreApplication a(argc, argv, help);
  a.debugUserInterrupts(false);

  // Options
  CurveReader reader;
  if(reader.setOptions(argc, argv)) {
    if(reader.isFunctionMode()) {
      reader.generateFunction();
      return 0;
    } else if(reader.read(argc, argv)) {
      return reader.terminate() ? 0 : 2;
    } else {
      return 2;
    }
  } else {
    return 2;
  }
}

ApplicationHelp * help()
{
  TRACE;
  ApplicationHelp * h=new ApplicationHelp;
  h->setOptionSummary( "[OPTIONS]" );
  h->setComments( "Manipulation of curve given through stdin. The same operations are applied to all curves. "
                  "Various curves are separated by blank lines or comments('#'). There can be as many column as "
                  "given by option '-columns'. Other columns are ignored." );
  h->addGroup("Mutli-column operations", "multi");
  h->addOption("-resample <N>", "Resample curves. N is the number of output samples. If MIN is -std::numeric_limits<double>::infinity(), the minimum "
               "X of curve are kept (same for MAX).");
  h->addOption("-resample-ext <N>", "Same as -resample except that limits of curves are extrapolated");
  h->addOption("-set <REF>", "Output the curve contains in REF with values ");
  h->addOption("-cut", "Cut curves, remove all sample outside MIN and MAX. It does not interpole values at both ends "
               "if MIN and MAX does not fit with a sample");
  h->addOption("-cut-int", "Same as -cut except that it interpoles values at both ends if MIN and MAX does not fit "
               "with a sample");
  h->addOption("-value <X>", "Return the interpolated value at X");
  h->addOption("-merge-replace <REF>", "Output curves. For all matching x in curve found in REF, the values of REF are output instead.");
  h->addOption("-merge-interpolate <REF>", "Output curves together with the interpolated values of a reference curve in file REF");
  h->addOption("-split", "Split a curve made of interlaced samples");
  h->addOption("-minmax", "Output minimum and maximum curves of all input curves which must have the same sampling");
  h->addGroup("Single-column operations", "single");
  h->addOption("-column <COL>", "Set column COL as Y affected by the following options (default=1).");
  h->addOption("-swap", "Swap x and y.");
  h->addOption("-max-index", "Return sample index of maximum Y.");
  h->addOption("-max-value", "Return maximum value for Y.");
  h->addOption("-local-max", "Return sample index and the value of all local maxima for Y.");
  h->addOption("-local-max-index", "Return sample index of all local maxima for Y.");
  h->addOption("-local-max-value", "Return value of all local maxima for Y.");
  h->addOption("-local-min", "Return sample index and the value of all local minima for Y.");
  h->addOption("-local-min-index", "Return sample index of all local minima for Y.");
  h->addOption("-local-min-value", "Return value of all local minima for Y.");
  h->addOption("-min-index", "Return sample index of minimum Y.");
  h->addOption("-min-value", "Return minium value for Y.");
  h->addOption("-regression", "Output linear regression parameters.");
  h->addOption("-derivative", "Output first derivative.");
  h->addOption("-curvature", "Output curvature a each sample (except the first and the last one.");
  h->addOption("-angles", "Output the angles between samples (except the last one).");
  h->addOption("-multiply <FACTOR>", "Multiplies Y values by FACTOR.");
  h->addOption("-pow <BASE>", "Takes power of Y values with base BASE.");
  h->addOption("-log <BASE>", "Takes log of Y values with base BASE.");
  h->addOption("-extrapolate <N>", "Add N samples at the beginning and at the end extrapolation from least square regression on N first and last samples.");
  h->addGroup("Function mode", "function");
  h->addOption("-function <FUNC>", "Output values of expression FUNC from MIN to MAX, x must be the variable parameter. "
                                   "If FUNC contains 'return' then the expression is executed verbatim. Several statements "
                                   "separated by ';' are allowed. Else a single expression is evaluated. The first form with "
                                   "'return' is interesting if you want to use internal variables, for instance:\n"
                                   "  gpcurve -function \"pi=3.141592; h=2.4;return h*Math.cos(x/180*pi)\"");
  h->addOption("-min <MIN>", "Minimum X value (default=-std::numeric_limits<double>::infinity())");
  h->addOption("-max <MAX>", "Maximum X value (default=std::numeric_limits<double>::infinity())");
  h->addOption("-dx <DX>", "Sample function with DX step, starting from MIN to MAX.");
  h->addExample("gpcurve -function \"(-100.378*x+1.3236e+11)\" -min 1318609364 -max 1318609395", "Computes expression from min to max with default step.");
  h->addGroup("Resample mode", "resample");
  h->addOption("-min <MIN>", "Minimum X value (default=-std::numeric_limits<double>::infinity())");
  h->addOption("-max <MAX>", "Maximum X value (default=std::numeric_limits<double>::infinity())");
  h->addOption("-sampling <TYPE>","Defines the sampling type:\n"
                              "  inversed   regular sampling in 1/X\n"
                              "  linear     regular sampling in linear(X) (default)\n"
                              "  log        regular sampling in log(X)");
  h->addGroup("Cut mode", "cut");
  h->addOption("-min <MIN>", "Minimum X value (default=-std::numeric_limits<double>::infinity())");
  h->addOption("-max <MAX>", "Maximum X value (default=std::numeric_limits<double>::infinity())");
  h->addGroup("Split mode", "split");
  h->addOption("-max-x <X>", "Maximum distance along X axis to associate neighbor samples (factor in case of log sampling, default=1.2)");
  h->addOption("-max-err <ERR>", "Maximum relative y error of associated samples slopes considered at max-x distance (default=1e-4)");
  h->addOption("-min-count <MIN>", "Minimum number of samples in each curve segment (default=4)");
  h->addOption("-sampling <TYPE>","Defines the sampling type:\n"
                              "  inversed   regular sampling in 1/X\n"
                              "  linear     regular sampling in linear(X) (default)\n"
                              "  log        regular sampling in log(X)");
  h->addGroup("Misfit mode", "misfit");
  h->addOption("-misfit <REF>", "Calculate misfit between curves and a reference curve in file REF. "
                                "Curve are supposed to have 1 or 2 columns: mean and an optional stddev. "
                                "The type of misift computation can be set with option '-misfit-type'.");
  h->addOption("-misfit-type <TYPE>", "TYPE can take the following values:\n"
                                      "  L1                        L1 norm.\n"
                                      "  L1_Normalized             L1 norm normalized by mean value or stddev if available.\n"
                                      "  L1_LogNormalized          L1 norm normalized by log(mean value) or log(stddev) if available.\n"
                                      "  L1_NormalizedBySigmaOnly  L1 norm normalized by stddev if available (if not, no normalization).\n"
                                      "  RMS                       Root mean square (compared to L2, the sum of squares is divided by N.\n"
                                      "  L2                        L2 norm.\n"
                                      "  L2_Normalized             L2 norm normalized by mean value or stddev if available.\n"
                                      "  L2_LogNormalized          L2 norm normalized by log(mean value) or log(stddev) if available.\n"
                                      "  L2_NormalizedBySigmaOnly  L2 norm normalized by stddev if available (if not, no normalization).\n"
                                      "  Akaike                    Akaike for least square estimation with normally distributed errors. "
                                                                  "Option '-misfit-dof' is required.\n"
                                      "  Akaike_Few     Akaike for least square estimation with normally distributed errors "
                                                       "and few samples compared to the degrees of freedom. "
                                                       "Option '-misfit-dof' is required.");
  h->addOption("-misfit-min <MIN>", "Minimum misfit value of misfit (on a per sample basis).");
  h->addOption("-misfit-dof <DOF>", "Number of degrees of freedom for Akaike misfits.");
  return h;
}
