/***************************************************************************
**
**  This file is part of DinverDCCore.
**
**  DinverDCCore 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.
**
**  DinverDCCore 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: 2004-10-21
**  Copyright: 2004-2019
**    Marc Wathelet
**    Marc Wathelet (ULg, Liège, Belgium)
**    Marc Wathelet (LGIT, Grenoble, France)
**
***************************************************************************/

#ifndef TARGETLIST_H
#define TARGETLIST_H

#include <QGpCoreTools.h>
#include <QGpCoreWave.h>
#include <DinverCore.h>

#include "DCReportBlock.h"
#include "PoissonCondition.h"
#include "ModalCurveTarget.h"
#include "DispersionTarget.h"
#include "AutocorrTarget.h"
#include "ValueTarget.h"
#include "RefractionTarget.h"
#include "MagnetoTelluricTarget.h"
#include "ParamProfile.h"
#include "DinverDCCoreDLLExport.h"

namespace DinverDCCore {

class ParamGroundModel;

class DINVERDCCORE_EXPORT TargetList : public XMLClass
{
  TRANSLATIONS("TargetList")
public:
  TargetList();
  TargetList(const TargetList& o);
  virtual ~TargetList();

  virtual const QString& xml_tagName() const {return xmlTargetListTag;}
  static const QString xmlTargetListTag;

  void setParamProfiles(ParamGroundModel * gm, RealSpace& ps);
  inline bool isPoissonRatioOk();
  inline bool isPoissonRatioOk(const GroundParameter * from);
  void setVp();
  double misfit(int nDimensions, bool& ok);
  void surfaceMisfit(double& totalMisfit, double& totalWeight,
                      Seismic1DModel * surfModel,
                      int nDimensions, bool& ok);
  void refractionMisfit(double& totalMisfit, double& totalWeight,
                         Seismic1DModel * surfModel, const QVector<double>& pitch,
                         int nDimensions, bool& ok);
  void refractionMisfit(double& totalMisfit, double& totalWeight,
                         RefractionDippingModel * tiltModel,
                         int nDimensions, bool& ok);
  void magnetoTelluricMisfit(double& totalMisfit, double& totalWeight,
                             const Resistivity1DModel * model, double staticShift,
                             int nDimensions, bool& ok);
  inline void writeReport(ReportWriter * report) const;

  ModalCurveTarget& dispersionTarget() {return _dispersionTarget;}
  const ModalCurveTarget& dispersionTarget() const {return _dispersionTarget;}

  AutocorrTarget& autocorrTarget() {return _autocorrTarget;}
  const AutocorrTarget& autocorrTarget() const {return _autocorrTarget;}

  ModalCurveTarget& ellipticityCurveTarget() {return _ellipticityCurveTarget;}
  const ModalCurveTarget& ellipticityCurveTarget() const {return _ellipticityCurveTarget;}

  ValueTarget& ellipticityPeakTarget() {return _ellipticityPeakTarget;}
  const ValueTarget& ellipticityPeakTarget() const {return _ellipticityPeakTarget;}

  RefractionTarget& refractionVpTarget() {return _refractionVpTarget;}
  const RefractionTarget& refractionVpTarget() const {return _refractionVpTarget;}

  RefractionTarget& refractionVsTarget() {return _refractionVsTarget;}
  const RefractionTarget& refractionVsTarget() const {return _refractionVsTarget;}

  MagnetoTelluricTarget& magnetoTelluricTarget() {return _magnetoTelluricTarget;}
  const MagnetoTelluricTarget& magnetoTelluricTarget() const {return _magnetoTelluricTarget;}

  const Point& position() const {return _position;}
  void setPosition(const Point& p) {_position=p;}

  void setMisfitType(MisfitType t);

  bool isEmpty() const;
  void validateTargets();
  int dispersionSampleCount() const;
  inline bool isGroundModelParameter(const Parameter * p) const;
protected:
  virtual void xml_writeProperties(XML_WRITECHILDREN_ARGS) const;
  virtual void xml_writeChildren(XML_WRITECHILDREN_ARGS) const;
  virtual XMLMember xml_member(XML_MEMBER_ARGS);
  virtual bool xml_setProperty(XML_SETPROPERTY_ARGS);
  virtual void xml_polishChild(XML_POLISHCHILD_ARGS);
  virtual bool xml_polish(XML_POLISH_ARGS);
private:
  friend class DCReportBlock;

  void initFactories();
  void initProfiles();
  void deleteFactories();
  double curveMisfit(const QList<ModalCurve>& curveList, ModalFactory& f,
                     const Target& target, int nDimensions);
  double curveMisfit(const QList<RefractionCurve>& curveList, RefractionFactory& f,
                     const Target& target, int nDimensions);
  double curveMisfit(const QList<MagnetoTelluricCurve>& curveList, MagnetoTelluricFactory& f,
                     const Target& target, int nDimensions);
  double logMisfit(const QList<ModalCurve>& curveList, ModalFactory& f,
                   const Target& target, int nDimensions);
  double determinantMisfit(const QList<ModalCurve>& curveList, Seismic1DModel * surfModel);
  double modelMisfit();
  inline bool surfaceWave() const;
  // Targets
  DispersionTarget _dispersionTarget;
  AutocorrTarget _autocorrTarget;
  ModalCurveTarget _ellipticityCurveTarget;
  ValueTarget _ellipticityPeakTarget;
  RefractionTarget _refractionVpTarget;
  RefractionTarget _refractionVsTarget;
  MagnetoTelluricTarget _magnetoTelluricTarget;

  // Computation storages
  DispersionFactory * _dispersionFactory;
  AutocorrFactory * _autocorrFactory;
  EllipticityFactory * _ellipticityFactory;
  RefractionFactory * _refractionVpFactory;
  RefractionFactory * _refractionVsFactory;
  MagnetoTelluricFactory * _magnetoTelluricFactory;

  // Ground structure
  ParamProfile * _vp, * _nu, * _vs, * _rho, * _pitch, * _res;
  Parameter * _magnetoTelluricStaticShift;
  PoissonCondition * _poissonCondition;

  // Position
  Point _position;

  Seismic1DModel * surfaceWaveModel();
};

inline bool TargetList::isGroundModelParameter(const Parameter * p) const
{
  return p!= _magnetoTelluricStaticShift;
}

inline void TargetList::writeReport(ReportWriter * report) const
{
  TRACE;
  DCReportBlock::write(report, *this,
                       _vp ? &_vp->resampledProfile() : nullptr,
                       _vs ? &_vs->resampledProfile() : nullptr,
                       _rho ? &_rho->resampledProfile() : nullptr,
                       _pitch ? &_pitch->resampledProfile() : nullptr,
                       _res ? &_res->resampledProfile() : nullptr);
}

inline bool TargetList::isPoissonRatioOk()
{
  TRACE;
  if(_poissonCondition)
    return _poissonCondition->isOk();
  else
    return true;
}

inline bool TargetList::isPoissonRatioOk(const GroundParameter * from)
{
  TRACE;
  if(_poissonCondition)
    return _poissonCondition->isOk(from);
  else
    return true;
}

} // namespace DinverDCCore

#endif // TARGETLIST_H
