// Copyright (C) 2019 EDF
// All Rights Reserved
// This code is published under the GNU Lesser General Public License (GNU LGPL)
#include <Eigen/Dense>
#include <iostream>
#include <memory>
#include <pybind11/pybind11.h>
#include <pybind11/eigen.h>
#include "StOpt/dp/SimulatorDPBase.h"
#include "StOpt/dp/SimulatorDPBaseTree.h"
#include "test/c++/python/BlackScholesSimulatorWrap.h"
#include "test/c++/python/MeanRevertingWrap.h"
#include "test/c++/python/MeanReverting1DAssetsWrap.h"
#include "test/c++/python/AR1Wrap.h"
#include "StOpt/python/BinaryFileArchiveStOpt.h"
#include "test/c++/tools/simulators/TrinomialTreeOUSimulator.h"
#include "test/c++/tools/simulators/MeanRevertingSimulatorTree.h"
#include "test/c++/python/MeanRevertingSimulatorTreeWrap.h"

namespace py = pybind11;


/// \brief Encapsulation for simulators
PYBIND11_MODULE(Simulators, m)
{

    ///  to map the constructor , should map  std::shared_ptr with boost python
    py::class_<BlackScholesSimulatorWrap,  std::shared_ptr< BlackScholesSimulatorWrap>, StOpt::SimulatorDPBase >(m, "BlackScholesSimulator")
    .def(py::init<   const Eigen::VectorXd &, const Eigen::VectorXd &, const Eigen::VectorXd &,  const Eigen::MatrixXd &, const double &,  const size_t &, const size_t &,  const bool &   >())
    .def("getMu", &BlackScholesSimulatorWrap::getMu)
    ;


    py::class_<MeanRevertingWrap, std::shared_ptr< MeanRevertingWrap>, StOpt::SimulatorDPBase  > (m, "MeanRevertingSimulator")
    .def(py::init< const FutureCurve &, const Eigen::VectorXd &,   const Eigen::VectorXd &,
         const double &, const double &,   const size_t &,  const size_t &, const bool & >())
    ;

    py::class_<MeanReverting1DAssetsWrap, std::shared_ptr< MeanReverting1DAssetsWrap>, StOpt::SimulatorDPBase  > (m, "MeanReverting1DAssetsSimulator")
    .def(py::init< const std::vector< FutureCurve>  &,  const std::vector<double>   &, const std::vector<double>   &, const Eigen::MatrixXd &,
         const double &,  const size_t &, const size_t &,  const bool &,   const std::string &, const int &  >())
    .def("resetDirection", &MeanReverting1DAssetsWrap::resetDirection)
    ;

    py::class_<AR1Wrap, std::shared_ptr< AR1Wrap>, StOpt::SimulatorDPBase  > (m, "AR1Simulator")
    .def(py::init< const double, const double, const double &,   const double &, const double &,    const size_t &,  const size_t &, const bool & >())
    ;

    py::class_<TrinomialTreeOUSimulator, std::shared_ptr< TrinomialTreeOUSimulator> >(m, "TrinomialTreeOUSimulator")
    .def(py::init< const double &,  const double &, const Eigen::ArrayXd & >())
    .def("getPoints", &TrinomialTreeOUSimulator::getPoints)
    .def("getProbability", &TrinomialTreeOUSimulator::getProbability)
    .def("calculateStepCondExpectation", &TrinomialTreeOUSimulator::calculateStepCondExpectation)
    .def("calculateCondExpectation", &TrinomialTreeOUSimulator::calculateCondExpectation)
    .def("calculateExpectation", &TrinomialTreeOUSimulator::calculateExpectation)
    .def("calConnected", &TrinomialTreeOUSimulator::calConnected)
    .def("dump", &TrinomialTreeOUSimulator::dump)
    ;


    py::class_<MeanRevertingSimulatorTreeWrap, std::shared_ptr< MeanRevertingSimulatorTreeWrap >, StOpt::SimulatorDPBaseTree >(m, "MeanRevertingSimulatorTree")
    .def(py::init<const std::shared_ptr<BinaryFileArchiveStOpt> &, const FutureCurve &, const double &, const double & >())
    .def(py::init<const std::shared_ptr<BinaryFileArchiveStOpt> &, const FutureCurve &, const double &, const double &, const int &  >())
    .def("stepBackward", &MeanRevertingSimulatorTreeWrap::stepBackward)
    .def("stepForward", &MeanRevertingSimulatorTreeWrap::stepForward)
    .def("getNodes", &StOpt::SimulatorDPBaseTree::getNodes)
    .def("getNbNodes", &StOpt::SimulatorDPBaseTree::getNbNodes)
    .def("getNodesNext", &StOpt::SimulatorDPBaseTree::getNodesNext)
    .def("getNbNodesNext", &StOpt::SimulatorDPBaseTree::getNbNodesNext)
    .def("getNbStep", &StOpt::SimulatorDPBaseTree::getNbStep)
    .def("getDates", &StOpt::SimulatorDPBaseTree::getDates)
    .def("getProba", &StOpt::SimulatorDPBaseTree::getProba)
    .def("getConnected", &StOpt::SimulatorDPBaseTree::getConnected)
    .def("getValueAssociatedToNode", &MeanRevertingSimulatorTreeWrap::getValueAssociatedToNode)
    .def("getNodeAssociatedToSim", &MeanRevertingSimulatorTreeWrap::getNodeAssociatedToSim)
    .def("getNbSimul", &MeanRevertingSimulatorTreeWrap::getNbSimul)
    .def("getSpotValues", &MeanRevertingSimulatorTreeWrap::getSpotValues)
    ;


}
