/***************************************************************************
**
**  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-18
**  Copyright: 2004-2019
**    Marc Wathelet
**    Marc Wathelet (ULg, Liège, Belgium)
**    Marc Wathelet (LGIT, Grenoble, France)
**
***************************************************************************/

#ifndef PARAMLAYER_H
#define PARAMLAYER_H

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

#include "GradientProfile.h"
#include "DinverDCCoreDLLExport.h"

namespace DinverDCCore {

class ParamProfile;
class ParamGroundModel;

class DINVERDCCORE_EXPORT ParamLayer : public XMLClass
{
  TRANSLATIONS( "ParamLayer" )
public:
  ParamLayer(const ParamLayer& o);
  ParamLayer(ParamProfile * profile, int index);
  ParamLayer(ParamProfile * profile, int index, double minValue, double maxValue, ParamProfile * linkedTo);
  ParamLayer(ParamProfile * profile, int index, double minValue, double maxValue, double minDepth, double maxDepth);
  virtual ~ParamLayer();

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

  enum Shape {Uniform, Linear, LinearIncrease, LinearDecrease, PowerLaw};
  enum GradientParameter {GradientValue, BottomValue};

  ParamProfile * profile() const {return _profile;}
  void setProfile(ParamProfile * p) {_profile=p;}

  int index() const {return _index;}
  void setIndex(int i) {_index=i;}

  QString name() const;
  QString unit() const;
  static inline QString name(QString profileShortName, int index);

  Shape shape() const {return _shape;}
  void setShape(Shape s);
  bool isUniformShape() {return _shape==Uniform;}

  GradientParameter gradientParameter() const {return _gradientParameter;}
  void setGradientParameter(GradientParameter gp) {_gradientParameter=gp;}

  void setSubLayerCount(int n) {_gradientProfile->setSubLayerCount(n);}

  const QString& linkedTo() const {return _linkedTo;}
  void setLinkedTo(const QString& l) {_linkedTo=l;}
  void setLinkedTo();
  void setPtrLink(ParamLayer * layer) {_ptrLink=layer;}
  void setLinkedDepth(bool last, ParamLayer * prev, RealSpace& ps);
  bool isLinkedTo(ParamLayer * o);

  bool isDepth() const {return _isDepth;}
  void setDepth(bool d) {_isDepth=d;}

  bool isLastParamCondition() const {return _lastParamCondition;}
  void setLastParamCondition(bool c) {_lastParamCondition= c;}

  double topMinimumValue() const {return _topMin;}
  void setTopMinimumValue(double v) {_topMin=v;}

  double topMaximumValue() const {return _topMax;}
  void setTopMaximumValue(double v) {_topMax=v;}

  double bottomMinimumValue() const {return _bottomMin;}
  void setBottomMinimumValue(double v) {_bottomMin=v;}

  double bottomMaximumValue() const {return _bottomMax;}
  void setBottomMaximumValue(double v) {_bottomMax=v;}

  double minimumDepth() const {return _dhMin;}
  void setMinimumDepth(double v) {_dhMin=v;}

  double maximumDepth() const {return _dhMax;}
  void setMaximumDepth(double v) {_dhMax=v;}

  void setTopDepthIndex(int& index);
  int topDepthIndex() const {return _topDepthIndex;}

  double fixedBottomDepth() const;
  void setFinalDepths(double& z);
  void setFinalProfileDepthsParam(Profile& profile, double & z);
  void setFinalProfileDepthsCondition(Profile& min, Profile& max, double & z);
  void setFinalProfileValuesParam(Profile& profile);
  void setFinalProfileValuesCondition(Profile& min, Profile& max);

  bool valueParameters(RealSpace& ps, const ParamGroundModel * groundModel);
  bool depthParameters(bool last, ParamLayer * prev, RealSpace& ps, const ParamGroundModel * groundModel);
  bool valueConditions(RealSpace& ps);
  void collectValueParameters(QList<Parameter *>& params) const;

  Parameter * topParam() const {return _topP;}
  Parameter * gradientParam() const {return _gradientP;}
  Parameter * bottomParam() const {return _bottomP;}
  Parameter * dhParam() const {return _dhP;}

  const GradientProfile& gradientProfile() const {return *_gradientProfile;}
private:
  double fixedThickness(ParamLayer *& ref);
  void setFinalProfileValuesGradient(Profile& profile, double topV, double gradientV);
  void setFinalProfileValuesBottom(Profile& profile, double topV, double bottomV);
  bool addGradientParameter(RealSpace& ps, const ParamGroundModel * groundModel, double minValue, double maxValue);

  ParamProfile * _profile;
  int _index;
  Shape _shape;
  GradientParameter _gradientParameter;
  double _topMin, _topMax, _bottomMin, _bottomMax;

  bool _lastParamCondition;

  QString _linkedTo;
  ParamLayer * _ptrLink;
  bool _isDepth;
  double _dhMin, _dhMax;

  Parameter * _topP, * _gradientP, * _bottomP, * _dhP;
  int _topDepthIndex;
  GradientProfile * _gradientProfile;
protected:
  virtual void xml_writeProperties(XML_WRITEPROPERTIES_ARGS) const;
  virtual XMLMember xml_member(XML_MEMBER_ARGS);
  virtual bool xml_setProperty(XML_SETPROPERTY_ARGS);
private:
  void initParameters();
};

inline QString ParamLayer::name(QString profileShortName, int index)
{
  TRACE;
  return profileShortName+QString::number(index);
}


} // namespace DinverDCCore

#endif // PARAMLAYER_H
