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

#include <QGpCoreTools.h>
#include "Group2PhaseReader.h"

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

  Full description of class still missing
*/

/*!
  Description of constructor still missing
*/
Group2PhaseReader::Group2PhaseReader()
    : ArgumentStdinReader()
{
  TRACE;
  _mode=Group2Phase;
}

bool Group2PhaseReader::setOptions(int& argc, char ** argv)
{
  TRACE;
  // Check arguments
  int i, j=1;
  for(i=1; i<argc; i++) {
    QByteArray arg=argv[i];
    if(arg[0]=='-') {
      if(arg=="-g2p") {
        _mode=Group2Phase;
      } else if(arg=="-p2g") {
        _mode=Phase2Group;
      } else {
        App::log(tr("gpgroup2phase: bad option %1, see -help\n").arg(argv[i]) );
        return false;
      }
    } else {
      argv[j++]=argv[i];
    }
  }
  if(j < argc) {
    argv[j]=nullptr;
    argc=j;
  }
  return true;
}

bool Group2PhaseReader::parse(QTextStream& s)
{
  TRACE;
  QTextStream sOut(stdout);
  Curve<Point2D> curve;
  Point2D p;
  QString buf;
  buf=s.readLine();
  while(!s.atEnd() && (buf[0]=='\n' || buf[0]=='#')) {
    buf=s.readLine();
    _comments+=buf+"\n";
  }
  while(!s.atEnd() && buf[0]!='\n' && buf[0]!='#') {
    p.fromString(buf);
    curve.append(p);
    buf=s.readLine();
  }
  _comments+=buf+"\n";
  switch(_mode) {
  case Phase2Group:
    sOut << _comments;
    _comments.clear();
    sOut << group(curve).toString();
    break;
  case Group2Phase:
    scanCurve(curve);
    break;
  }
  return true;
}

void Group2PhaseReader::scanCurve(Curve<Point2D>& groupCurve)
{
  QTextStream sOut(stdout);
  for(double s1=0.00028; s1<0.01; s1+=0.0001) {
    for(double s2=0.00028; s2<0.01; s2+=0.0001) {
      Curve<Point2D> phaseCurve=phase(groupCurve, s1, s2);
      if(!phaseCurve.isEmpty()) {
        printf("# s1=%lg, s2=%lg\n", s1, s2);
        sOut << phaseCurve.toString();
        /*printf("# group (check) \n");
        Curve<Point2D> groupCheckCurve=group(phaseCurve);
        groupCheckCurve.toStream(stdout);
        exit(0);*/
      }
    }
  }
}

Curve<Point2D> Group2PhaseReader::phase(const Curve<Point2D>& groupCurve, double s1, double s2)
{
  Curve<Point2D> phaseCurve;
  int n=groupCurve.count();
  if(n<3) return phaseCurve;
  double x1, x2, x3, s3, sg2;
  x1=groupCurve.at(0).x();
  phaseCurve.append(Point2D(x1, s1));
  x2=groupCurve.at(1).x();
  phaseCurve.append(Point2D(x2, s2));
  sg2=groupCurve.at(1).y();
  for(int i=2;i<n;i++) {
    x3=groupCurve.at(i).x();
    s3=s2 + (x3 - x2) * (( sg2 - s2) * 2.0/x2 - (s2 - s1)/(x2 -x1) );
    sg2=groupCurve.at(i).y();
    if(s3<=0.0) {
      phaseCurve.clear();
      return phaseCurve;
    }
    phaseCurve.append(Point2D(x3, s3));
    x1=x2;
    x2=x3;
    s1=s2;
    s2=s3;
  }
  return phaseCurve;
}

Curve<Point2D> Group2PhaseReader::group(const Curve<Point2D>& phaseCurve)
{
  Curve<Point2D> groupCurve;
  int n=phaseCurve.count()-1;
  for(int i=1;i<n;i++) {
    double val=phaseCurve.at(i).y();
    double derslow=0.5*((val-phaseCurve.at(i-1).y())/(phaseCurve.at(i).x()-phaseCurve.at(i-1).x())+
                          (phaseCurve.at(i+1).y()-val)/(phaseCurve.at(i+1).x()-phaseCurve.at(i).x()));
    derslow*=phaseCurve.at(i).x();
    groupCurve.append(Point2D(phaseCurve.at(i).x(), val+derslow));
  }
  return groupCurve;
}
