//                                               -*- C++ -*-
/**
 *  @file  RootStrategyImplementation.cxx
 *  @brief
 *
 *  Copyright (C) 2005-2013 EDF-EADS-Phimeca
 *
 *  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 3 of the License, or
 *  (at your option) any later version.
 *
 *  This library 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
 *  along with this library.  If not, see <http://www.gnu.org/licenses/>.
 *
 *  @author schueller
 *  @date   2012-02-17 19:35:43 +0100 (Fri, 17 Feb 2012)
 */
#include <cstdlib>

#include "RootStrategyImplementation.hxx"
#include "Brent.hxx"
#include "Exception.hxx"
#include "ResourceMap.hxx"

BEGIN_NAMESPACE_OPENTURNS

/**
 * @class RootStrategyImplementation
 */

CLASSNAMEINIT(RootStrategyImplementation);

/* Default constructor */
RootStrategyImplementation::RootStrategyImplementation()
  : PersistentObject()
  , solver_(new Brent())
  , maximumDistance_(ResourceMap::GetAsNumericalScalar( "RootStrategyImplementation-DefaultMaximumDistance" ))
  , stepSize_(ResourceMap::GetAsNumericalScalar( "RootStrategyImplementation-DefaultStepSize" ))
  , isAlreadyComputedOriginValue_(false)
  , originValue_(0.0)
{
  // Nothing to do
}

/* Parameters constructor */
RootStrategyImplementation::RootStrategyImplementation(const Solver & solver)
  : PersistentObject()
  , solver_(solver)
  , maximumDistance_(ResourceMap::GetAsNumericalScalar( "RootStrategyImplementation-DefaultMaximumDistance" ))
  , stepSize_(ResourceMap::GetAsNumericalScalar( "RootStrategyImplementation-DefaultStepSize" ))
  , isAlreadyComputedOriginValue_(false)
  , originValue_(0.0)
{
  // Nothing to do
}

/* Parameters constructor */
RootStrategyImplementation::RootStrategyImplementation(const Solver & solver,
                                                       const NumericalScalar maximumDistance,
                                                       const NumericalScalar stepSize)
  : PersistentObject()
  , solver_(solver)
  , maximumDistance_(maximumDistance)
  , stepSize_(stepSize)
  , isAlreadyComputedOriginValue_(false)
  , originValue_(0.0)
{
  // Nothing to do
}

/* Virtual constructor */
RootStrategyImplementation * RootStrategyImplementation::clone() const
{
  return new RootStrategyImplementation(*this);
}

/* Solve gives all the roots found applying the root strategy */
RootStrategyImplementation::NumericalScalarCollection RootStrategyImplementation::solve(const NumericalMathFunction & function,
                                                                                        const NumericalScalar value)
{
  throw NotYetImplementedException(HERE);
}

/* Solver accessor */
void RootStrategyImplementation::setSolver(const Solver & solver)
{
  solver_ = solver;
}

Solver RootStrategyImplementation::getSolver() const
{
  return solver_;
}

/* Maximum distance accessor */
void RootStrategyImplementation::setMaximumDistance(const NumericalScalar maximumDistance)
{
  maximumDistance_ = maximumDistance;
}

NumericalScalar RootStrategyImplementation::getMaximumDistance() const
{
  return maximumDistance_;
}

/* Step size accessor */
void RootStrategyImplementation::setStepSize(const NumericalScalar stepSize)
{
  stepSize_ = stepSize;
}

NumericalScalar RootStrategyImplementation::getStepSize() const
{
  return stepSize_;
}

/* Value of the performance function at the origin accessor */
void RootStrategyImplementation::setOriginValue(const NumericalScalar originValue)
{
  originValue_ = originValue;
  isAlreadyComputedOriginValue_ = true;
}

/* We have to store the value of the performance function at the origin for two reasons:
   + to save computations, as this value will be reused for each direction
   + to check if the origin is in the failure space or not, wich change the meaning of the roots
*/
NumericalScalar RootStrategyImplementation::getOriginValue() const
{
  if (!isAlreadyComputedOriginValue_) throw NotDefinedException(HERE);
  return originValue_;
}

/* String converter */
String RootStrategyImplementation::__repr__() const
{
  OSS oss;
  oss << "class=" << RootStrategyImplementation::GetClassName()
      << " solver=" << solver_
      << " maximumDistance=" << maximumDistance_
      << " stepSize=" << stepSize_;
  return oss;
}

END_NAMESPACE_OPENTURNS
