// Copyright (C) 2016 EDF
// All Rights Reserved
// This code is published under the GNU Lesser General Public License (GNU LGPL)
#include <Eigen/Dense>
#include <iostream>
#include <pybind11/pybind11.h>
#include "test/c++/tools/BasketOptions.h"
#include "StOpt/core/utils/comparisonUtils.h"
#include "test/c++/python/PayOffSwing.h"
#include "test/c++/python/PayOffFictitiousSwing.h"
#include "test/c++/python/FutureCurveWrap.h"
#include "test/c++/python/OneDimDataWrap.h"

/** \file Pybind11Utils.cpp
 * \brief Map Pay off for swing
 * \author Xavier Warin
 */

using namespace Eigen;
using namespace std;
using namespace StOpt;


namespace py = pybind11;

//  map 0 function as a pay off function
class ZeroWrap: public StOpt::PayOffBase
{
public :

    // constructor
    ZeroWrap() {}
    virtual  ~ZeroWrap() {}

    /// \brief getFunction
    std::function<double(const int &, const Eigen::ArrayXd &, const Eigen::ArrayXd &)>  getFunction() const
    {
        auto f([](const int &, const Eigen::ArrayXd &, const Eigen::ArrayXd &)
        {
            return 0.;
        });
        return std::function<double(const int &, const Eigen::ArrayXd &, const Eigen::ArrayXd &)>(std::cref(f));
    }

    /// \brief  get back pay off function
    double set(const int &, const Eigen::ArrayXd &, const Eigen::ArrayXd &) const
    {
        return 0.;
    }
};


PYBIND11_MODULE(Utils, m)
{

    py::class_<BasketCall, std::shared_ptr<BasketCall > >(m, "BasketCall")
    .def(py::init<const double & >())
    .def("applyVec", &BasketCall::applyVec)
    ;

    py::class_< PayOffSwing, std::shared_ptr<PayOffSwing>, PayOffBase >(m, "PayOffSwing")
    .def(py::init< const BasketCall &, const int & >())
    .def("set", &PayOffSwing::set)
    ;
    py::class_< PayOffFictitiousSwing, std::shared_ptr<PayOffFictitiousSwing>, PayOffBase >(m, "PayOffFictitiousSwing")
    .def(py::init< const BasketCall &, const int & >())
    .def("set", &PayOffFictitiousSwing::set)
    ;
    py::class_<ZeroWrap, std::shared_ptr< ZeroWrap>, PayOffBase >(m, "ZeroPayOff")
    .def(py::init<>())
    .def("set", &ZeroWrap::set)
    ;

    py::class_<FutureCurve, std::shared_ptr<FutureCurve> >(m, "FutureCurve")
    .def(py::init< const std::shared_ptr<OneDimRegularSpaceGrid>  &,  const py::list & >())
    .def("get", &StOpt::OneDimData< StOpt::OneDimRegularSpaceGrid, double>::get)
    ;

    py::class_<RegimeCurve, std::shared_ptr<RegimeCurve> >(m, "RegimeCurve")
    .def(py::init<const std::shared_ptr<OneDimSpaceGrid>  &,  const py::list &>())
    ;

}
