/***************************************************************************
**
**  This file is part of QGpCoreWave.
**
**  This library is free software; you can redistribute it and/or
**  modify it under the terms of the GNU Lesser General Public
**  License as published by the Free Software Foundation; either
**  version 2.1 of the License, or (at your option) any later version.
**
**  This file 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 Lesser General Public
**  License for more details.
**
**  You should have received a copy of the GNU Lesser General Public
**  License along with this library; if not, write to the Free Software
**  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
**
**  See http://www.geopsy.org for more information.
**
**  Created: 2008-11-20
**  Copyright: 2008-2019
**    Marc Wathelet
**    Marc Wathelet (LGIT, Grenoble, France)
**
***************************************************************************/

#include <QGpCoreTools.h>
#include "RefractionFactory.h"
#include "RefractionCurve.h"
#include "RefractionDippingModel.h"
#include "TiltNode.h"

namespace QGpCoreWave {

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

  Full description of class still missing
*/

/*!
  Description of constructor still missing
*/
RefractionFactory::RefractionFactory()
{
  TRACE;
  _travelTimes=0;
}

/*!
  Description of destructor still missing
*/
RefractionFactory::~RefractionFactory()
{
  TRACE;
  delete [] _travelTimes;
}

void RefractionFactory::setX(const QList<RefractionCurve>& curves)
{
  TRACE;
  //  Gather all the sources and receivers
  _sources.clear();
  _receivers.clear();
  for(QList<RefractionCurve>::const_iterator itCurve=curves.begin(); itCurve!=curves.end(); itCurve++) {
    const RefractionCurve& curve=*itCurve;
    _sources.append(curve.source());
    for(RefractionCurve::const_iterator itRec=curve.begin(); itRec!=curve.end(); itRec++) {
      _receivers.append(itRec->x());
    }
  }
  std::sort(_sources.begin(), _sources.end());
  unique(_sources);
  std::sort(_receivers.begin(), _receivers.end());
  unique(_receivers);
  // Allocates values for storing arrival times
  _travelTimes=new RealValue[ _sources.count()*_receivers.count() ];
}

void RefractionFactory::linkX(QList<RefractionCurve>& curves) const
{
  TRACE;
  // Set references to values
  for(QList<RefractionCurve>::iterator itCurve=curves.begin(); itCurve!=curves.end(); itCurve++) {
    RefractionCurve& curve=*itCurve;
    curve.linkSource(_sources);
    curve.linkReceivers(_receivers);
  }
}

/*!

*/
bool RefractionFactory::calculate(RefractionDippingModel * model)
{
  TRACE;
  model->setXLeft(_receivers.first());
  model->setXRight(_receivers.last());
  model->begin();
  TiltNode srcNode, recNode;
  int deepestLayer;
  RealValue * values=_travelTimes;
  for(QVector<double>::const_iterator itSrc=_sources.begin(); itSrc!=_sources.end(); itSrc++) {
    srcNode.init(*itSrc, *model);
    for(QVector<double>::const_iterator itRec=_receivers.begin(); itRec!=_receivers.end(); itRec++) {
      recNode.init(*itRec,*model);
      (values++)->setValue(model->travelTime(srcNode, recNode, deepestLayer));
    }
  }
  model->end();
  return true;
}

void RefractionFactory::writeReport(QDataStream& s) const
{
  TRACE;
  int nSrc=sourceCount();
  int nRec=receiverCount();
  s << nSrc << nRec;
  for(int i=0; i < nSrc; i++ ) {
    s << _sources[i];
  }
  for(int i=0; i < nRec; i++ ) {
    s << _receivers[i];
  }
  int n=nSrc * nRec;
  for(int i=0; i < n; i++ ) {
    s << _travelTimes[i].value();
  }
}

void RefractionFactory::readReport(QDataStream& s)
{
  TRACE;
  int nSrc, nRec, n;
  s >> nSrc >> nRec;
  n=nSrc * nRec;
  _sources.resize(nSrc);
  for(int i=0; i < nSrc; i++ ) {
    s >> _sources[i];
  }
  _receivers.resize(nRec);
  for(int i=0; i < nRec; i++ ) {
    s >> _receivers[i];
  }
  double tt;
  delete _travelTimes;
  _travelTimes=new RealValue[n];
  for(int i=0; i < n; i++ ) {
    s >> tt;
    _travelTimes[i].setValue(tt);
  }
}

void RefractionFactory::toStream(int sourceIndex, QTextStream& sOut) const
{
  TRACE;
  const RealValue * tt=source(sourceIndex);
  Point2D p;
  int n=_receivers.count();
  for(int i=0; i < n; i++ ) {
    p.setX(_receivers[i] );
    p.setY(tt[i].value());
    sOut << p << "\n";
  }
  sOut << flush;
}

} // namespace QGpCoreWave
