#pragma once

#include <iostream>
#include <functional>
#include "GaussianExpectationLib.h"
#include "../general_model/MFMGeneral.h"
#include "../random_process/InterestRateTimeSliceProcess.h"
#include "CalibratorSingleCurrency.h"

//////////////////////////////////////////////////////////////////////////////////////
// A 1d-Markov Functional model using rolling numeraire
//////////////////////////////////////////////////////////////////////////////////////
class MFMSingleCurrency : public MFMGeneral<SingleCurrencyCalibrator, InterestRateTimeSliceProcess>
{

private:

	double m_mean_reversion_param;

	double m_t1_discount_factor;

	// return vector of x^2 values
	gelib::d_vector square(gelib::d_vector const& x);

public:

	MFMSingleCurrency(
		double mean_reversion_param, size_t gridpoints_per_slice, double sd_spread, double discount_factor_t1, size_t poly_order,
		gelib::d_vector const& times, gelib::d_vector const& forward_libors, gelib::d_vector const& caplet_volatilities, 
		gelib::d_vector const& x_volatilities, gelib::d_vector const& accrual_factors);

	void get_discount_factors(gelib::d_vector& out) const;

	void get_variances(gelib::d_vector& out) const;

	void get_grids(gelib::d_matrix& out) const;

	void get_conditional_means(gelib::d_matrix& out) const;

	void get_ad_grids(gelib::d_matrix& out) const;

	void get_J0_grids(gelib::d_matrix& out) const;

	void get_libor_grids(gelib::d_matrix& out) const;

	double digital_caplet_price(size_t which_slice, double k) const;

	double digital_caplet_price_inverse(size_t which_slice, double dcp) const;

	double value_caplet(double strike_price, size_t which_slice);

	static const std::string constructor_check(
		double mean_reversion_param, size_t gridpoints_per_slice, double sd_spread, double discount_factor_t1, size_t poly_order,
		gelib::d_vector const& times, gelib::d_vector const& forward_libors, gelib::d_vector const& caplet_volatilities, 
		gelib::d_vector const& x_volatilities, gelib::d_vector const& accrual_factors);

	static const std::string caplet_valuation_check(double strike_price, size_t which_slice, size_t number_of_slices);

};