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

#include <SciFigs.h>
#include <QGpCoreMath.h>

#include "HistogramWidget.h"
#include "gphistogramVersion.h"
#include "gphistogramInstallPath.h"
#include "GaussianMixtureOutput.h"

PACKAGE_INFO("gphistogram", GPHISTOGRAM)

ApplicationHelp * help();

HistogramWidget * createWidgets(const HistogramReader& reader, Histogram2D * hist)
{
  HistogramWidget * w=new HistogramWidget;
  w->setNormalize(reader.isNormalized());
  w->setHistogram(hist);
  w->setHistogramComments(reader.fileNames().join(";"));
  if(!reader.curveFileNames().isEmpty()) {
    if(!w->loadCurves(reader.curveFileNames(), reader.curveFormatFileName())) {
      delete w;
      return nullptr;
    }
  }
  return w;
}

int main(int argc, char ** argv)
{
  Application a(argc, argv, help);

  // Options
  ExportOptions exportOptions;
  HistogramReader reader;
  if(!reader.setOptions(argc, argv)) {
    return 2;
  }
  if(!exportOptions.read(argc, argv)) {
    return 2;
  }
  if(!CoreApplication::checkRemainingArgs(argc, argv)) {
    return 2;
  }
  if(!reader.read(argc, argv, reader.ignoreStdin())) {
    return 2;
  }
  if(reader.isEmpty()) {
    if(!reader.read(Message::getOpenFileNames(tr("Open data file"),
                                              tr("All files (*);;"
                                                 "Max files (*.max)")))) {
      return 2;
    }
  }
  if(!reader.setDefaultLimits()) {
    return 2;
  }
  Histogram2D * hist=reader.histogram();
  if(!hist) {
    App::log(tr("Error building histogram, check input data/parameters\n"));
    return 2;
  }

  int appReturn;
  SAFE_UNINITIALIZED(appReturn,0)
  QTextStream sOut(stdout);
  switch (reader.action()) {
  case HistogramReader::Gui: {
      SciFigsGlobal s;
      HistogramWidget * w=createWidgets(reader, hist);
      if(!w) {
        return 2;
      }
      w->exportPlot(exportOptions);
      w->setGaussianMixtureParameters(reader.gaussianMixtureParameters());
      w->setHeaderLine(reader.headerLine());
      if(reader.fileNames().count()==1) {
        QFileInfo fi(reader.fileNames().first());
        w->setWindowTitle(fi.fileName()+" - gphistogram");
      }
      w->show();
      appReturn=a.exec();
      delete w;
    }
    break;
  case HistogramReader::Plot: {
      SciFigsGlobal s;
      HistogramWidget * w=createWidgets(reader, hist);
      if(!w) {
        return 2;
      }
      w->exportPlot(exportOptions);
      appReturn=0;
      delete w;
    }
    break;
  case HistogramReader::Mean: {
      sOut << "# Mean curve\n"
           << hist->meanCurve().toString();
      appReturn=0;
    }
    break;
  case HistogramReader::Median: {
      sOut << "# Median curve\n"
           << hist->medianCurve().toString();
      appReturn=0;
    }
    break;
  case HistogramReader::Mode: {
      sOut << "# Mode curve\n"
           << hist->modeCurve().toString();
      appReturn=0;
    }
    break;
  case HistogramReader::GaussMix: {
      GaussianMixtureOutput gmo;
      HistogramDensities d;
      d.setHistogram(hist);
      gmo.setHistogramDensities(&d);
      d.setParameters(reader.gaussianMixtureParameters());
      gmo.connect(&d, SIGNAL(histogramFinished(int)), &gmo, SLOT(newValues(int)));
      d.start();
      d.wait();
      appReturn=0;
    }
    break;
  case HistogramReader::Grid: {
      sOut << "# Grid values\n";
      sOut << *hist;
      appReturn=0;
    }
    break;
  case HistogramReader::Max: {
      hist->save(reader.exportMaxFileName(), reader.headerLine());
      appReturn=0;
    }
    break;
  }
  delete hist;
  return appReturn;
}

ApplicationHelp * help()
{
  TRACE;
  ApplicationHelp * h=new ApplicationHelp;
  h->setOptionSummary( "[OPTIONS] <FILE>..." );
  h->setComments( "From two columns (x, y) provided through stdin or FILE, it produces a grid and count the number of hits in each cell. "
                  "A median or mean curve can be directly computed or the histogram is plotted. Editing and filtering is then possible." );
  h->addGroup("Data", "data");
  h->addOption("-p, -pattern <PATTERN>", "Read only lines containing PATTERN. PATTERN is not a regular expression. See examples for useful tricks.");
  h->addOption("-no-normalize", "Do not normalize histograms.");
  h->addOption("-stdin", "Read data from stdin (default=no).");
  h->addGroup("Output", "output");
  h->addOption("-mean", "Output mean curve and exit.");
  h->addOption("-median", "Output median curve and exit.");
  h->addOption("-mode", "Output mode curve and exit.");
  h->addOption("-gauss-mix", "Output gaussian mixture curve and exit.");
  h->addOption("-plot", "Export plot (see '-h plot' for options).");
  h->addOption("-grid", "Output grid values and exit.");
  h->addOption("-max <FILE>", "Output filter max values and exit.");
  HistogramReader::helpCurves(h);
  HistogramReader::helpX(h);
  HistogramReader::helpY(h);
  h->addGroup("Valid values", "valid");
  h->addOption("-valid-column","Column index containing valid flag (0 is the first).");
  h->addOption("-ignore-valid","Ignore valid flag for standard formats (.max)");
  h->addGroup("Max", "max");
  h->addOption("-rel-power <R>", "For .max files, accept only samples with power > R*maximum power (over a time window and for a frequency).");
  h->addOption("-max-noise <R>", "For .max files, accept only samples with relative incoherent noise < R.");
  h->addOption("-s-f", "For .max files, plot slowness versus frequency (default).");
  h->addOption("-azimuth", "For .max files, plot azimuth.");
  h->addOption("-ell", "For .max files, plot signed ellipticity.");
  h->addOption("-ell-abs", "For .max files, plot absolute value of ellipticity.");
  h->addOption("-ell-deg", "For .max files, plot ellipticity angle in deg.");
  h->addOption("-ell-inv-deg", "For .max files, plot ellipticity angle in deg with the opposite sign (for downwards vertical components).");
  h->addOption("-ell-rad", "For .max files, plot ellipticity angle in rad.");
  h->addOption("-ell-inv-rad", "For .max files, plot ellipticity angle in rad with the opposite sign (for downwards vertical components).");
  h->addOption("-noise", "For .max files, plot the ratio of incoherent noise over coherent signal.");
  h->addOption("-s-k", "For .max files, plot slowness versus wave number.");
  h->addOption("-s-l", "For .max files, plot slowness versus wave length.");
  h->addOption("-s-p", "For .max files, plot slowness versus period.");
  h->addOption("-k-f", "For .max files, plot wave number versus frequency.");
  h->addOption("-l-f", "For .max files, plot wave length versus frequency.");
  h->addGroup("Gaussian Mixture", "gaussmix");
  h->addOption("-gm-type <T>", "Inversion type can be: 'Full' or 'MeanOnly' (default).");
  h->addOption("-gm-count <N>","Adjust histograms with a maximum of N Gaussian densities (default=4).");
  h->addOption("-gm-relerr <ERR>", "For MeanOnly inversion, use this relative error to compute stddev (default=0.1).");
  h->addOption("-gm-abserr <ERR>", "For MeanOnly inversion, use this absolute error to compute stddev (default=0). "
                                   "If absolute error is 0, relative error is used instead.");
  h->addOption("-gm-kmin <KMIN>","Filter results between KMIN and KMAX.");
  h->addOption("-gm-kmax <KMAX>","Filter results between KMIN and KMAX.");
  h->addOption("-gm-verbose","Verbose inversion.");
  h->addGroup("Plot", "plot", 2);
  ExportOptions::help(h);
  h->addExample("gphistogram my.max -p l", "Select Radial, Rayleigh and/or Vertical for '-3C', '-H' and '-Z' max files."
                                           "'-3C' is a three-component, '-H' is an horizontal and '-Z' is a vertical max file.");
  h->addExample("gphistogram my.max -p R", "Select Radial or Rayleigh for '-3C' and '-H' max files.");
  h->addExample("gphistogram my.max -p L", "Select Love for '-3C' max files.");
  h->addExample("gphistogram my.max -p T", "Select Transverse for '-H' max files.");
  h->addExample("gphistogram my.max", "Select Vertical for '-Z' max files.");
  return h;
}
