/***************************************************************************
**
**  This file is part of DinverCore.
**
**  DinverCore 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.
**
**  DinverCore 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: 2009-05-18
**  Copyright: 2009-2019
**    Marc Wathelet
**    Marc Wathelet (LGIT, Grenoble, France)
**
***************************************************************************/

#include <QGpCoreTools.h>

#include "DinverC.h"
#include "SimpleCondition.h"

namespace DinverCore {

/*!
  \fn const char * dinver_plugin_tag()
  A short name without space and special character to identify the plugin.
  It must be unique. To get a list of plugin tag: dinver -plugin-list

  Mandatory to define it in a C++ file.
*/

/*!
  \fn const char * dinver_plugin_title()
  A brief user frienly string to identify the plugin

  Mandatory to define it in a C++ file.
*/

/*!
  \fn const char * dinver_plugin_version()
  A string containing the version of the plugin

  Mandatory to define it in a C++ file.
*/

/*!
  \fn const char * dinver_plugin_description()
  A (long) user frienly string to describe the plugin. It can be a html string.

  Mandatory to define it in a C++ file.
*/

/*!
  \fn void dinver_init_global()
  Initialize global variables. If you share global variables between inversion runs and if
  runs can modify these global variables, you must be careful of correctly lock ressources.
  If you want to avoid such problems, make sure than common variables are written only during
  initialization or do not start more than one run at a time inside dinver.

  Mandatory to define it.
*/

/*!
  \fn void dinver_init_run(DinverForward forward)
  Initialize the run: create parameters and conditions. Optionaly, you can set \a data to
  point to a structure used by

  Mandatory to define it.
*/

/*!
  \fn void dinver_forward(int nd, float * model, bool * ok, float * misfit)
  Compute \a misfit from \a model parameters. Set \a ok to false if \a misfit cannot be calculated.

  Mandatory to define it.
*/

/*!
  Set total number of parameters, including the fixed ones (initialized with a null range)
*/
void dinver_set_parameter_count(DinverForward forward, int n)
{
  for(int i=0;i<n;i++) {
    forward->parameterSpace().addParameter(QString("p%1").arg(i), "", 0.0, 0.0, ParameterGrid::Linear, 0.0);
  }
}

/*!
  Set range of parameter index \a paramIndex from \a min to \a max. \a scale must be 0 (linear) or 1 (log)
*/
void dinver_set_range(DinverForward forward, int paramIndex, float min, float max, int scale, float precision)
{
  Parameter * p;
  p=forward->parameterSpace().parameter(paramIndex);
  p->setMinimum(Number::toDouble(min));
  p->setMaximum(Number::toDouble(max));
  if(min>0.0 && scale==1) {
    p->setScale(ParameterGrid::Log);
  } else {
    p->setScale(ParameterGrid::Linear);
  }
  p->setPrecision(precision);
  p->initGrid();
}

/*!
  Add a simple condition between parameter \a p1 and \a p2 for \a run: p1<a*p2+b
*/
void dinver_add_less_than_condition(DinverForward forward, int p1Index, float a, int p2Index, float b)
{
  RealSpace& ps=forward->parameterSpace();
  Parameter * p1=ps.parameter(p1Index);
  Parameter * p2=ps.parameter(p2Index);
  ps.addCondition(new SimpleCondition(p1, SimpleCondition::LessThan,
                  Number::toDouble(a), p2, Number::toDouble(b)));
}

/*!
  Add a simple condition between parameter \a p1 and \a p2 for \a run: p1<a*p2+b
*/
void dinver_add_greater_than_condition(DinverForward forward, int p1Index, float a, int p2Index, float b)
{
  RealSpace& ps=forward->parameterSpace();
  Parameter * p1=ps.parameter(p1Index);
  Parameter * p2=ps.parameter(p2Index);
  ps.addCondition(new SimpleCondition(p1, SimpleCondition::GreaterThan,
                  Number::toDouble(a), p2, Number::toDouble(b)));
}

} // namespace DinverCore
